chef-dk 0.3.5 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +4 -4
  3. data/README.md +4 -4
  4. data/lib/chef-dk/builtin_commands.rb +4 -0
  5. data/lib/chef-dk/chef_runner.rb +7 -1
  6. data/lib/chef-dk/command/exec.rb +9 -0
  7. data/lib/chef-dk/command/export.rb +132 -0
  8. data/lib/chef-dk/command/generator_commands.rb +1 -1
  9. data/lib/chef-dk/command/generator_commands/app.rb +8 -0
  10. data/lib/chef-dk/command/generator_commands/base.rb +46 -4
  11. data/lib/chef-dk/command/generator_commands/cookbook.rb +8 -0
  12. data/lib/chef-dk/command/generator_commands/cookbook_code_file.rb +1 -0
  13. data/lib/chef-dk/command/push.rb +3 -6
  14. data/lib/chef-dk/command/shell_init.rb +28 -5
  15. data/lib/chef-dk/command/update.rb +106 -0
  16. data/lib/chef-dk/command/verify.rb +72 -0
  17. data/lib/chef-dk/component_test.rb +12 -1
  18. data/lib/chef-dk/configurable.rb +52 -0
  19. data/lib/chef-dk/cookbook_metadata.rb +10 -1
  20. data/lib/chef-dk/cookbook_profiler/git.rb +1 -1
  21. data/lib/chef-dk/exceptions.rb +17 -2
  22. data/lib/chef-dk/helpers.rb +2 -2
  23. data/lib/chef-dk/policyfile/community_cookbook_source.rb +1 -1
  24. data/lib/chef-dk/policyfile/dsl.rb +7 -0
  25. data/lib/chef-dk/policyfile/uploader.rb +25 -4
  26. data/lib/chef-dk/policyfile_compiler.rb +21 -1
  27. data/lib/chef-dk/policyfile_lock.rb +5 -0
  28. data/lib/chef-dk/policyfile_services/export_repo.rb +194 -0
  29. data/lib/chef-dk/policyfile_services/install.rb +8 -2
  30. data/lib/chef-dk/policyfile_services/push.rb +4 -1
  31. data/lib/chef-dk/service_exceptions.rb +6 -0
  32. data/lib/chef-dk/skeletons/code_generator/files/default/Berksfile +1 -1
  33. data/lib/chef-dk/skeletons/code_generator/files/default/repo/README.md +1 -1
  34. data/lib/chef-dk/skeletons/code_generator/files/default/repo/cookbooks/README.md +1 -1
  35. data/lib/chef-dk/skeletons/code_generator/files/default/repo/environments/README.md +2 -2
  36. data/lib/chef-dk/skeletons/code_generator/files/default/serverspec_spec_helper.rb +3 -0
  37. data/lib/chef-dk/skeletons/code_generator/files/default/spec_helper.rb +1 -7
  38. data/lib/chef-dk/skeletons/code_generator/metadata.rb +1 -1
  39. data/lib/chef-dk/skeletons/code_generator/recipes/app.rb +31 -1
  40. data/lib/chef-dk/skeletons/code_generator/recipes/cookbook.rb +32 -2
  41. data/lib/chef-dk/skeletons/code_generator/recipes/recipe.rb +18 -0
  42. data/lib/chef-dk/skeletons/code_generator/templates/default/recipe.rb.erb +5 -0
  43. data/lib/chef-dk/skeletons/code_generator/templates/default/recipe_spec.rb.erb +23 -0
  44. data/lib/chef-dk/skeletons/code_generator/templates/default/serverspec_default_spec.rb.erb +12 -0
  45. data/lib/chef-dk/version.rb +1 -1
  46. data/lib/kitchen/provisioner/policyfile_zero.rb +149 -0
  47. data/spec/shared/a_file_generator.rb +1 -0
  48. data/spec/shared/command_with_ui_object.rb +11 -0
  49. data/spec/shared/custom_generator_cookbook.rb +117 -0
  50. data/spec/unit/chef_runner_spec.rb +26 -0
  51. data/spec/unit/command/exec_spec.rb +46 -5
  52. data/spec/unit/command/export_spec.rb +176 -0
  53. data/spec/unit/command/generator_commands/app_spec.rb +38 -0
  54. data/spec/unit/command/generator_commands/cookbook_spec.rb +37 -28
  55. data/spec/unit/command/generator_commands/recipe_spec.rb +4 -2
  56. data/spec/unit/command/install_spec.rb +3 -6
  57. data/spec/unit/command/push_spec.rb +3 -6
  58. data/spec/unit/command/shell_init_spec.rb +77 -49
  59. data/spec/unit/command/update_spec.rb +155 -0
  60. data/spec/unit/command/verify_spec.rb +22 -7
  61. data/spec/unit/cookbook_metadata_spec.rb +44 -8
  62. data/spec/unit/cookbook_profiler/git_spec.rb +12 -0
  63. data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/Berksfile +1 -1
  64. data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/Berksfile +1 -1
  65. data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/Berksfile +1 -1
  66. data/spec/unit/fixtures/cookbooks_api/small_universe.json +667 -667
  67. data/spec/unit/fixtures/cookbooks_api/universe.json +1 -1
  68. data/spec/unit/fixtures/cookbooks_api/update_fixtures.rb +1 -1
  69. data/spec/unit/fixtures/example_cookbook/Berksfile +1 -1
  70. data/spec/unit/fixtures/example_cookbook_metadata_json_only/.gitignore +17 -0
  71. data/spec/unit/fixtures/example_cookbook_metadata_json_only/.kitchen.yml +16 -0
  72. data/spec/unit/fixtures/example_cookbook_metadata_json_only/Berksfile +3 -0
  73. data/spec/unit/fixtures/example_cookbook_metadata_json_only/README.md +4 -0
  74. data/spec/unit/fixtures/example_cookbook_metadata_json_only/chefignore +96 -0
  75. data/spec/unit/fixtures/example_cookbook_metadata_json_only/metadata.json +5 -0
  76. data/spec/unit/fixtures/example_cookbook_metadata_json_only/recipes/default.rb +8 -0
  77. data/spec/unit/fixtures/example_cookbook_no_metadata/.gitignore +17 -0
  78. data/spec/unit/fixtures/example_cookbook_no_metadata/.kitchen.yml +16 -0
  79. data/spec/unit/fixtures/example_cookbook_no_metadata/Berksfile +3 -0
  80. data/spec/unit/fixtures/example_cookbook_no_metadata/README.md +4 -0
  81. data/spec/unit/fixtures/example_cookbook_no_metadata/chefignore +96 -0
  82. data/spec/unit/fixtures/example_cookbook_no_metadata/recipes/default.rb +8 -0
  83. data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/Berksfile +1 -1
  84. data/spec/unit/policyfile/community_cookbook_source_spec.rb +2 -2
  85. data/spec/unit/policyfile/cookbook_location_specification_spec.rb +3 -3
  86. data/spec/unit/policyfile/uploader_spec.rb +61 -25
  87. data/spec/unit/policyfile_demands_spec.rb +47 -0
  88. data/spec/unit/policyfile_evaluation_spec.rb +1 -1
  89. data/spec/unit/policyfile_lock_build_spec.rb +60 -3
  90. data/spec/unit/policyfile_services/export_repo_spec.rb +321 -0
  91. data/spec/unit/policyfile_services/install_spec.rb +20 -1
  92. data/spec/unit/policyfile_services/push_spec.rb +36 -9
  93. metadata +53 -38
  94. data/lib/chef-dk/skeletons/code_generator/files/default/converge_spec.rb +0 -9
  95. data/lib/chef-dk/skeletons/code_generator/templates/default/default_recipe.rb.erb +0 -5
@@ -2,7 +2,25 @@
2
2
  context = ChefDK::Generator.context
3
3
  cookbook_dir = File.join(context.cookbook_root, context.cookbook_name)
4
4
  recipe_path = File.join(cookbook_dir, "recipes", "#{context.new_file_basename}.rb")
5
+ spec_helper_path = File.join(cookbook_dir, "spec", "spec_helper.rb")
6
+ spec_path = File.join(cookbook_dir, "spec", "unit", "recipes", "#{context.new_file_basename}_spec.rb")
5
7
 
8
+ # Chefspec
9
+ directory "#{cookbook_dir}/spec/unit/recipes" do
10
+ recursive true
11
+ end
12
+
13
+ cookbook_file spec_helper_path do
14
+ action :create_if_missing
15
+ end
16
+
17
+ template spec_path do
18
+ source "recipe_spec.rb.erb"
19
+ helpers(ChefDK::Generator::TemplateHelper)
20
+ action :create_if_missing
21
+ end
22
+
23
+ # Recipe
6
24
  template recipe_path do
7
25
  source "recipe.rb.erb"
8
26
  helpers(ChefDK::Generator::TemplateHelper)
@@ -0,0 +1,5 @@
1
+ #
2
+ # Cookbook Name:: <%= cookbook_name %>
3
+ # Recipe:: <%= recipe_name %>
4
+ #
5
+ <%= license_description('#') %>
@@ -0,0 +1,23 @@
1
+ #
2
+ # Cookbook Name:: <%= cookbook_name %>
3
+ # Spec:: default
4
+ #
5
+ <%= license_description('#') %>
6
+
7
+ require 'spec_helper'
8
+
9
+ describe '<%= cookbook_name %>::<%= recipe_name %>' do
10
+
11
+ context 'When all attributes are default, on an unspecified platform' do
12
+
13
+ let(:chef_run) do
14
+ runner = ChefSpec::ServerRunner.new
15
+ runner.converge(described_recipe)
16
+ end
17
+
18
+ it 'converges successfully' do
19
+ chef_run # This should not raise an error
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe '<%= cookbook_name %>::default' do
4
+
5
+ # Serverspec examples can be found at
6
+ # http://serverspec.org/resource_types.html
7
+
8
+ it 'does something' do
9
+ skip 'Replace this with meaningful tests'
10
+ end
11
+
12
+ end
@@ -16,5 +16,5 @@
16
16
  #
17
17
 
18
18
  module ChefDK
19
- VERSION = "0.3.5"
19
+ VERSION = "0.4.0"
20
20
  end
@@ -0,0 +1,149 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
4
+ #
5
+ # Copyright (C) 2013, Fletcher Nichol
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ require "kitchen/provisioner/chef_base"
20
+
21
+ # TODO: chef-dk and kitchen can only co-exist if kitchen and chef-dk agree on
22
+ # the version of mixlib-shellout to use. Kitchen currently locked at 1.x,
23
+ # chef-dk is on 2.x
24
+ require 'chef-dk/policyfile_services/export_repo'
25
+
26
+ module Kitchen
27
+
28
+ module Provisioner
29
+
30
+ # Policyfile + Chef Zero provisioner.
31
+ #
32
+ # @author Daniel DeLeo <dan@chef.io>
33
+ class PolicyfileZero < ChefBase
34
+
35
+ # This provsioner will forcibly set the following config options:
36
+ # * `use_policyfile`: `true`
37
+ # * `versioned_cookbooks`: `true`
38
+ # * `deployment_group`: `POLICY_NAME-local`
39
+ # Since it makes no sense to modify these, they are hardcoded elsewhere.
40
+ default_config :client_rb, {}
41
+ default_config :ruby_bindir, "/opt/chef/embedded/bin"
42
+
43
+ # Policyfile mode does not support the `-j dna.json` option to
44
+ # `chef-client`.
45
+ default_config :json_attributes, false
46
+ default_config :chef_zero_port, 8889
47
+
48
+ default_config :chef_client_path do |provisioner|
49
+ File.join(provisioner[:chef_omnibus_root], %w[bin chef-client])
50
+ end
51
+
52
+ # Emit a warning that Policyfile stuff is still experimental.
53
+ #
54
+ # (see Base#finalize_config!)
55
+ def finalize_config!(*args)
56
+ super
57
+ banner("Using experimental policyfile mode for chef-client")
58
+ warn("The Policyfile feature is under active development.")
59
+ warn("For best results, always use the latest chef-client version")
60
+ end
61
+
62
+ # (see Base#create_sandbox)
63
+ def create_sandbox
64
+ super
65
+ prepare_validation_pem
66
+ prepare_client_rb
67
+ end
68
+
69
+ # (see Base#run_command)
70
+ def run_command
71
+ level = config[:log_level] == :info ? :auto : config[:log_level]
72
+ chef_client_bin = sudo(config[:chef_client_path])
73
+
74
+ cmd = "#{chef_client_bin} --local-mode"
75
+ args = [
76
+ "--config #{config[:root_path]}/client.rb",
77
+ "--log_level #{level}",
78
+ "--force-formatter",
79
+ "--no-color"
80
+ ]
81
+ if config[:chef_zero_port]
82
+ args << "--chef-zero-port #{config[:chef_zero_port]}"
83
+ end
84
+ if config[:log_file]
85
+ args << "--logfile #{config[:log_file]}"
86
+ end
87
+
88
+ Util.wrap_command([cmd, *args].join(" "))
89
+ end
90
+
91
+ private
92
+
93
+ # Overrides behavior of parent class so that dna.json isn't created; we
94
+ # don't need it.
95
+ #
96
+ # @api private
97
+ def prepare_json
98
+ end
99
+
100
+ # Copies the policyfile's cookbooks to the sandbox.
101
+ #
102
+ # @api private
103
+ def prepare_cookbooks
104
+ Kitchen.mutex.synchronize do
105
+ policy_exporter.run
106
+ end
107
+ end
108
+
109
+ # An instance of ChefDK::PolicyfileServices::ExportRepo, configured with
110
+ # the sandbox path. Calling `#run` on this copies the cookbooks to the
111
+ # sandbox. Calling `#policy_name` returns the policy's name.
112
+ #
113
+ # @api private
114
+ def policy_exporter
115
+ @policy_exporter ||= ChefDK::PolicyfileServices::ExportRepo.new(export_dir: sandbox_path)
116
+ end
117
+
118
+ # Writes a fake (but valid) validation.pem into the sandbox directory.
119
+ #
120
+ # @api private
121
+ def prepare_validation_pem
122
+ info("Preparing validation.pem")
123
+ debug("Using a dummy validation.pem")
124
+
125
+ source = File.join(Kitchen.source_root, %w[support dummy-validation.pem])
126
+ FileUtils.cp(source, File.join(sandbox_path, "validation.pem"))
127
+ end
128
+
129
+ # Writes a client.rb configuration file to the sandbox directory.
130
+ #
131
+ # @api private
132
+ def prepare_client_rb
133
+ data = default_config_rb.merge(config[:client_rb])
134
+
135
+ data["use_policyfile"] = true
136
+ data["versioned_cookbooks"] = true
137
+ data["deployment_group"] = "#{policy_exporter.policy_name}-local"
138
+
139
+ info("Preparing client.rb")
140
+ debug("Creating client.rb from #{data.inspect}")
141
+
142
+ File.open(File.join(sandbox_path, "client.rb"), "wb") do |file|
143
+ file.write(format_config_file(data))
144
+ end
145
+ end
146
+
147
+ end
148
+ end
149
+ end
@@ -63,6 +63,7 @@ shared_examples_for "a file generator" do
63
63
  expect(generator_context.cookbook_root).to eq(expected_cookbook_root)
64
64
  expect(generator_context.cookbook_name).to eq(cookbook_name)
65
65
  expect(generator_context.new_file_basename).to eq(new_file_name)
66
+ expect(generator_context.recipe_name).to eq(new_file_name)
66
67
  end
67
68
  end
68
69
 
@@ -0,0 +1,11 @@
1
+ shared_examples_for "a command with a UI object" do
2
+
3
+ subject(:command) { described_class.new }
4
+
5
+ it "configures a default UI component" do
6
+ ui = command.ui
7
+ expect(ui.out_stream).to eq($stdout)
8
+ expect(ui.err_stream).to eq($stderr)
9
+ end
10
+
11
+ end
@@ -0,0 +1,117 @@
1
+
2
+ # Required `let` bindings:
3
+ # * `generator_name` in lowercase, e.g., "cookbook", "app"
4
+ # * `generator_arg`: argument to the generator command
5
+ # * `expected_cookbook_files`: a list of files the generator should create
6
+ shared_examples_for "custom generator cookbook" do
7
+
8
+ context "when given a generator-cookbook path" do
9
+
10
+ let(:default_generator_cookbook_path) { File.expand_path('lib/chef-dk/skeletons/code_generator', project_root) }
11
+
12
+ let(:generator_cookbook_path) { File.join(tempdir, 'a_generator_cookbook') }
13
+
14
+ let(:argv) { [generator_arg, "--generator-cookbook", generator_cookbook_path] }
15
+
16
+ subject(:code_generator) { described_class.new(argv) }
17
+
18
+ before do
19
+ reset_tempdir
20
+ code_generator.read_and_validate_params
21
+ allow(code_generator.config_loader).to receive(:load)
22
+ end
23
+
24
+ it "configures the generator context" do
25
+ code_generator.setup_context
26
+ expect(generator_context.cookbook_name).to eq(generator_arg)
27
+ expect(code_generator.chef_runner.cookbook_path).to eq(tempdir)
28
+ expect(code_generator.chef_runner.run_list).to eq(["recipe[a_generator_cookbook::#{generator_name}]"])
29
+ end
30
+
31
+ context "when the generator cookbook is configured in a configuration file" do
32
+
33
+ let(:argv) { [generator_arg] }
34
+
35
+ let(:chefdk_config) { double("Mixlib::Config context for ChefDK", generator_cookbook: generator_cookbook_path) }
36
+
37
+ before do
38
+ allow(code_generator).to receive(:chefdk_config).and_return(chefdk_config)
39
+ end
40
+
41
+ it "configures the generator context" do
42
+ code_generator.setup_context
43
+ expect(generator_context.cookbook_name).to eq(generator_arg)
44
+ expect(code_generator.chef_runner.cookbook_path).to eq(tempdir)
45
+ expect(code_generator.chef_runner.run_list).to eq(["recipe[a_generator_cookbook::#{generator_name}]"])
46
+ end
47
+ end
48
+
49
+ context "with an invalid generator-cookbook path" do
50
+
51
+ it "fails with an informative error" do
52
+ Dir.chdir(tempdir) do
53
+ allow(code_generator.chef_runner).to receive(:stdout).and_return(stdout_io)
54
+ allow(code_generator).to receive(:stderr).and_return(stderr_io)
55
+ expect(code_generator.run).to eq(1)
56
+ end
57
+
58
+ cookbook_path = File.dirname(generator_cookbook_path)
59
+ expected_msg = %Q(ERROR: Could not find cookbook(s) to satisfy run list ["recipe[a_generator_cookbook::#{generator_name}]"] in #{cookbook_path})
60
+
61
+ expect(stderr_io.string).to include(expected_msg)
62
+ end
63
+
64
+ end
65
+
66
+ context "with a generator-cookbook path to a specific cookbook" do
67
+
68
+ let(:metadata_file) { File.join(generator_cookbook_path, "metadata.rb") }
69
+
70
+ before do
71
+ FileUtils.cp_r(default_generator_cookbook_path, generator_cookbook_path)
72
+
73
+ # have to update metadata with the correct name
74
+ IO.binwrite(metadata_file, "name 'a_generator_cookbook'")
75
+ end
76
+
77
+ it "creates the new files" do
78
+ expect(code_generator.chef_runner.cookbook_path).to eq(tempdir)
79
+ expect(code_generator.chef_runner.run_list).to eq(["recipe[a_generator_cookbook::#{generator_name}]"])
80
+
81
+ Dir.chdir(tempdir) do
82
+ allow(code_generator.chef_runner).to receive(:stdout).and_return(stdout_io)
83
+ code_generator.run
84
+ end
85
+ end
86
+
87
+ end
88
+
89
+ context "with a generator-cookbook path to a directory containing a 'code_generator' cookbook" do
90
+
91
+ before do
92
+ FileUtils.mkdir_p(generator_cookbook_path)
93
+ FileUtils.cp_r(default_generator_cookbook_path, generator_cookbook_path)
94
+
95
+ allow(code_generator).to receive(:stderr).and_return(stderr_io)
96
+ end
97
+
98
+ it "creates the new_files (and warns about deprecated usage)" do
99
+ allow(code_generator.chef_runner).to receive(:stdout).and_return(stdout_io)
100
+
101
+ Dir.chdir(tempdir) do
102
+ code_generator.run
103
+ end
104
+ generated_files = Dir.glob("#{tempdir}/#{generator_arg}/**/*", File::FNM_DOTMATCH)
105
+ expected_cookbook_files.each do |expected_file|
106
+ expect(generated_files).to include(expected_file)
107
+ end
108
+
109
+ code_generator_path = File.join(generator_cookbook_path, "code_generator")
110
+ warning_message = "WARN: Please configure the generator cookbook by giving the full path to the desired cookbook (like '#{code_generator_path}')"
111
+
112
+ expect(stderr_io.string).to include(warning_message)
113
+ end
114
+ end
115
+ end
116
+ end
117
+
@@ -72,6 +72,32 @@ describe ChefDK::ChefRunner do
72
72
  expect(test_state[:loaded_recipes]).to eq([ "recipe_one", "recipe_two" ])
73
73
  expect(test_state[:converged_recipes]).to eq([ "recipe_one", "recipe_two" ])
74
74
  end
75
+
76
+ context "when the embedded chef run fails" do
77
+
78
+ let(:embedded_runner) { instance_double("Chef::Runner") }
79
+
80
+ before do
81
+ allow(Chef::Runner).to receive(:new).and_return(embedded_runner)
82
+ allow(embedded_runner).to receive(:converge).and_raise("oops")
83
+ end
84
+
85
+ it "wraps the exception in a ChefConvergeError" do
86
+ expect { chef_runner.converge }.to raise_error(ChefDK::ChefConvergeError)
87
+ end
88
+
89
+ end
90
+
91
+ context "when cookbook_path is relative" do
92
+
93
+ let(:default_cookbook_path) { "~/heres_some_cookbooks" }
94
+
95
+ it "expands the path" do
96
+ expect(chef_runner.cookbook_path).to eq(File.expand_path(default_cookbook_path))
97
+ end
98
+
99
+ end
100
+
75
101
  end
76
102
 
77
103
 
@@ -24,7 +24,7 @@ describe ChefDK::Command::Exec do
24
24
  let(:command_options) { [] }
25
25
 
26
26
  def run_command
27
- command_instance.run(command_options)
27
+ command_instance.run_with_default_options(command_options)
28
28
  end
29
29
 
30
30
  it "has a usage banner" do
@@ -76,11 +76,11 @@ describe ChefDK::Command::Exec do
76
76
 
77
77
  let(:expected_PATH) { [omnibus_bin_dir, user_bin_dir, omnibus_embedded_bin_dir, ENV['PATH']].join(File::PATH_SEPARATOR) }
78
78
 
79
- let(:expected_GEM_ROOT) { Gem.default_dir.inspect }
79
+ let(:expected_GEM_ROOT) { Gem.default_dir }
80
80
 
81
81
  let(:expected_GEM_HOME) { Gem.user_dir }
82
82
 
83
- let(:expected_GEM_PATH) { Gem.path.join(':') }
83
+ let(:expected_GEM_PATH) { Gem.path.join(File::PATH_SEPARATOR) }
84
84
 
85
85
  before do
86
86
  allow(command_instance).to receive(:omnibus_embedded_bin_dir).and_return(omnibus_embedded_bin_dir)
@@ -97,6 +97,47 @@ describe ChefDK::Command::Exec do
97
97
  expect{ run_command }.to raise_error # XXX: this isn't a test we just need to swallow the exception
98
98
  end
99
99
 
100
+ ['-v', '--version', '-h', '--help'].each do |switch|
101
+ context "when running a command with #{switch}" do
102
+ let(:command_options) { %W[gem list #{switch}] }
103
+
104
+ it "should call exec to fire off the command with the correct environment" do
105
+ expect(ENV).to receive(:[]=).with("PATH", expected_PATH)
106
+ expect(ENV).to receive(:[]=).with("GEM_ROOT", expected_GEM_ROOT)
107
+ expect(ENV).to receive(:[]=).with("GEM_HOME", expected_GEM_HOME)
108
+ expect(ENV).to receive(:[]=).with("GEM_PATH", expected_GEM_PATH)
109
+
110
+ expect(command_instance).to receive(:exec).with(*command_options)
111
+ expect{ run_command }.to raise_error # XXX: this isn't a test we just need to swallow the exception
112
+ end
113
+ end
114
+ end
115
+
116
+ ['-h', '--help'].each do |switch|
117
+ context "when running a exec with #{switch} and things after it" do
118
+ let(:command_options) { %W[#{switch} gem] }
119
+
120
+ it "should call not call exec, but it should print the banner" do
121
+ allow(command_instance).to receive(:msg)
122
+ expect(ENV).not_to receive(:[]=)
123
+ expect(command_instance).to receive(:banner)
124
+ expect(command_instance).not_to receive(:exec)
125
+ run_command
126
+ end
127
+ end
128
+
129
+ context "when running a exec with #{switch}" do
130
+ let(:command_options) { ["#{switch}"] }
131
+
132
+ it "should call not call exec, but it should print the banner" do
133
+ allow(command_instance).to receive(:msg)
134
+ expect(ENV).not_to receive(:[]=)
135
+ expect(command_instance).to receive(:banner)
136
+ expect(command_instance).not_to receive(:exec)
137
+ run_command
138
+ end
139
+ end
140
+ end
100
141
  end
101
142
 
102
143
  context "when running command that does not exist" do
@@ -110,11 +151,11 @@ describe ChefDK::Command::Exec do
110
151
 
111
152
  let(:expected_PATH) { [omnibus_bin_dir, user_bin_dir, omnibus_embedded_bin_dir, ENV['PATH']].join(File::PATH_SEPARATOR) }
112
153
 
113
- let(:expected_GEM_ROOT) { Gem.default_dir.inspect }
154
+ let(:expected_GEM_ROOT) { Gem.default_dir }
114
155
 
115
156
  let(:expected_GEM_HOME) { Gem.user_dir }
116
157
 
117
- let(:expected_GEM_PATH) { Gem.path.join(':') }
158
+ let(:expected_GEM_PATH) { Gem.path.join(File::PATH_SEPARATOR) }
118
159
 
119
160
 
120
161
  before do