chef 11.16.4 → 11.18.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +2 -2
  3. data/lib/chef/api_client.rb +1 -1
  4. data/lib/chef/chef_fs/chef_fs_data_store.rb +3 -2
  5. data/lib/chef/chef_fs/command_line.rb +3 -2
  6. data/lib/chef/chef_fs/data_handler/group_data_handler.rb +5 -1
  7. data/lib/chef/chef_fs/file_system/acl_entry.rb +2 -1
  8. data/lib/chef/chef_fs/file_system/chef_repository_file_system_entry.rb +2 -1
  9. data/lib/chef/chef_fs/file_system/rest_list_dir.rb +3 -2
  10. data/lib/chef/chef_fs/file_system/rest_list_entry.rb +5 -4
  11. data/lib/chef/config_fetcher.rb +1 -1
  12. data/lib/chef/cookbook/cookbook_version_loader.rb +4 -4
  13. data/lib/chef/cookbook/metadata.rb +1 -1
  14. data/lib/chef/cookbook_version.rb +2 -2
  15. data/lib/chef/data_bag.rb +1 -1
  16. data/lib/chef/data_bag_item.rb +1 -1
  17. data/lib/chef/encrypted_data_bag_item/decryptor.rb +3 -3
  18. data/lib/chef/environment.rb +1 -1
  19. data/lib/chef/exceptions.rb +19 -2
  20. data/lib/chef/json_compat.rb +64 -45
  21. data/lib/chef/knife/bootstrap.rb +2 -2
  22. data/lib/chef/knife/bootstrap/archlinux-gems.erb +2 -2
  23. data/lib/chef/knife/bootstrap/centos5-gems.erb +2 -2
  24. data/lib/chef/knife/bootstrap/chef-aix.erb +2 -2
  25. data/lib/chef/knife/bootstrap/chef-full.erb +2 -2
  26. data/lib/chef/knife/bootstrap/fedora13-gems.erb +2 -2
  27. data/lib/chef/knife/bootstrap/ubuntu10.04-apt.erb +2 -2
  28. data/lib/chef/knife/bootstrap/ubuntu10.04-gems.erb +2 -2
  29. data/lib/chef/knife/bootstrap/ubuntu12.04-gems.erb +2 -2
  30. data/lib/chef/knife/cookbook_site_download.rb +1 -1
  31. data/lib/chef/knife/cookbook_site_install.rb +34 -10
  32. data/lib/chef/knife/cookbook_site_list.rb +1 -1
  33. data/lib/chef/knife/cookbook_site_search.rb +1 -1
  34. data/lib/chef/knife/cookbook_site_share.rb +2 -2
  35. data/lib/chef/knife/cookbook_site_show.rb +3 -3
  36. data/lib/chef/knife/cookbook_site_unshare.rb +1 -1
  37. data/lib/chef/knife/core/subcommand_loader.rb +24 -0
  38. data/lib/chef/knife/deps.rb +3 -2
  39. data/lib/chef/node.rb +1 -1
  40. data/lib/chef/provider/deploy/revision.rb +1 -1
  41. data/lib/chef/provider/dsc_script.rb +32 -5
  42. data/lib/chef/provider/env.rb +25 -10
  43. data/lib/chef/provider/remote_file/cache_control_data.rb +1 -1
  44. data/lib/chef/resource.rb +1 -1
  45. data/lib/chef/resource/dsc_script.rb +2 -16
  46. data/lib/chef/resource_collection.rb +1 -1
  47. data/lib/chef/resource_reporter.rb +3 -3
  48. data/lib/chef/role.rb +1 -1
  49. data/lib/chef/run_list.rb +1 -1
  50. data/lib/chef/user.rb +1 -1
  51. data/lib/chef/util/dsc/local_configuration_manager.rb +15 -11
  52. data/lib/chef/util/powershell/cmdlet_result.rb +2 -2
  53. data/lib/chef/version.rb +1 -2
  54. data/spec/data/bootstrap/test-hints.erb +1 -1
  55. data/spec/data/bootstrap/test.erb +1 -1
  56. data/spec/functional/knife/cookbook_delete_spec.rb +3 -3
  57. data/spec/functional/knife/exec_spec.rb +1 -1
  58. data/spec/functional/resource/dsc_script_spec.rb +92 -47
  59. data/spec/functional/resource/env_spec.rb +3 -4
  60. data/spec/functional/util/powershell/cmdlet_spec.rb +1 -2
  61. data/spec/integration/knife/chef_fs_data_store_spec.rb +1 -1
  62. data/spec/integration/knife/chef_repo_path_spec.rb +6 -1
  63. data/spec/integration/knife/chef_repository_file_system_spec.rb +1 -1
  64. data/spec/integration/knife/chefignore_spec.rb +1 -1
  65. data/spec/integration/knife/common_options_spec.rb +1 -1
  66. data/spec/integration/knife/cookbook_api_ipv6_spec.rb +1 -1
  67. data/spec/integration/knife/delete_spec.rb +1 -1
  68. data/spec/integration/knife/deps_spec.rb +1 -1
  69. data/spec/integration/knife/diff_spec.rb +3 -3
  70. data/spec/integration/knife/download_spec.rb +3 -3
  71. data/spec/integration/knife/list_spec.rb +1 -1
  72. data/spec/integration/knife/raw_spec.rb +11 -1
  73. data/spec/integration/knife/redirection_spec.rb +1 -1
  74. data/spec/integration/knife/serve_spec.rb +1 -1
  75. data/spec/integration/knife/show_spec.rb +1 -1
  76. data/spec/integration/knife/upload_spec.rb +9 -9
  77. data/spec/spec_helper.rb +6 -0
  78. data/spec/support/shared/integration/integration_helper.rb +1 -2
  79. data/spec/support/shared/shared_examples.rb +10 -0
  80. data/spec/tiny_server.rb +2 -1
  81. data/spec/unit/api_client_spec.rb +3 -3
  82. data/spec/unit/chef_fs/data_handler/group_handler_spec.rb +63 -0
  83. data/spec/unit/config_fetcher_spec.rb +1 -1
  84. data/spec/unit/cookbook/metadata_spec.rb +7 -3
  85. data/spec/unit/cookbook_loader_spec.rb +1 -1
  86. data/spec/unit/cookbook_version_spec.rb +4 -0
  87. data/spec/unit/data_bag_item_spec.rb +5 -1
  88. data/spec/unit/data_bag_spec.rb +5 -1
  89. data/spec/unit/deprecation_spec.rb +1 -1
  90. data/spec/unit/encrypted_data_bag_item_spec.rb +14 -7
  91. data/spec/unit/environment_spec.rb +7 -3
  92. data/spec/unit/exceptions_spec.rb +6 -0
  93. data/spec/unit/json_compat_spec.rb +58 -17
  94. data/spec/unit/knife/cookbook_metadata_from_file_spec.rb +0 -1
  95. data/spec/unit/knife/cookbook_site_download_spec.rb +2 -1
  96. data/spec/unit/knife/cookbook_site_install_spec.rb +161 -116
  97. data/spec/unit/knife/cookbook_site_share_spec.rb +6 -6
  98. data/spec/unit/knife/core/bootstrap_context_spec.rb +2 -2
  99. data/spec/unit/knife/core/subcommand_loader_spec.rb +66 -1
  100. data/spec/unit/knife/data_bag_from_file_spec.rb +1 -2
  101. data/spec/unit/node_spec.rb +4 -0
  102. data/spec/unit/provider/dsc_script_spec.rb +134 -105
  103. data/spec/unit/provider/env/windows_spec.rb +2 -2
  104. data/spec/unit/provider/env_spec.rb +76 -11
  105. data/spec/unit/provider/remote_file/cache_control_data_spec.rb +1 -1
  106. data/spec/unit/resource/dsc_script_spec.rb +0 -29
  107. data/spec/unit/resource_collection_spec.rb +5 -1
  108. data/spec/unit/resource_reporter_spec.rb +3 -3
  109. data/spec/unit/resource_spec.rb +5 -1
  110. data/spec/unit/role_spec.rb +4 -0
  111. data/spec/unit/run_list_spec.rb +5 -1
  112. data/spec/unit/user_spec.rb +5 -1
  113. data/spec/unit/util/dsc/local_configuration_manager_spec.rb +15 -10
  114. metadata +11 -9
@@ -108,16 +108,16 @@ describe Chef::Knife::CookbookSiteShare do
108
108
  File.stub(:open).and_return(true)
109
109
  end
110
110
 
111
- it 'should post the cookbook to "http://cookbooks.opscode.com"' do
112
- response_text = {:uri => 'http://cookbooks.opscode.com/cookbooks/cookbook_name'}.to_json
111
+ it 'should post the cookbook to "https://supermarket.getchef.com"' do
112
+ response_text = {:uri => 'https://supermarket.getchef.com/cookbooks/cookbook_name'}.to_json
113
113
  @upload_response.stub(:body).and_return(response_text)
114
114
  @upload_response.stub(:code).and_return(201)
115
- Chef::CookbookSiteStreamingUploader.should_receive(:post).with(/cookbooks\.opscode\.com/, anything(), anything(), anything())
115
+ Chef::CookbookSiteStreamingUploader.should_receive(:post).with(/supermarket\.getchef\.com/, anything(), anything(), anything())
116
116
  @knife.run
117
117
  end
118
118
 
119
119
  it 'should alert the user when a version already exists' do
120
- response_text = {:error_messages => ['Version already exists']}.to_json
120
+ response_text = Chef::JSONCompat.to_json({:error_messages => ['Version already exists']})
121
121
  @upload_response.stub(:body).and_return(response_text)
122
122
  @upload_response.stub(:code).and_return(409)
123
123
  lambda { @knife.run }.should raise_error(SystemExit)
@@ -125,7 +125,7 @@ describe Chef::Knife::CookbookSiteShare do
125
125
  end
126
126
 
127
127
  it 'should pass any errors on to the user' do
128
- response_text = {:error_messages => ["You're holding it wrong"]}.to_json
128
+ response_text = Chef::JSONCompat.to_json({:error_messages => ["You're holding it wrong"]})
129
129
  @upload_response.stub(:body).and_return(response_text)
130
130
  @upload_response.stub(:code).and_return(403)
131
131
  lambda { @knife.run }.should raise_error(SystemExit)
@@ -133,7 +133,7 @@ describe Chef::Knife::CookbookSiteShare do
133
133
  end
134
134
 
135
135
  it 'should print the body if no errors are exposed on failure' do
136
- response_text = {:system_error => "Your call was dropped", :reason => "There's a map for that"}.to_json
136
+ response_text = Chef::JSONCompat.to_json({:system_error => "Your call was dropped", :reason => "There's a map for that"})
137
137
  @upload_response.stub(:body).and_return(response_text)
138
138
  @upload_response.stub(:code).and_return(500)
139
139
  @knife.ui.should_receive(:error).with(/#{Regexp.escape(response_text)}/)#.ordered
@@ -116,13 +116,13 @@ EXPECTED
116
116
  describe "when JSON attributes are given" do
117
117
  let(:config) { {:first_boot_attributes => {:baz => :quux}} }
118
118
  it "adds the attributes to first_boot" do
119
- bootstrap_context.first_boot.to_json.should eq({:baz => :quux, :run_list => run_list}.to_json)
119
+ Chef::JSONCompat.to_json(bootstrap_context.first_boot).should eq(Chef::JSONCompat.to_json({:baz => :quux, :run_list => run_list}))
120
120
  end
121
121
  end
122
122
 
123
123
  describe "when JSON attributes are NOT given" do
124
124
  it "sets first_boot equal to run_list" do
125
- bootstrap_context.first_boot.to_json.should eq({:run_list => run_list}.to_json)
125
+ Chef::JSONCompat.to_json(bootstrap_context.first_boot).should eq(Chef::JSONCompat.to_json({:run_list => run_list}))
126
126
  end
127
127
  end
128
128
 
@@ -73,7 +73,72 @@ describe Chef::Knife::SubcommandLoader do
73
73
  @loader.site_subcommands.should include(expected_command)
74
74
  end
75
75
 
76
- describe "finding 3rd party plugins" do
76
+ # https://github.com/opscode/chef-dk/issues/227
77
+ #
78
+ # `knife` in ChefDK isn't from a gem install, it's directly run from a clone
79
+ # of the source, but there can be one or more versions of chef also installed
80
+ # as a gem. If the gem install contains a command that doesn't exist in the
81
+ # source tree of the "primary" chef install, it can be loaded and cause an
82
+ # error. We also want to ensure that we only load builtin commands from the
83
+ # "primary" chef install.
84
+ context "when a different version of chef is also installed as a gem" do
85
+
86
+ let(:all_found_commands) do
87
+ [
88
+ "/opt/chefdk/embedded/apps/chef/lib/chef/knife/bootstrap.rb",
89
+ "/opt/chefdk/embedded/apps/chef/lib/chef/knife/client_bulk_delete.rb",
90
+ "/opt/chefdk/embedded/apps/chef/lib/chef/knife/client_create.rb",
91
+ # We use the fake version 1.0.0 because that version doesn't exist,
92
+ # which ensures it won't ever equal "chef-#{Chef::VERSION}"
93
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-1.0.0/lib/chef/knife/bootstrap.rb",
94
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-1.0.0/lib/chef/knife/client_bulk_delete.rb",
95
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-1.0.0/lib/chef/knife/client_create.rb",
96
+ # This command is "extra" compared to what's in the embedded/apps/chef install:
97
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-1.0.0/lib/chef/knife/data_bag_secret_options.rb",
98
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-vault-2.2.4/lib/chef/knife/decrypt.rb",
99
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/knife-spork-1.4.1/lib/chef/knife/spork-bump.rb",
100
+ # These are fake commands that have names designed to test that the
101
+ # regex is strict enough
102
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-foo-#{Chef::VERSION}/lib/chef/knife/chef-foo.rb",
103
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/foo-chef-#{Chef::VERSION}/lib/chef/knife/foo-chef.rb",
104
+ # In a real scenario, we'd use rubygems APIs to only select the most
105
+ # recent gem, but for this test we want to check that we're doing the
106
+ # right thing both when the plugin version matches and does not match
107
+ # the current chef version. Looking at
108
+ # `SubcommandLoader::MATCHES_THIS_CHEF_GEM` and
109
+ # `SubcommandLoader::MATCHES_CHEF_GEM` should make it clear why we want
110
+ # to test these two cases.
111
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-bar-1.0.0/lib/chef/knife/chef-bar.rb",
112
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/bar-chef-1.0.0/lib/chef/knife/bar-chef.rb"
113
+ ]
114
+ end
115
+
116
+ let(:expected_valid_commands) do
117
+ [
118
+ "/opt/chefdk/embedded/apps/chef/lib/chef/knife/bootstrap.rb",
119
+ "/opt/chefdk/embedded/apps/chef/lib/chef/knife/client_bulk_delete.rb",
120
+ "/opt/chefdk/embedded/apps/chef/lib/chef/knife/client_create.rb",
121
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-vault-2.2.4/lib/chef/knife/decrypt.rb",
122
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/knife-spork-1.4.1/lib/chef/knife/spork-bump.rb",
123
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-foo-#{Chef::VERSION}/lib/chef/knife/chef-foo.rb",
124
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/foo-chef-#{Chef::VERSION}/lib/chef/knife/foo-chef.rb",
125
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/chef-bar-1.0.0/lib/chef/knife/chef-bar.rb",
126
+ "/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/bar-chef-1.0.0/lib/chef/knife/bar-chef.rb"
127
+ ]
128
+ end
129
+
130
+ before do
131
+ expect(@loader).to receive(:find_files_latest_gems).with("chef/knife/*.rb").and_return(all_found_commands)
132
+ expect(@loader).to receive(:find_subcommands_via_dirglob).and_return({})
133
+ end
134
+
135
+ it "ignores commands from the non-matching gem install" do
136
+ expect(@loader.find_subcommands_via_rubygems.values).to eq(expected_valid_commands)
137
+ end
138
+
139
+ end
140
+
141
+ describe "finding 3rd party plugins" do
77
142
  let(:env_home) { "/home/alice" }
78
143
  let(:manifest_path) { env_home + "/.chef/plugin_manifest.json" }
79
144
 
@@ -21,7 +21,6 @@ require 'spec_helper'
21
21
  require 'chef/data_bag_item'
22
22
  require 'chef/encrypted_data_bag_item'
23
23
  require 'tempfile'
24
- require 'json'
25
24
 
26
25
  Chef::Knife::DataBagFromFile.load_deps
27
26
 
@@ -46,7 +45,7 @@ describe Chef::Knife::DataBagFromFile do
46
45
  "greeting" => "hello",
47
46
  "nested" => { "a1" => [1, 2, 3], "a2" => { "b1" => true }}
48
47
  }
49
- @db_file.write(@plain_data.to_json)
48
+ @db_file.write(Chef::JSONCompat.to_json(@plain_data))
50
49
  @db_file.flush
51
50
  @knife.instance_variable_set(:@name_args, ['bag_name', @db_file.path])
52
51
  end
@@ -762,6 +762,10 @@ describe Chef::Node do
762
762
  end
763
763
  serialized_node.run_list.should == node.run_list
764
764
  end
765
+
766
+ include_examples "to_json equalivent to Chef::JSONCompat.to_json" do
767
+ let(:subject) { node.from_file(File.expand_path("nodes/test.example.com.rb", CHEF_SPEC_DATA)) }
768
+ end
765
769
  end
766
770
 
767
771
  describe "to_s" do
@@ -22,123 +22,152 @@ require 'chef/util/dsc/resource_info'
22
22
  require 'spec_helper'
23
23
 
24
24
  describe Chef::Provider::DscScript do
25
- let (:node) {
26
- node = Chef::Node.new
27
- node.automatic[:languages][:powershell][:version] = '4.0'
28
- node
29
- }
30
- let (:events) { Chef::EventDispatch::Dispatcher.new }
31
- let (:run_context) { Chef::RunContext.new(node, {}, events) }
32
- let (:resource) { Chef::Resource::DscScript.new("script", run_context) }
33
- let (:provider) do
34
- Chef::Provider::DscScript.new(resource, run_context)
35
- end
36
-
37
- describe '#load_current_resource' do
38
- it "describes the resource as converged if there were 0 DSC resources" do
39
- allow(provider).to receive(:run_configuration).with(:test).and_return([])
40
- provider.load_current_resource
41
- provider.instance_variable_get('@resource_converged').should be_true
25
+ context 'when DSC is available' do
26
+ let (:node) {
27
+ node = Chef::Node.new
28
+ node.automatic[:languages][:powershell][:version] = '4.0'
29
+ node
30
+ }
31
+ let (:events) { Chef::EventDispatch::Dispatcher.new }
32
+ let (:run_context) { Chef::RunContext.new(node, {}, events) }
33
+ let (:resource) { Chef::Resource::DscScript.new("script", run_context) }
34
+ let (:provider) do
35
+ Chef::Provider::DscScript.new(resource, run_context)
42
36
  end
43
37
 
44
- it "describes the resource as not converged if there is 1 DSC resources that is converged" do
45
- dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resource', false, ['nothing will change something'])
46
- allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info])
47
- provider.load_current_resource
48
- provider.instance_variable_get('@resource_converged').should be_true
38
+ describe '#load_current_resource' do
39
+ it "describes the resource as converged if there were 0 DSC resources" do
40
+ allow(provider).to receive(:run_configuration).with(:test).and_return([])
41
+ provider.load_current_resource
42
+ provider.instance_variable_get('@resource_converged').should be_true
43
+ end
44
+
45
+ it "describes the resource as not converged if there is 1 DSC resources that is converged" do
46
+ dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resource', false, ['nothing will change something'])
47
+ allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info])
48
+ provider.load_current_resource
49
+ provider.instance_variable_get('@resource_converged').should be_true
50
+ end
51
+
52
+ it "describes the resource as not converged if there is 1 DSC resources that is not converged" do
53
+ dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resource', true, ['will change something'])
54
+ allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info])
55
+ provider.load_current_resource
56
+ provider.instance_variable_get('@resource_converged').should be_false
57
+ end
58
+
59
+ it "describes the resource as not converged if there are any DSC resources that are not converged" do
60
+ dsc_resource_info1 = Chef::Util::DSC::ResourceInfo.new('resource', true, ['will change something'])
61
+ dsc_resource_info2 = Chef::Util::DSC::ResourceInfo.new('resource', false, ['nothing will change something'])
62
+
63
+ allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info1, dsc_resource_info2])
64
+ provider.load_current_resource
65
+ provider.instance_variable_get('@resource_converged').should be_false
66
+ end
67
+
68
+ it "describes the resource as converged if all DSC resources that are converged" do
69
+ dsc_resource_info1 = Chef::Util::DSC::ResourceInfo.new('resource', false, ['nothing will change something'])
70
+ dsc_resource_info2 = Chef::Util::DSC::ResourceInfo.new('resource', false, ['nothing will change something'])
71
+
72
+ allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info1, dsc_resource_info2])
73
+ provider.load_current_resource
74
+ provider.instance_variable_get('@resource_converged').should be_true
75
+ end
49
76
  end
50
77
 
51
- it "describes the resource as not converged if there is 1 DSC resources that is not converged" do
52
- dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resource', true, ['will change something'])
53
- allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info])
54
- provider.load_current_resource
55
- provider.instance_variable_get('@resource_converged').should be_false
78
+ describe '#generate_configuration_document' do
79
+ # I think integration tests should cover these cases
80
+
81
+ it 'uses configuration_document_from_script_path when a dsc script file is given' do
82
+ allow(provider).to receive(:load_current_resource)
83
+ resource.command("path_to_script")
84
+ generator = double('Chef::Util::DSC::ConfigurationGenerator')
85
+ generator.should_receive(:configuration_document_from_script_path)
86
+ allow(Chef::Util::DSC::ConfigurationGenerator).to receive(:new).and_return(generator)
87
+ provider.send(:generate_configuration_document, 'tmp', nil)
88
+ end
89
+
90
+ it 'uses configuration_document_from_script_code when a the dsc resource is given' do
91
+ allow(provider).to receive(:load_current_resource)
92
+ resource.code("ImADSCResource{}")
93
+ generator = double('Chef::Util::DSC::ConfigurationGenerator')
94
+ generator.should_receive(:configuration_document_from_script_code)
95
+ allow(Chef::Util::DSC::ConfigurationGenerator).to receive(:new).and_return(generator)
96
+ provider.send(:generate_configuration_document, 'tmp', nil)
97
+ end
98
+
99
+ it 'should noop if neither code or command are provided' do
100
+ allow(provider).to receive(:load_current_resource)
101
+ generator = double('Chef::Util::DSC::ConfigurationGenerator')
102
+ generator.should_receive(:configuration_document_from_script_code).with('', anything(), anything())
103
+ allow(Chef::Util::DSC::ConfigurationGenerator).to receive(:new).and_return(generator)
104
+ provider.send(:generate_configuration_document, 'tmp', nil)
105
+ end
56
106
  end
57
107
 
58
- it "describes the resource as not converged if there are any DSC resources that are not converged" do
59
- dsc_resource_info1 = Chef::Util::DSC::ResourceInfo.new('resource', true, ['will change something'])
60
- dsc_resource_info2 = Chef::Util::DSC::ResourceInfo.new('resource', false, ['nothing will change something'])
61
-
62
- allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info1, dsc_resource_info2])
63
- provider.load_current_resource
64
- provider.instance_variable_get('@resource_converged').should be_false
108
+ describe 'action_run' do
109
+ it 'should converge the script if it is not converged' do
110
+ dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resource', true, ['will change something'])
111
+ allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info])
112
+ allow(provider).to receive(:run_configuration).with(:set)
113
+
114
+ provider.run_action(:run)
115
+ resource.should be_updated
116
+ end
117
+
118
+ it 'should not converge if the script is already converged' do
119
+ allow(provider).to receive(:run_configuration).with(:test).and_return([])
120
+
121
+ provider.run_action(:run)
122
+ resource.should_not be_updated
123
+ end
65
124
  end
66
125
 
67
- it "describes the resource as converged if all DSC resources that are converged" do
68
- dsc_resource_info1 = Chef::Util::DSC::ResourceInfo.new('resource', false, ['nothing will change something'])
69
- dsc_resource_info2 = Chef::Util::DSC::ResourceInfo.new('resource', false, ['nothing will change something'])
70
-
71
- allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info1, dsc_resource_info2])
72
- provider.load_current_resource
73
- provider.instance_variable_get('@resource_converged').should be_true
126
+ describe '#generate_description' do
127
+ it 'removes the resource name from the beginning of any log line from the LCM' do
128
+ dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resourcename', true, ['resourcename doing something', 'lastline'])
129
+ provider.instance_variable_set('@dsc_resources_info', [dsc_resource_info])
130
+ provider.send(:generate_description)[1].should match(/converge DSC resource resourcename by doing something/)
131
+ end
132
+
133
+ it 'ignores the last line' do
134
+ dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resourcename', true, ['resourcename doing something', 'lastline'])
135
+ provider.instance_variable_set('@dsc_resources_info', [dsc_resource_info])
136
+ provider.send(:generate_description)[1].should_not match(/lastline/)
137
+ end
138
+
139
+ it 'reports a dsc resource has not been changed if the LCM reported no change was required' do
140
+ dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resourcename', false, ['resourcename does nothing', 'lastline'])
141
+ provider.instance_variable_set('@dsc_resources_info', [dsc_resource_info])
142
+ provider.send(:generate_description)[1].should match(/converge DSC resource resourcename by doing nothing/)
143
+ end
74
144
  end
75
145
  end
76
146
 
77
- describe '#generate_configuration_document' do
78
- # I think integration tests should cover these cases
79
-
80
- it 'uses configuration_document_from_script_path when a dsc script file is given' do
81
- allow(provider).to receive(:load_current_resource)
82
- resource.command("path_to_script")
83
- generator = double('Chef::Util::DSC::ConfigurationGenerator')
84
- generator.should_receive(:configuration_document_from_script_path)
85
- allow(Chef::Util::DSC::ConfigurationGenerator).to receive(:new).and_return(generator)
86
- provider.send(:generate_configuration_document, 'tmp', nil)
87
- end
88
-
89
- it 'uses configuration_document_from_script_code when a the dsc resource is given' do
90
- allow(provider).to receive(:load_current_resource)
91
- resource.code("ImADSCResource{}")
92
- generator = double('Chef::Util::DSC::ConfigurationGenerator')
93
- generator.should_receive(:configuration_document_from_script_code)
94
- allow(Chef::Util::DSC::ConfigurationGenerator).to receive(:new).and_return(generator)
95
- provider.send(:generate_configuration_document, 'tmp', nil)
96
- end
97
-
98
- it 'should noop if neither code or command are provided' do
99
- allow(provider).to receive(:load_current_resource)
100
- generator = double('Chef::Util::DSC::ConfigurationGenerator')
101
- generator.should_receive(:configuration_document_from_script_code).with('', anything(), anything())
102
- allow(Chef::Util::DSC::ConfigurationGenerator).to receive(:new).and_return(generator)
103
- provider.send(:generate_configuration_document, 'tmp', nil)
104
- end
105
- end
106
-
107
- describe 'action_run' do
108
- it 'should converge the script if it is not converged' do
109
- dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resource', true, ['will change something'])
110
- allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info])
111
- allow(provider).to receive(:run_configuration).with(:set)
112
-
113
- provider.run_action(:run)
114
- resource.should be_updated
115
- end
116
-
117
- it 'should not converge if the script is already converged' do
118
- allow(provider).to receive(:run_configuration).with(:test).and_return([])
119
-
120
- provider.run_action(:run)
121
- resource.should_not be_updated
122
- end
123
- end
124
-
125
- describe '#generate_description' do
126
- it 'removes the resource name from the beginning of any log line from the LCM' do
127
- dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resourcename', true, ['resourcename doing something', 'lastline'])
128
- provider.instance_variable_set('@dsc_resources_info', [dsc_resource_info])
129
- provider.send(:generate_description)[1].should match(/converge DSC resource resourcename by doing something/)
130
- end
131
-
132
- it 'ignores the last line' do
133
- dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resourcename', true, ['resourcename doing something', 'lastline'])
134
- provider.instance_variable_set('@dsc_resources_info', [dsc_resource_info])
135
- provider.send(:generate_description)[1].should_not match(/lastline/)
136
- end
147
+ context 'when Dsc is not available' do
148
+ let (:node) { Chef::Node.new }
149
+ let (:events) { Chef::EventDispatch::Dispatcher.new }
150
+ let (:run_context) { Chef::RunContext.new(node, {}, events) }
151
+ let (:resource) { Chef::Resource::DscScript.new('script', run_context) }
152
+ let (:provider) { Chef::Provider::DscScript.new(resource, run_context) }
153
+
154
+ describe 'action_run' do
155
+ ['1.0', '2.0', '3.0'].each do |version|
156
+ it "raises an exception for powershell version '#{version}'" do
157
+ node.automatic[:languages][:powershell][:version] = version
158
+
159
+ expect {
160
+ provider.run_action(:run)
161
+ }.to raise_error(Chef::Exceptions::NoProviderAvailable)
162
+ end
163
+ end
164
+
165
+ it 'raises an exception if Powershell is not present' do
166
+ expect {
167
+ provider.run_action(:run)
168
+ }.to raise_error(Chef::Exceptions::NoProviderAvailable)
169
+ end
137
170
 
138
- it 'reports a dsc resource has not been changed if the LCM reported no change was required' do
139
- dsc_resource_info = Chef::Util::DSC::ResourceInfo.new('resourcename', false, ['resourcename does nothing', 'lastline'])
140
- provider.instance_variable_set('@dsc_resources_info', [dsc_resource_info])
141
- provider.send(:generate_description)[1].should match(/converge DSC resource resourcename by doing nothing/)
142
171
  end
143
172
  end
144
173
  end
@@ -53,7 +53,7 @@ describe Chef::Provider::Env::Windows, :windows_only do
53
53
  end
54
54
 
55
55
  it "should update the ruby ENV object when it updates the value" do
56
- provider.should_receive(:compare_value).and_return(true)
56
+ provider.should_receive(:requires_modify_or_create?).and_return(true)
57
57
  new_resource.value("foobar")
58
58
  provider.action_modify
59
59
  expect(ENV['CHEF_WINDOWS_ENV_TEST']).to eql('foobar')
@@ -92,7 +92,7 @@ describe Chef::Provider::Env::Windows, :windows_only do
92
92
  end
93
93
 
94
94
  it "replaces Windows system variables" do
95
- provider.should_receive(:compare_value).and_return(true)
95
+ provider.should_receive(:requires_modify_or_create?).and_return(true)
96
96
  provider.should_receive(:expand_path).with(system_root).and_return(system_root_value)
97
97
  provider.action_modify
98
98
  expect(ENV['PATH']).to eql(system_root_value)
@@ -88,20 +88,20 @@ describe Chef::Provider::Env do
88
88
 
89
89
  it "should check to see if the values are the same if the key exists" do
90
90
  @provider.key_exists = true
91
- @provider.should_receive(:compare_value).and_return(false)
91
+ @provider.should_receive(:requires_modify_or_create?).and_return(false)
92
92
  @provider.action_create
93
93
  end
94
94
 
95
95
  it "should call modify_env if the key exists and values are not equal" do
96
96
  @provider.key_exists = true
97
- @provider.stub(:compare_value).and_return(true)
97
+ @provider.stub(:requires_modify_or_create?).and_return(true)
98
98
  @provider.should_receive(:modify_env).and_return(true)
99
99
  @provider.action_create
100
100
  end
101
101
 
102
102
  it "should set the new_resources updated flag when it updates an existing value" do
103
103
  @provider.key_exists = true
104
- @provider.stub(:compare_value).and_return(true)
104
+ @provider.stub(:requires_modify_or_create?).and_return(true)
105
105
  @provider.stub(:modify_env).and_return(true)
106
106
  @provider.action_create
107
107
  @new_resource.should be_updated
@@ -147,20 +147,20 @@ describe Chef::Provider::Env do
147
147
  end
148
148
 
149
149
  it "should call modify_group if the key exists and values are not equal" do
150
- @provider.should_receive(:compare_value).and_return(true)
150
+ @provider.should_receive(:requires_modify_or_create?).and_return(true)
151
151
  @provider.should_receive(:modify_env).and_return(true)
152
152
  @provider.action_modify
153
153
  end
154
154
 
155
155
  it "should set the new resources updated flag to true if modify_env is called" do
156
- @provider.stub(:compare_value).and_return(true)
156
+ @provider.stub(:requires_modify_or_create?).and_return(true)
157
157
  @provider.stub(:modify_env).and_return(true)
158
158
  @provider.action_modify
159
159
  @new_resource.should be_updated
160
160
  end
161
161
 
162
162
  it "should not call modify_env if the key exists but the values are equal" do
163
- @provider.should_receive(:compare_value).and_return(false)
163
+ @provider.should_receive(:requires_modify_or_create?).and_return(false)
164
164
  @provider.should_not_receive(:modify_env)
165
165
  @provider.action_modify
166
166
  end
@@ -198,9 +198,31 @@ describe Chef::Provider::Env do
198
198
  @provider.delete_element.should eql(true)
199
199
  @new_resource.should be_updated
200
200
  end
201
+
202
+ context "when new_resource's value contains the delimiter" do
203
+ it "should return false if all the elements are deleted" do
204
+ # This indicates that the entire key needs to be deleted
205
+ @new_resource.value("C:/foo/bin;C:/bar/bin")
206
+ @provider.delete_element.should eql(false)
207
+ @new_resource.should_not be_updated # This will be updated in action_delete
208
+ end
209
+
210
+ it "should return true if any, but not all, of the elements are deleted" do
211
+ @new_resource.value("C:/foo/bin;C:/notbaz/bin")
212
+ @provider.should_receive(:create_env)
213
+ @provider.delete_element.should eql(true)
214
+ @new_resource.should be_updated
215
+ end
216
+
217
+ it "should return true if none of the elements are deleted" do
218
+ @new_resource.value("C:/notfoo/bin;C:/notbaz/bin")
219
+ @provider.delete_element.should eql(true)
220
+ @new_resource.should_not be_updated
221
+ end
222
+ end
201
223
  end
202
224
 
203
- describe "compare_value" do
225
+ describe "requires_modify_or_create?" do
204
226
  before(:each) do
205
227
  @new_resource.value("C:/bar")
206
228
  @current_resource = @new_resource.clone
@@ -208,25 +230,68 @@ describe Chef::Provider::Env do
208
230
  end
209
231
 
210
232
  it "should return false if the values are equal" do
211
- @provider.compare_value.should be_false
233
+ @provider.requires_modify_or_create?.should be_false
212
234
  end
213
235
 
214
236
  it "should return true if the values not are equal" do
215
237
  @new_resource.value("C:/elsewhere")
216
- @provider.compare_value.should be_true
238
+ @provider.requires_modify_or_create?.should be_true
217
239
  end
218
240
 
219
241
  it "should return false if the current value contains the element" do
220
242
  @new_resource.delim(";")
221
243
  @current_resource.value("C:/bar;C:/foo;C:/baz")
222
244
 
223
- @provider.compare_value.should be_false
245
+ @provider.requires_modify_or_create?.should be_false
224
246
  end
225
247
 
226
248
  it "should return true if the current value does not contain the element" do
227
249
  @new_resource.delim(";")
228
250
  @current_resource.value("C:/biz;C:/foo/bin;C:/baz")
229
- @provider.compare_value.should be_true
251
+ @provider.requires_modify_or_create?.should be_true
252
+ end
253
+
254
+ context "when new_resource's value contains the delimiter" do
255
+ it "should return false if all the current values are contained" do
256
+ @new_resource.value("C:/biz;C:/baz")
257
+ @new_resource.delim(";")
258
+ @current_resource.value("C:/biz;C:/foo/bin;C:/baz")
259
+ @provider.requires_modify_or_create?.should be_false
260
+ end
261
+
262
+ it "should return true if any of the new values are not contained" do
263
+ @new_resource.value("C:/biz;C:/baz;C:/bin")
264
+ @new_resource.delim(";")
265
+ @current_resource.value("C:/biz;C:/foo/bin;C:/baz")
266
+ @provider.requires_modify_or_create?.should be_true
267
+ end
268
+ end
269
+ end
270
+
271
+ describe "modify_env" do
272
+ before(:each) do
273
+ @provider.stub(:create_env).and_return(true)
274
+ @new_resource.delim ";"
275
+
276
+ @current_resource = Chef::Resource::Env.new("FOO")
277
+ @current_resource.value "C:/foo/bin"
278
+ @provider.current_resource = @current_resource
279
+ end
280
+
281
+ it "should not modify the variable passed to the resource" do
282
+ new_value = "C:/bar/bin"
283
+ passed_value = new_value.dup
284
+ @new_resource.value(passed_value)
285
+ @provider.modify_env
286
+ passed_value.should == new_value
287
+ end
288
+
289
+ it "should only add values not already contained when a delimiter is provided" do
290
+ @new_resource.value("C:/foo;C:/bar;C:/baz")
291
+ @new_resource.delim(";")
292
+ @current_resource.value("C:/foo/bar;C:/bar;C:/baz")
293
+ @provider.modify_env
294
+ @new_resource.value.should eq("C:/foo;C:/foo/bar;C:/bar;C:/baz")
230
295
  end
231
296
  end
232
297
  end