diff options
author | Jay Mundrawala <jdmundrawala@gmail.com> | 2014-10-09 15:25:14 -0700 |
---|---|---|
committer | Jay Mundrawala <jdmundrawala@gmail.com> | 2014-10-09 15:25:14 -0700 |
commit | 38b215e3e1d8eb631bedc80393ed09dce03d4db6 (patch) | |
tree | 9d348471c919635796047d3690963cb40f710a93 | |
parent | d15e4e2734741e9251fbb6f83a5542e17d8303a3 (diff) | |
download | chef-jdmundrawala/test.tar.gz |
Removing tests I don't needjdmundrawala/test
454 files changed, 0 insertions, 87375 deletions
diff --git a/spec/functional/application_spec.rb b/spec/functional/application_spec.rb deleted file mode 100644 index 4a0fdff8f8..0000000000 --- a/spec/functional/application_spec.rb +++ /dev/null @@ -1,58 +0,0 @@ -# -# 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 'chef/mixin/shell_out' - -describe Chef::Application do - include Chef::Mixin::ShellOut - - before do - @original_argv = ARGV.dup - ARGV.clear - @original_env = ENV.to_hash - ENV.clear - @app = Chef::Application.new - end - - after do - ARGV.replace(@original_argv) - ENV.clear - ENV.update(@original_env) - end - - describe "when proxy options are set in config" do - before do - Chef::Config[:http_proxy] = "http://proxy.example.org:8080" - Chef::Config[:https_proxy] = nil - Chef::Config[:ftp_proxy] = nil - Chef::Config[:no_proxy] = nil - - @app.configure_proxy_environment_variables - 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 - - so.stdout.chomp.should == "http://proxy.example.org:8080" - end - end -end diff --git a/spec/functional/assets/PkgA.1.0.0.0.bff b/spec/functional/assets/PkgA.1.0.0.0.bff Binary files differdeleted file mode 100644 index b157d080e8..0000000000 --- a/spec/functional/assets/PkgA.1.0.0.0.bff +++ /dev/null diff --git a/spec/functional/assets/PkgA.2.0.0.0.bff b/spec/functional/assets/PkgA.2.0.0.0.bff Binary files differdeleted file mode 100644 index 0afe7b7f12..0000000000 --- a/spec/functional/assets/PkgA.2.0.0.0.bff +++ /dev/null diff --git a/spec/functional/assets/dummy-1-0.aix6.1.noarch.rpm b/spec/functional/assets/dummy-1-0.aix6.1.noarch.rpm Binary files differdeleted file mode 100644 index 1c6f129a9a..0000000000 --- a/spec/functional/assets/dummy-1-0.aix6.1.noarch.rpm +++ /dev/null diff --git a/spec/functional/assets/dummy-2-0.aix6.1.noarch.rpm b/spec/functional/assets/dummy-2-0.aix6.1.noarch.rpm Binary files differdeleted file mode 100644 index 650b7dd9ba..0000000000 --- a/spec/functional/assets/dummy-2-0.aix6.1.noarch.rpm +++ /dev/null diff --git a/spec/functional/assets/mytest-1.0-1.noarch.rpm b/spec/functional/assets/mytest-1.0-1.noarch.rpm Binary files differdeleted file mode 100644 index 07334a0cc7..0000000000 --- a/spec/functional/assets/mytest-1.0-1.noarch.rpm +++ /dev/null diff --git a/spec/functional/assets/mytest-2.0-1.noarch.rpm b/spec/functional/assets/mytest-2.0-1.noarch.rpm Binary files differdeleted file mode 100644 index 7e7ba17839..0000000000 --- a/spec/functional/assets/mytest-2.0-1.noarch.rpm +++ /dev/null diff --git a/spec/functional/dsl/reboot_pending_spec.rb b/spec/functional/dsl/reboot_pending_spec.rb deleted file mode 100644 index 114754ccba..0000000000 --- a/spec/functional/dsl/reboot_pending_spec.rb +++ /dev/null @@ -1,121 +0,0 @@ -# -# Author:: Bryan McLellan <btm@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/dsl/reboot_pending" -require "chef/win32/registry" -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_safe? - !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') - end - - let(:node) { Chef::Node.new } - let(:events) { Chef::EventDispatch::Dispatcher.new } - let!(:ohai) { run_ohai } # Ensure we have necessary node data - 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 - - describe "when there is nothing to indicate a reboot is pending" do - it "should return false" do - pending "Found existing registry keys" unless registry_safe? - expect(recipe.reboot_pending?).to be_false - end - end - - describe 'HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations' do - it "returns true if the registry value exists" do - pending "Found existing registry keys" unless registry_safe? - registry.set_value('HKLM\SYSTEM\CurrentControlSet\Control\Session Manager', - { :name => 'PendingFileRenameOperations', :type => :multi_string, :data => ['\??\C:\foo.txt|\??\C:\bar.txt'] }) - - expect(recipe.reboot_pending?).to be_true - end - - after do - if registry_safe? - registry.delete_value('HKLM\SYSTEM\CurrentControlSet\Control\Session Manager', { :name => 'PendingFileRenameOperations' }) - end - end - end - - describe 'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired' do - it "returns true if the registry key exists" do - pending "Found existing registry keys" unless registry_safe? - registry.create_key('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired', false) - - expect(recipe.reboot_pending?).to be_true - end - - after do - if registry_safe? - registry.delete_key('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired', false) - end - end - end - - describe 'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootRequired' do - it "returns true if the registry key exists" do - pending "Permissions are limited to 'TrustedInstaller' by default" - pending "Found existing registry keys" unless registry_safe? - registry.create_key('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootRequired', false) - - expect(recipe.reboot_pending?).to be_true - end - - after do - if registry_safe? - registry.delete_key('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootRequired', false) - end - end - end - - describe 'HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile\Flags' do - it "returns true if the registry key exists" do - pending "Found existing registry keys" unless registry_safe? - 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_true - end - - after do - if registry_safe? - registry.delete_value('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile', { :name => 'Flags' }) - registry.delete_key('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile', false) - end - end - end - end -end diff --git a/spec/functional/dsl/registry_helper_spec.rb b/spec/functional/dsl/registry_helper_spec.rb deleted file mode 100644 index 452c4c2799..0000000000 --- a/spec/functional/dsl/registry_helper_spec.rb +++ /dev/null @@ -1,63 +0,0 @@ -# -# Author:: Prajakta Purohit (<prajakta@opscode.com>) -# Copyright:: Copyright (c) 2011 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/dsl/registry_helper" -require "spec_helper" - -describe Chef::Resource::RegistryKey, :windows_only do - - before (:all) 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"]) - end - - 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.new("foo", run_context) - end - - context "tests registry dsl" do - it "returns true if registry_key_exists" do - @resource.registry_key_exists?("HKCU\\Software\\Root").should == true - end - it "returns true if registry has specified value" do - values = @resource.registry_get_values("HKCU\\Software\\Root") - values.include?({:name=>"RootType1",:type=>:string,:data=>"fibrous"}).should == true - end - it "returns true if specified registry_has_subkey" do - @resource.registry_has_subkeys?("HKCU\\Software\\Root").should == true - end - it "returns true if specified key has specified subkey" do - subkeys = @resource.registry_get_subkeys("HKCU\\Software\\Root") - subkeys.include?("Branch").should == true - end - it "returns true if registry_value_exists" do - @resource.registry_value_exists?("HKCU\\Software\\Root", {:name=>"RootType1", :type=>:string, :data=>"fibrous"}).should == true - end - it "returns true if data_value_exists" do - @resource.registry_data_exists?("HKCU\\Software\\Root", {:name=>"RootType1", :type=>:string, :data=>"fibrous"}).should == true - end - end -end diff --git a/spec/functional/file_content_management/deploy_strategies_spec.rb b/spec/functional/file_content_management/deploy_strategies_spec.rb deleted file mode 100644 index dd1ef6228f..0000000000 --- a/spec/functional/file_content_management/deploy_strategies_spec.rb +++ /dev/null @@ -1,239 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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' - -shared_examples_for "a content deploy strategy" do - - # Ruby 1.8 has no binread - def binread(file) - if IO.respond_to?(:binread) - IO.binread(file) - else - IO.read(file) - end - end - - def normalize_mode(mode_int) - ( mode_int & 07777).to_s(8) - end - - let(:sandbox_dir) do - basename = make_tmpname("content-deploy-tests") - full_path = File.join(CHEF_SPEC_DATA, basename) - FileUtils.mkdir_p(full_path) - full_path - end - - after do - FileUtils.rm_rf(sandbox_dir) if File.exist?(sandbox_dir) - end - - 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 - - ## - # UNIX Context - let(:default_mode) { normalize_mode(0100666 - File.umask) } - - it "touches the file to create it (UNIX)", :unix_only do - content_deployer.create(target_file_path) - File.should exist(target_file_path) - file_info = File.stat(target_file_path) - file_info.should be_owned - file_info.should be_file - normalize_mode(file_info.mode).should == default_mode - end - - ## - # Window Context - let(:parent_dir) { File.dirname(target_file_path) } - - let(:parent_security_descriptor) do - security_obj = Chef::ReservedNames::Win32::Security::SecurableObject.new(parent_dir) - security_obj.security_descriptor(true) - end - - let(:masks) do - Chef::ReservedNames::Win32::API::Security - end - - def ace_inherits?(ace) - flags = ace.flags - (flags & masks::OBJECT_INHERIT_ACE) !=0 - end - - let(:parent_inheritable_aces) do - inheritable_aces = parent_security_descriptor.dacl.select do |ace| - ace_inherits?(ace) - end - end - - it "touches the file to create it (Windows)", :windows_only do - content_deployer.create(target_file_path) - File.should exist(target_file_path) - file_info = File.stat(target_file_path) - file_info.should be_owned - file_info.should be_file - - parent_aces = parent_inheritable_aces - security_obj = Chef::ReservedNames::Win32::Security::SecurableObject.new(target_file_path) - - security_descriptor = security_obj.security_descriptor(true) - # On certain windows systems like 2003 and Azure VMs there are some default - # ACEs that are not inherited from parents. So filter out the parents before - # comparing the aces - self_aces = security_descriptor.dacl.select do |ace| - ace_inherits?(ace) - end - - self_aces.each_with_index do |ace, index| - ace.mask.should == parent_aces[index].mask - end - end - end - - describe "updating the file" do - - let(:staging_dir) { Dir.mktmpdir } - - let(:staging_file_content) { "this is the expected content" } - - let(:staging_file_path) do - path = File.join(staging_dir, "cp-deploy-strategy-staging-file.txt") - File.open(path, "w+", 0600) { |f| f.print(staging_file_content) } - path - end - - def unix_invariant_properies(stat_struct) - unix_invariants.inject({}) do |property_map, property| - property_map[property] = stat_struct.send(property) - property_map - end - end - - def win_invariant_properties(sec_obj) - descriptor = sec_obj.security_descriptor(true) - security_descriptor_invariants.inject({}) do |prop_map, property| - prop_map[property] = descriptor.send(property) - prop_map - end - end - - before do - content_deployer.create(target_file_path) - end - - it "maintains invariant properties on UNIX", :unix_only do - original_info = File.stat(target_file_path) - content_deployer.deploy(staging_file_path, target_file_path) - updated_info = File.stat(target_file_path) - - unix_invariant_properies(original_info).should == unix_invariant_properies(updated_info) - end - - it "maintains invariant properties on Windows", :windows_only do - original_info = Chef::ReservedNames::Win32::Security::SecurableObject.new(target_file_path) - content_deployer.deploy(staging_file_path, target_file_path) - updated_info = Chef::ReservedNames::Win32::Security::SecurableObject.new(target_file_path) - - win_invariant_properties(original_info).should == win_invariant_properties(updated_info) - end - - it "updates the target with content from staged" do - content_deployer.deploy(staging_file_path, target_file_path) - binread(target_file_path).should == staging_file_content - end - - context "when the owner of the target file is not the owner of the staging file", :requires_root do - - before do - File.chown(1337, 1337, target_file_path) - end - - it "copies the staging file's content" do - original_info = File.stat(target_file_path) - content_deployer.deploy(staging_file_path, target_file_path) - updated_info = File.stat(target_file_path) - - unix_invariant_properies(original_info).should == unix_invariant_properies(updated_info) - end - - end - - end -end - -describe Chef::FileContentManagement::Deploy::Cp do - - let(:unix_invariants) do - [ - :uid, - :gid, - :mode, - :ino - ] - end - - let(:security_descriptor_invariants) do - [ - :owner, - :group, - :dacl - ] - end - - it_should_behave_like "a content deploy strategy" - -end - -describe Chef::FileContentManagement::Deploy::MvUnix, :unix_only do - - let(:unix_invariants) do - [ - :uid, - :gid, - :mode - ] - end - - it_should_behave_like "a content deploy strategy" -end - -# On Unix we won't have loaded the file, avoid undefined constant errors: -class Chef::FileContentManagement::Deploy::MvWindows ; end - -describe Chef::FileContentManagement::Deploy::MvWindows, :windows_only do - - context "when a file has no sacl" do - - let(:security_descriptor_invariants) do - [ - :owner, - :group, - :dacl - ] - end - - it_should_behave_like "a content deploy strategy" - end - -end diff --git a/spec/functional/http/simple_spec.rb b/spec/functional/http/simple_spec.rb deleted file mode 100644 index fec71351df..0000000000 --- a/spec/functional/http/simple_spec.rb +++ /dev/null @@ -1,140 +0,0 @@ -# -# Author:: Lamont Granquist (<lamont@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 'tiny_server' -require 'support/shared/functional/http' - -describe Chef::HTTP::Simple do - include ChefHTTPShared - - let(:http_client) { described_class.new(source) } - let(:http_client_disable_gzip) { described_class.new(source, { :disable_gzip => true } ) } - - before(:all) do - start_tiny_server - end - - after(:all) do - stop_tiny_server - end - - shared_examples_for "downloads requests correctly" do - it "successfully downloads a streaming request" do - tempfile = http_client.streaming_request(source, {}) - tempfile.close - expect(Digest::MD5.hexdigest(binread(tempfile.path))).to eq(Digest::MD5.hexdigest(expected_content)) - end - it "successfully does a non-streaming GET request" do - expect(Digest::MD5.hexdigest(http_client.get(source))).to eq(Digest::MD5.hexdigest(expected_content)) - end - end - - shared_examples_for "validates content length and throws an exception" do - it "successfully downloads a streaming request" do - expect { http_client.streaming_request(source) }.to raise_error(Chef::Exceptions::ContentLengthMismatch) - end - it "successfully does a non-streaming GET request" do - expect { http_client.get(source) }.to raise_error(Chef::Exceptions::ContentLengthMismatch) - end - end - - shared_examples_for "an endpoint that 403s" do - it "fails with a Net::HTTPServerException for a streaming request" do - expect { http_client.streaming_request(source) }.to raise_error(Net::HTTPServerException) - end - - it "fails with a Net::HTTPServerException for a GET request" do - expect { http_client.get(source) }.to raise_error(Net::HTTPServerException) - end - end - - # see CHEF-5100 - shared_examples_for "a 403 after a successful request when reusing the request object" do - it "fails with a Net::HTTPServerException for a streaming request" do - tempfile = http_client.streaming_request(source) - tempfile.close - expect(Digest::MD5.hexdigest(binread(tempfile.path))).to eq(Digest::MD5.hexdigest(expected_content)) - expect { http_client.streaming_request(source2) }.to raise_error(Net::HTTPServerException) - end - - it "fails with a Net::HTTPServerException for a GET request" do - expect(Digest::MD5.hexdigest(http_client.get(source))).to eq(Digest::MD5.hexdigest(expected_content)) - expect { http_client.get(source2) }.to raise_error(Net::HTTPServerException) - end - end - - it_behaves_like "downloading all the things" - - context "when Chef::Log.level = :debug" do - before do - Chef::Log.level = :debug - @debug_log = '' - Chef::Log.stub(:debug) { |str| @debug_log << str } - end - - 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') - 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/) - expect(@debug_log).not_to match(/HTTP Request Body/) - expect(@debug_log).not_to match(/HTTP Response Body/) - expect(@debug_log).not_to match(/Your request is just terrible./) - end - - it "Logs the request and response for 200 POST, but not the body" do - 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/) - expect(@debug_log).not_to match(/HTTP Request Body/) - expect(@debug_log).not_to match(/hithere/) - expect(@debug_log).not_to match(/HTTP Response Body/) - expect(@debug_log).not_to match(/Your request is just terrible./) - end - - it "Logs the request and response and bodies for 400 response" do - expect do - 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/) - expect(@debug_log).to match(/HTTP Status and Header Data/) - expect(@debug_log).not_to match(/HTTP Request Body/) - expect(@debug_log).not_to match(/hithere/) - expect(@debug_log).to match(/HTTP Response Body/) - expect(@debug_log).to match(/Your request is just terrible./) - end - - it "Logs the request and response and bodies for 400 POST response" do - expect do - 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/) - expect(@debug_log).to match(/HTTP Status and Header Data/) - expect(@debug_log).to match(/HTTP Request Body/) - expect(@debug_log).to match(/hithere/) - expect(@debug_log).to match(/HTTP Response Body/) - expect(@debug_log).to match(/Your request is just terrible./) - end - end -end diff --git a/spec/functional/knife/configure_spec.rb b/spec/functional/knife/configure_spec.rb deleted file mode 100644 index 3bef18a0aa..0000000000 --- a/spec/functional/knife/configure_spec.rb +++ /dev/null @@ -1,38 +0,0 @@ -# -# Author:: Bryan McLellan <btm@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 'spec_helper' - -require 'chef/knife/configure' -require 'ohai' - -describe "knife configure" do - let (:ohai) do - o = Ohai::System.new - o.load_plugins - o.require_plugin 'os' - o.require_plugin 'hostname' - o - end - - it "loads the fqdn from Ohai" do - knife_configure = Chef::Knife::Configure.new - 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 deleted file mode 100644 index ee620bf165..0000000000 --- a/spec/functional/knife/cookbook_delete_spec.rb +++ /dev/null @@ -1,157 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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. -# - -require 'spec_helper' -require 'tiny_server' - -describe Chef::Knife::CookbookDelete do - before(:all) do - @server = TinyServer::Manager.new - @server.start - end - - before(:each) do - @knife = Chef::Knife::CookbookDelete.new - @api = TinyServer::API.instance - @api.clear - - Chef::Config[:node_name] = nil - Chef::Config[:client_key] = nil - Chef::Config[:chef_server_url] = 'http://localhost:9000' - end - - after(:all) do - @server.stop - 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 - - @knife.name_args = %w{no-such-cookbook} - @api.get("/cookbooks/no-such-cookbook", 404, {'error'=>'dear Tim, no. -Sent from my iPad'}.to_json) - end - - it "logs an error and exits" do - @knife.ui.stub(:stderr).and_return(@log_output) - lambda {@knife.run}.should raise_error(SystemExit) - @log_output.string.should match(/Cannot find a cookbook named no-such-cookbook to delete/) - end - - end - - 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']} } - @api.get("/cookbooks/obsolete-cookbook", 200, @cookbook_list.to_json) - end - - it "asks for confirmation, then deletes the cookbook" do - stdin, stdout = StringIO.new("y\n"), StringIO.new - @knife.ui.stub(:stdin).and_return(stdin) - @knife.ui.stub(:stdout).and_return(stdout) - - cb100_deleted = false - @api.delete("/cookbooks/obsolete-cookbook/1.0.0", 200) { cb100_deleted = true; "[\"true\"]" } - - @knife.run - - stdout.string.should match(/#{Regexp.escape('Do you really want to delete obsolete-cookbook version 1.0.0? (Y/N)')}/) - cb100_deleted.should be_true - end - - it "asks for confirmation before purging" do - @knife.config[:purge] = true - - stdin, stdout = StringIO.new("y\ny\n"), StringIO.new - @knife.ui.stub(:stdin).and_return(stdin) - @knife.ui.stub(:stdout).and_return(stdout) - - cb100_deleted = false - @api.delete("/cookbooks/obsolete-cookbook/1.0.0?purge=true", 200) { cb100_deleted = true; "[\"true\"]" } - - @knife.run - - stdout.string.should match(/#{Regexp.escape('Are you sure you want to purge files')}/) - stdout.string.should match(/#{Regexp.escape('Do you really want to delete obsolete-cookbook version 1.0.0? (Y/N)')}/) - cb100_deleted.should be_true - - end - - end - - 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) } } - @api.get("/cookbooks/obsolete-cookbook", 200, @cookbook_list.to_json) - end - - it "deletes all versions of a cookbook when given the '-a' flag" do - @knife.config[:all] = true - @knife.config[:yes] = true - cb100_deleted = cb110_deleted = cb120_deleted = nil - @api.delete("/cookbooks/obsolete-cookbook/1.0.0", 200) { cb100_deleted = true; "[\"true\"]" } - @api.delete("/cookbooks/obsolete-cookbook/1.1.0", 200) { cb110_deleted = true; "[\"true\"]" } - @api.delete("/cookbooks/obsolete-cookbook/1.2.0", 200) { cb120_deleted = true; "[\"true\"]" } - @knife.run - - cb100_deleted.should be_true - cb110_deleted.should be_true - cb120_deleted.should be_true - end - - it "asks which version to delete and deletes that when not given the -a flag" do - cb100_deleted = cb110_deleted = cb120_deleted = nil - @api.delete("/cookbooks/obsolete-cookbook/1.0.0", 200) { cb100_deleted = true; "[\"true\"]" } - stdin, stdout = StringIO.new, StringIO.new - @knife.ui.stub(:stdin).and_return(stdin) - @knife.ui.stub(:stdout).and_return(stdout) - stdin << "1\n" - stdin.rewind - @knife.run - cb100_deleted.should be_true - stdout.string.should match(/Which version\(s\) do you want to delete\?/) - end - - it "deletes all versions of the cookbook when not given the -a flag and the user chooses to delete all" do - cb100_deleted = cb110_deleted = cb120_deleted = nil - @api.delete("/cookbooks/obsolete-cookbook/1.0.0", 200) { cb100_deleted = true; "[\"true\"]" } - @api.delete("/cookbooks/obsolete-cookbook/1.1.0", 200) { cb110_deleted = true; "[\"true\"]" } - @api.delete("/cookbooks/obsolete-cookbook/1.2.0", 200) { cb120_deleted = true; "[\"true\"]" } - - stdin, stdout = StringIO.new("4\n"), StringIO.new - @knife.ui.stub(:stdin).and_return(stdin) - @knife.ui.stub(:stdout).and_return(stdout) - - @knife.run - - cb100_deleted.should be_true - cb110_deleted.should be_true - cb120_deleted.should be_true - end - - end - -end diff --git a/spec/functional/knife/exec_spec.rb b/spec/functional/knife/exec_spec.rb deleted file mode 100644 index 455160fd5c..0000000000 --- a/spec/functional/knife/exec_spec.rb +++ /dev/null @@ -1,57 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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. -# - -require 'spec_helper' -require 'tiny_server' - -describe Chef::Knife::Exec do - before(:all) do - @server = TinyServer::Manager.new#(:debug => true) - @server.start - end - - before(:each) do - @knife = Chef::Knife::Exec.new - @api = TinyServer::API.instance - @api.clear - - Chef::Config[:node_name] = nil - Chef::Config[:client_key] = nil - Chef::Config[:chef_server_url] = 'http://localhost:9000' - - $output = StringIO.new - end - - after(:all) do - @server.stop - end - - pending "executes a script in the context of the chef-shell main context", :ruby_18_only - - it "executes a script in the context of the chef-shell main context", :ruby_gte_19_only do - @node = Chef::Node.new - @node.name("ohai-world") - response = {"rows" => [@node],"start" => 0,"total" => 1} - @api.get(%r{^/search/node}, 200, response.to_json) - code = "$output.puts nodes.all" - @knife.config[:exec] = code - @knife.run - $output.string.should match(%r{node\[ohai-world\]}) - end - -end diff --git a/spec/functional/knife/smoke_test.rb b/spec/functional/knife/smoke_test.rb deleted file mode 100644 index 6ccd462516..0000000000 --- a/spec/functional/knife/smoke_test.rb +++ /dev/null @@ -1,34 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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. -# - -require 'spec_helper' - -describe "knife smoke tests" do - - # Since our specs load all code, there could be a case where knife does not - # run correctly b/c of a missing require, but is not caught by other tests. - # - # We run `knife -v` to verify that knife at least loads all its code. - it "can run and print its version" do - knife_path = File.expand_path("../../bin/knife", CHEF_SPEC_DATA) - knife_cmd = Mixlib::ShellOut.new("#{knife_path} -v") - knife_cmd.run_command - knife_cmd.error! - knife_cmd.stdout.should include(Chef::VERSION) - end -end diff --git a/spec/functional/knife/ssh_spec.rb b/spec/functional/knife/ssh_spec.rb deleted file mode 100644 index 40d71859c7..0000000000 --- a/spec/functional/knife/ssh_spec.rb +++ /dev/null @@ -1,268 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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. -# - -require 'spec_helper' -require 'tiny_server' - -describe Chef::Knife::Ssh do - - before(:all) do - Chef::Knife::Ssh.load_deps - @server = TinyServer::Manager.new - @server.start - end - - after(:all) do - @server.stop - end - - describe "identity file" do - context "when knife[:ssh_identity_file] is set" do - before do - setup_knife(['*:*', 'uptime']) - Chef::Config[:knife][:ssh_identity_file] = "~/.ssh/aws.rsa" - end - - it "uses the ssh_identity_file" do - @knife.run - @knife.config[:identity_file].should == "~/.ssh/aws.rsa" - end - end - - context "when knife[:ssh_identity_file] is set and frozen" do - before do - setup_knife(['*:*', 'uptime']) - Chef::Config[:knife][:ssh_identity_file] = "~/.ssh/aws.rsa".freeze - end - - it "uses the ssh_identity_file" do - @knife.run - @knife.config[:identity_file].should == "~/.ssh/aws.rsa" - end - end - - context "when -i is provided" do - before do - 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 - @knife.config[:identity_file].should == "~/.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 - @knife.config[:identity_file].should == "~/.ssh/aws.rsa" - end - end - - context "when knife[:ssh_identity_file] is not provided]" do - before do - setup_knife(['*:*', 'uptime']) - Chef::Config[:knife][:ssh_identity_file] = nil - end - - it "uses the default" do - @knife.run - @knife.config[:identity_file].should == nil - end - end - end - - describe "port" do - context "when -p 31337 is provided" do - before do - setup_knife(['-p 31337', '*:*', 'uptime']) - end - - it "uses the ssh_port" do - @knife.run - @knife.config[:ssh_port].should == "31337" - end - end - end - - describe "user" do - context "when knife[:ssh_user] is set" do - before do - setup_knife(['*:*', 'uptime']) - Chef::Config[:knife][:ssh_user] = "ubuntu" - end - - it "uses the ssh_user" do - @knife.run - @knife.config[:ssh_user].should == "ubuntu" - end - end - - context "when knife[:ssh_user] is set and frozen" do - before do - setup_knife(['*:*', 'uptime']) - Chef::Config[:knife][:ssh_user] = "ubuntu".freeze - end - - it "uses the ssh_user" do - @knife.run - @knife.config[:ssh_user].should == "ubuntu" - end - end - - context "when -x is provided" do - before do - setup_knife(['-x ubuntu', '*:*', 'uptime']) - Chef::Config[:knife][:ssh_user] = nil - end - - it "should use the value on the command line" do - @knife.run - @knife.config[:ssh_user].should == "ubuntu" - end - - it "should override what is set in knife.rb" do - Chef::Config[:knife][:ssh_user] = "root" - @knife.run - @knife.config[:ssh_user].should == "ubuntu" - end - end - - context "when knife[:ssh_user] is not provided]" do - before do - setup_knife(['*:*', 'uptime']) - Chef::Config[:knife][:ssh_user] = nil - end - - it "uses the default (current user)" do - @knife.run - @knife.config[:ssh_user].should == nil - end - end - end - - describe "attribute" do - context "when knife[:ssh_attribute] is set" do - before do - setup_knife(['*:*', 'uptime']) - Chef::Config[:knife][:ssh_attribute] = "ec2.public_hostname" - end - - it "uses the ssh_attribute" do - @knife.run - @knife.config[:attribute].should == "ec2.public_hostname" - end - end - - context "when knife[:ssh_attribute] is not provided]" do - before do - setup_knife(['*:*', 'uptime']) - Chef::Config[:knife][:ssh_attribute] = nil - end - - it "uses the default" do - @knife.run - @knife.config[:attribute].should == "fqdn" - end - end - - context "when -a ec2.public_ipv4 is provided" do - before do - setup_knife(['-a ec2.public_hostname', '*:*', 'uptime']) - Chef::Config[:knife][:ssh_attribute] = nil - end - - it "should use the value on the command line" do - @knife.run - @knife.config[:attribute].should == "ec2.public_hostname" - end - - it "should override what is set in knife.rb" 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']) - @knife.run - @knife.config[:attribute].should == "ec2.public_hostname" - end - end - end - - describe "gateway" do - context "when knife[:ssh_gateway] is set" do - before do - setup_knife(['*:*', 'uptime']) - Chef::Config[:knife][:ssh_gateway] = "user@ec2.public_hostname" - end - - it "uses the ssh_gateway" do - @knife.session.should_receive(:via).with("ec2.public_hostname", "user", {}) - @knife.run - @knife.config[:ssh_gateway].should == "user@ec2.public_hostname" - end - end - - context "when -G user@ec2.public_hostname is provided" do - before do - setup_knife(['-G user@ec2.public_hostname', '*:*', 'uptime']) - Chef::Config[:knife][:ssh_gateway] = nil - end - - it "uses the ssh_gateway" do - @knife.session.should_receive(:via).with("ec2.public_hostname", "user", {}) - @knife.run - @knife.config[:ssh_gateway].should == "user@ec2.public_hostname" - end - end - - context "when the gateway requires a password" do - before do - setup_knife(['-G user@ec2.public_hostname', '*:*', 'uptime']) - Chef::Config[:knife][:ssh_gateway] = nil - @knife.session.stub(:via) do |host, user, options| - raise Net::SSH::AuthenticationFailed unless options[:password] - end - end - - it "should prompt the user for a password" do - @knife.ui.should_receive(:ask).with("Enter the password for user@ec2.public_hostname: ").and_return("password") - @knife.run - end - end - end - - 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 - # necessary to have default options merged in. - @knife.merge_configs - @knife.stub(:ssh_command).and_return { 0 } - @api = TinyServer::API.instance - @api.clear - - Chef::Config[:node_name] = nil - Chef::Config[:client_key] = nil - Chef::Config[:chef_server_url] = 'http://localhost:9000' - - @api.get("/search/node?q=*:*&sort=X_CHEF_id_CHEF_X%20asc&start=0&rows=1000", 200) { - %({"total":1, "start":0, "rows":[{"name":"i-xxxxxxxx", "json_class":"Chef::Node", "automatic":{"fqdn":"the.fqdn", "ec2":{"public_hostname":"the_public_hostname"}},"recipes":[]}]}) - } - end - -end diff --git a/spec/functional/mixin/shell_out_spec.rb b/spec/functional/mixin/shell_out_spec.rb deleted file mode 100644 index 35e5b30eae..0000000000 --- a/spec/functional/mixin/shell_out_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -# -# 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' - -describe Chef::Mixin::ShellOut do - include Chef::Mixin::ShellOut - - describe "shell_out_with_systems_locale" 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 - - 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 - - expect(cmd.stdout.chomp).to eq 'POSIX' - end - end - end -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 deleted file mode 100755 index 63a4578c69..0000000000 --- a/spec/functional/provider/remote_file/cache_control_data_spec.rb +++ /dev/null @@ -1,101 +0,0 @@ -# -# Author:: Adam Edwards (<adamed@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' -require 'uri' - -describe Chef::Provider::RemoteFile::CacheControlData do - - before do - @original_config = Chef::Config.hash_dup - end - - after do - Chef::Config.configuration = @original_config if @original_config - end - - before(:each) do - Chef::Config[:file_cache_path] = Dir.mktmpdir - end - - after(:each) do - FileUtils.rm_rf(Chef::Config[:file_cache_path]) - 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 - Chef::Provider::RemoteFile::CacheControlData.load_and_validate(uri, file_checksum) - end - - # the checksum of the file last we fetched it. - let(:file_checksum) { "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" } - - let(:etag) { "\"a-strong-identifier\"" } - let(:mtime) { "Thu, 01 Aug 2013 08:16:32 GMT" } - - before do - cache_control_data.etag = etag - cache_control_data.mtime = mtime - cache_control_data.checksum = file_checksum - end - - it "writes data to the cache" do - cache_control_data.save - end - - it "writes the data to the cache and the same data can be read back" do - cache_control_data.save - saved_cache_control_data = Chef::Provider::RemoteFile::CacheControlData.load_and_validate(uri, file_checksum) - saved_cache_control_data.etag.should == cache_control_data.etag - saved_cache_control_data.mtime.should == cache_control_data.mtime - saved_cache_control_data.checksum.should == cache_control_data.checksum - end - - # Cover the very long remote file path case -- see CHEF-4422 where - # local cache file names generated from the long uri exceeded - # local file system path limits resulting in exceptions from - # 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)) - end - - let(:uri) { uri_exceeds_file_system_limit } - - it "writes data to the cache" do - lambda do - cache_control_data.save - end.should_not raise_error - end - - it "writes the data to the cache and the same data can be read back" do - cache_control_data.save - saved_cache_control_data = Chef::Provider::RemoteFile::CacheControlData.load_and_validate(uri, file_checksum) - saved_cache_control_data.etag.should == cache_control_data.etag - saved_cache_control_data.mtime.should == cache_control_data.mtime - saved_cache_control_data.checksum.should == 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 deleted file mode 100644 index 150d46d384..0000000000 --- a/spec/functional/provider/whyrun_safe_ruby_block_spec.rb +++ /dev/null @@ -1,51 +0,0 @@ -# -# Author:: Serdar Sutay (<serdar@opscode.com>) -# Copyright:: Copyright (c) 2014 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::WhyrunSafeRubyBlock do - let(:node) { Chef::Node.new } - - let(:run_context) { - events = Chef::EventDispatch::Dispatcher.new - Chef::RunContext.new(node, {}, events) - } - - before do - $evil_global_evil_laugh = :wahwah - Chef::Config[:why_run] = true - end - - after do - Chef::Config[:why_run] = false - end - - describe "when testing the resource" do - let(:new_resource) do - r = Chef::Resource::WhyrunSafeRubyBlock.new("reload all", run_context) - r.block { $evil_global_evil_laugh = :mwahahaha } - r - end - - it "updates the evil laugh, even in why-run mode" do - new_resource.run_action(new_resource.action) - $evil_global_evil_laugh.should == :mwahahaha - new_resource.should be_updated - end - end -end diff --git a/spec/functional/rebooter_spec.rb b/spec/functional/rebooter_spec.rb deleted file mode 100644 index 8006580d5c..0000000000 --- a/spec/functional/rebooter_spec.rb +++ /dev/null @@ -1,105 +0,0 @@ -# -# Author:: Chris Doherty <cdoherty@getchef.com>) -# Copyright:: Copyright (c) 2014 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::Platform::Rebooter do - - let(:reboot_info) do - { - :delay_mins => 5, - :requested_by => "reboot resource functional test", - :reason => "rebooter spec test" - } - end - - def create_resource - resource = Chef::Resource::Reboot.new(expected[:requested_by], run_context) - resource.delay_mins(expected[:delay_mins]) - resource.reason(expected[:reason]) - resource - end - - let(:run_context) do - node = Chef::Node.new - events = Chef::EventDispatch::Dispatcher.new - Chef::RunContext.new(node, {}, events) - end - - let(:expected) do - { - :windows => 'shutdown /r /t 5 /c "rebooter spec test"', - :linux => 'shutdown -r +5 "rebooter spec test"' - } - end - - let(:rebooter) { Chef::Platform::Rebooter } - - describe '#reboot_if_needed!' do - - it 'should not call #shell_out! when reboot has not been requested' do - expect(rebooter).to receive(:shell_out!).exactly(0).times - expect(rebooter).to receive(:reboot_if_needed!).once.and_call_original - rebooter.reboot_if_needed!(run_context.node) - end - - describe 'calling #shell_out! to reboot' do - - before(:each) do - run_context.request_reboot(reboot_info) - end - - after(:each) do - run_context.cancel_reboot - end - - shared_context 'test a reboot method' do - def test_rebooter_method(method_sym, is_windows, expected_reboot_str) - Chef::Platform.stub(: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) - end - end - - describe 'when using #reboot_if_needed!' do - include_context 'test a reboot method' - - 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 - test_rebooter_method(:reboot_if_needed!, false, expected[:linux]) - end - end - - describe 'when using #reboot!' do - include_context 'test a reboot method' - - 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 - test_rebooter_method(:reboot!, false, expected[:linux]) - end - end - end - end -end diff --git a/spec/functional/resource/batch_spec.rb b/spec/functional/resource/batch_spec.rb deleted file mode 100644 index baa01ee5d9..0000000000 --- a/spec/functional/resource/batch_spec.rb +++ /dev/null @@ -1,37 +0,0 @@ -# -# Author:: Adam Edwards (<adamed@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::Batch, :windows_only do - include_context Chef::Resource::WindowsScript - - let(:script_content) { "whoami" } - - let!(:resource) do - Chef::Resource::WindowsScript::Batch.new("Batch resource functional test", @run_context) - end - - describe "when the run action is invoked on Windows" do - it "executes the script code" do - resource.code(script_content + " > #{script_output_path}") - resource.returns(0) - resource.run_action(:run) - end - end -end diff --git a/spec/functional/resource/bff_spec.rb b/spec/functional/resource/bff_spec.rb deleted file mode 100644 index b969254b6b..0000000000 --- a/spec/functional/resource/bff_spec.rb +++ /dev/null @@ -1,122 +0,0 @@ -# -# Author:: Prabhu Das (<prabhu.das@clogeny.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 '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 - include Chef::Mixin::ShellOut - - let(:new_resource) do - new_resource = Chef::Resource::BffPackage.new(@pkg_name, run_context) - new_resource.source @pkg_path - new_resource - end - - def bff_pkg_should_be_installed(resource) - expect(shell_out("lslpp -L #{resource.name}").exitstatus).to eq(0) - ::File.exists?("/usr/PkgA/bin/acommand") - end - - def bff_pkg_should_be_removed(resource) - expect(shell_out("lslpp -L #{resource.name}").exitstatus).to eq(1) - !::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 - end - - after(:all) do - FileUtils.rm @pkg_path - end - - context "package install action" do - it "should install a package" do - new_resource.run_action(:install) - bff_pkg_should_be_installed(new_resource) - end - - after(:each) do - shell_out("installp -u #{@pkg_name}") - end - end - - context "package install action with options" do - it "should install a package" do - new_resource.options("-e/tmp/installp.log") - new_resource.run_action(:install) - bff_pkg_should_be_installed(new_resource) - end - - after(:each) do - shell_out("installp -u #{@pkg_name}") - FileUtils.rm "/tmp/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 - end - - it "should upgrade package" do - new_resource.run_action(:install) - bff_pkg_should_be_installed(new_resource) - end - - after(:each) do - shell_out("installp -u #{@pkg_name}") - FileUtils.rm @pkg_path - end - end - - context "package remove action" do - before(:each) do - shell_out("installp -aYF -d #{@pkg_path} #{@pkg_name}") - end - - it "should remove an installed package" do - new_resource.run_action(:remove) - bff_pkg_should_be_removed(new_resource) - end - end - - context "package remove action with options" do - before(:each) do - shell_out("installp -aYF -d #{@pkg_path} #{@pkg_name}") - end - - it "should remove an installed package" do - new_resource.options("-e/tmp/installp.log") - new_resource.run_action(:remove) - bff_pkg_should_be_removed(new_resource) - end - - after(:each) do - FileUtils.rm "/tmp/installp.log" - end - end -end - diff --git a/spec/functional/resource/cookbook_file_spec.rb b/spec/functional/resource/cookbook_file_spec.rb deleted file mode 100644 index 7797ed0041..0000000000 --- a/spec/functional/resource/cookbook_file_spec.rb +++ /dev/null @@ -1,81 +0,0 @@ -# -# Author:: Tim Hinderliter (<tim@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::Resource::CookbookFile do - include_context Chef::Resource::File - - 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| - f.read - end - content.force_encoding(Encoding::BINARY) if content.respond_to?(:force_encoding) - content - end - - let(:default_mode) { ((0100666 - File.umask) & 07777).to_s(8) } - - it_behaves_like "a securable resource with reporting" - - 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')) - Chef::Cookbook::FileVendor.fetch_from_disk(cookbook_repo) - loader = Chef::CookbookLoader.new(cookbook_repo) - loader.load_cookbooks - cookbook_collection = Chef::CookbookCollection.new(loader) - - node = Chef::Node.new - events = Chef::EventDispatch::Dispatcher.new - run_context = Chef::RunContext.new(node, cookbook_collection, events) - resource = Chef::Resource::CookbookFile.new(path, run_context) - resource.cookbook(cookbook_name) - resource.source(source) - - resource - end - - let(:resource) do - create_resource - end - - it_behaves_like "a file resource" - - # These examples cover CHEF-3467 where unexpected and incorrect - # permissions can result on Windows because CookbookFile's - # 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(:path) { File.join(windows_non_temp_dir, make_tmpname(file_base)) } - - before do - FileUtils::mkdir_p(windows_non_temp_dir) if Chef::Platform.windows? - end - - after do - FileUtils.rm_r(windows_non_temp_dir) if Chef::Platform.windows? && File.exists?(windows_non_temp_dir) - end - - end -end diff --git a/spec/functional/resource/cron_spec.rb b/spec/functional/resource/cron_spec.rb deleted file mode 100644 index 0a19fae0ed..0000000000 --- a/spec/functional/resource/cron_spec.rb +++ /dev/null @@ -1,166 +0,0 @@ -# encoding: UTF-8 -# -# Author:: Kaustubh Deorukhkar (<kaustubh@clogeny.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 'functional/resource/base' -require 'chef/mixin/shell_out' - -describe Chef::Resource::Cron, :requires_root, :unix_only do - - include Chef::Mixin::ShellOut - - # Platform specific validation routines. - def cron_should_exists(cron_name, command) - case ohai[:platform] - when "aix", "solaris", "opensolaris", "solaris2", "omnios" - expect(shell_out("crontab -l #{new_resource.user} | grep \"#{cron_name}\"").exitstatus).to eq(0) - expect(shell_out("crontab -l #{new_resource.user} | grep \"#{cron_name}\"").stdout.lines.to_a.size).to eq(1) - expect(shell_out("crontab -l #{new_resource.user} | grep \"#{command}\"").exitstatus).to eq(0) - expect(shell_out("crontab -l #{new_resource.user} | grep \"#{command}\"").stdout.lines.to_a.size).to eq(1) - else - expect(shell_out("crontab -l -u #{new_resource.user} | grep \"#{cron_name}\"").exitstatus).to eq(0) - expect(shell_out("crontab -l #{new_resource.user} | grep \"#{cron_name}\"").stdout.lines.to_a.size).to eq(0) - expect(shell_out("crontab -l -u #{new_resource.user} | grep \"#{command}\"").exitstatus).to eq(0) - expect(shell_out("crontab -l #{new_resource.user} | grep \"#{command}\"").stdout.lines.to_a.size).to eq(0) - end - end - - def cron_should_not_exists(cron_name) - case ohai[:platform] - when "aix", "solaris", "opensolaris", "solaris2", "omnios" - expect(shell_out("crontab -l #{new_resource.user} | grep \"#{cron_name}\"").exitstatus).to eq(1) - expect(shell_out("crontab -l #{new_resource.user} | grep \"#{new_resource.command}\"").stdout.lines.to_a.size).to eq(0) - else - expect(shell_out("crontab -l -u #{new_resource.user} | grep \"#{cron_name}\"").exitstatus).to eq(1) - expect(shell_out("crontab -l -u #{new_resource.user} | grep \"#{new_resource.command}\"").stdout.lines.to_a.size).to eq(0) - end - end - - # Actual tests - let(:new_resource) do - new_resource = Chef::Resource::Cron.new("Chef functional test cron", run_context) - new_resource.user 'root' - new_resource.minute '@hourly' - new_resource.hour '' - new_resource.day '' - new_resource.month '' - new_resource.weekday '' - new_resource.command "/bin/true" - new_resource - end - - let(:provider) do - provider = new_resource.provider_for_action(new_resource.action) - provider - end - - describe "create action" do - after do - new_resource.run_action(:delete) - end - - it "should create a crontab entry" do - new_resource.run_action(:create) - cron_should_exists(new_resource.name, new_resource.command) - end - - it "should create exactly one crontab entry" do - 5.times { new_resource.run_action(:create) } - cron_should_exists(new_resource.name, new_resource.command) - end - end - - describe "delete action" do - before do - new_resource.run_action(:create) - end - - it "should delete a crontab entry" do - # Note that test cron is created by previous test - new_resource.run_action(:delete) - - cron_should_not_exists(new_resource.name) - end - end - - 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./) - else - resource.run_action(:create) - # Verify if the cron is created successfully - cron_attribute_should_exists(resource.name, attribute, value) - end - end - - def cron_attribute_should_exists(cron_name, attribute, value) - 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) - end - - after do - new_resource.run_action(:delete) - end - - it "should create a crontab entry for mailto attribute" do - new_resource.mailto "cheftest@example.com" - create_and_validate_with_attribute(new_resource, "mailto", "cheftest@example.com") - end - - it "should create a crontab entry for path attribute" do - new_resource.path "/usr/local/bin" - create_and_validate_with_attribute(new_resource, "path", "/usr/local/bin") - end - - it "should create a crontab entry for shell attribute" do - new_resource.shell "/bin/bash" - create_and_validate_with_attribute(new_resource, "shell", "/bin/bash") - end - - it "should create a crontab entry for home attribute" do - new_resource.home "/home/opscode" - create_and_validate_with_attribute(new_resource, "home", "/home/opscode") - end - end - - describe "negative tests for create action" do - after do - new_resource.run_action(:delete) - end - - def cron_create_should_raise_exception - expect { new_resource.run_action(:create) }.to raise_error(Chef::Exceptions::Cron, /Error updating state of #{new_resource.name}, exit: 1/) - cron_should_not_exists(new_resource.name) - end - - it "should not create cron with invalid minute" do - new_resource.minute "invalid" - cron_create_should_raise_exception - end - - it "should not create cron with invalid user" do - new_resource.user "1-really-really-invalid-user-name" - cron_create_should_raise_exception - end - - end -end diff --git a/spec/functional/resource/deploy_revision_spec.rb b/spec/functional/resource/deploy_revision_spec.rb deleted file mode 100644 index eae422ac1d..0000000000 --- a/spec/functional/resource/deploy_revision_spec.rb +++ /dev/null @@ -1,882 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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 'tmpdir' - -# Deploy relies heavily on symlinks, so it doesn't work on windows. -describe Chef::Resource::DeployRevision, :unix_only => true do - - let(:file_cache_path) { Dir.mktmpdir } - let(:deploy_directory) { Dir.mktmpdir } - - # By making restart or other operations write to this file, we can externally - # track the order in which those operations happened. - let(:observe_order_file) { Tempfile.new("deploy-resource-observe-operations") } - - before do - Chef::Log.level = :info - @old_file_cache_path = Chef::Config[:file_cache_path] - Chef::Config[:file_cache_path] = file_cache_path - end - - after do - Chef::Config[:file_cache_path] = @old_file_cache_path - FileUtils.remove_entry_secure deploy_directory if File.exist?(deploy_directory) - FileUtils.remove_entry_secure file_cache_path - observe_order_file.close - FileUtils.remove_entry_secure observe_order_file.path - end - - before(:all) do - @ohai = Ohai::System.new - @ohai.all_plugins("os") - end - - let(:node) do - - Chef::Node.new.tap do |n| - n.name "rspec-test" - n.consume_external_attrs(@ohai.data, {}) - end - end - - let(:event_dispatch) { Chef::EventDispatch::Dispatcher.new } - let(:run_context) { Chef::RunContext.new(node, {}, event_dispatch) } - - # These tests use git's bundle feature, which is a way to export an entire - # git repo (or subset of commits) as a single file. - # - # Generally you can treat a git bundle as a regular git remote. - # - # See also: http://git-scm.com/2010/03/10/bundles.html - let(:git_bundle_repo) { File.expand_path("git_bundles/sinatra-test-app.gitbundle", CHEF_SPEC_DATA) } - - let(:git_bundle_with_in_repo_callbacks) { File.expand_path("git_bundles/sinatra-test-app-with-callback-files.gitbundle", CHEF_SPEC_DATA) } - - let(:git_bundle_with_in_repo_symlinks) { File.expand_path("git_bundles/sinatra-test-app-with-symlinks.gitbundle", CHEF_SPEC_DATA) } - - # This is the fourth version - let(:latest_rev) { "3eb5ca6c353c83d9179dd3b29347539829b401f3" } - - # This is the third version - let(:previous_rev) { "6d19a6dbecc8e37f5b2277345885c0c783eb8fb1" } - - # This is the second version - let(:second_rev) { "0827e1b0e5043608ac0a824da5c558e252154ad0" } - - # This is the sixth version, it is on the "with-deploy-scripts" branch - let(:rev_with_in_repo_callbacks) { "2404d015882659754bdb93ad6e4b4d3d02691a82" } - - # This is the fifth version in the "with-symlinks" branch - let(:rev_with_in_repo_symlinks) { "5a4748c52aaea8250b4346a9b8ede95ee3755e28" } - - # Read values from the +observe_order_file+ and split each line. This way you - # can see in which order things really happened. - def actual_operations_order - IO.read(observe_order_file.path).split("\n").map(&:strip) - end - - # 1. touch `restart.txt` in cwd so we know that the command is run with the - # right cwd. - # 2. Append +tag+ to the `observe_order_file` so we can check the order in - # which operations happen later in the test. - def shell_restart_command(tag) - "touch restart.txt && echo '#{tag}' >> #{observe_order_file.path}" - end - - let(:basic_deploy_resource) do - Chef::Resource::DeployRevision.new(deploy_directory, run_context).tap do |r| - r.name "deploy-revision-unit-test" - r.repo git_bundle_repo - r.symlink_before_migrate({}) - r.symlinks({}) - end - end - - let(:deploy_to_latest_rev) do - basic_deploy_resource.dup.tap do |r| - r.revision(latest_rev) - r.restart_command shell_restart_command(:deploy_to_latest_rev) - end - end - - let(:deploy_to_previous_rev) do - basic_deploy_resource.dup.tap do |r| - r.revision(previous_rev) - r.restart_command shell_restart_command(:deploy_to_previous_rev) - end - end - - let(:deploy_to_latest_rev_again) do - basic_deploy_resource.dup.tap do |r| - r.revision(latest_rev) - r.restart_command shell_restart_command(:deploy_to_latest_rev_again) - end - end - - let(:deploy_to_previous_rev_again) do - basic_deploy_resource.dup.tap do |r| - r.revision(previous_rev) - r.restart_command shell_restart_command(:deploy_to_previous_rev_again) - end - end - - let(:deploy_to_second_rev) do - basic_deploy_resource.dup.tap do |r| - r.revision(second_rev) - r.restart_command shell_restart_command(:deploy_to_second_rev) - end - end - - let(:deploy_to_second_rev_again) do - basic_deploy_resource.dup.tap do |r| - r.revision(second_rev) - r.restart_command shell_restart_command(:deploy_to_second_rev_again) - end - end - - let(:deploy_to_second_rev_again_again) do - basic_deploy_resource.dup.tap do |r| - r.revision(second_rev) - r.restart_command shell_restart_command(:deploy_to_second_rev_again_again) - end - end - - # Computes the full path for +path+ relative to the deploy directory - def rel_path(path) - File.expand_path(path, deploy_directory) - end - - def actual_current_rev - Dir.chdir(rel_path("current")) do - `git rev-parse HEAD`.strip - end - end - - def self.the_app_is_deployed_at_revision(target_rev_spec) - it "deploys the app to the target revision (#{target_rev_spec})" do - target_rev = send(target_rev_spec) - - File.should exist(rel_path("current")) - - actual_current_rev.should == target_rev - - # Is the app code actually there? - File.should exist(rel_path("current/app/app.rb")) - end - end - - context "when deploying a simple app" do - describe "for the first time, with the required directory layout precreated" do - before do - FileUtils.mkdir_p(rel_path("releases")) - FileUtils.mkdir_p(rel_path("shared")) - deploy_to_latest_rev.run_action(:deploy) - end - - the_app_is_deployed_at_revision(:latest_rev) - - it "restarts the application" do - File.should exist(rel_path("current/restart.txt")) - actual_operations_order.should == %w[deploy_to_latest_rev] - end - - it "is marked as updated" do - deploy_to_latest_rev.should be_updated_by_last_action - end - end - - describe "back to a previously deployed revision, with the directory structure precreated" do - before do - FileUtils.mkdir_p(rel_path("releases")) - FileUtils.mkdir_p(rel_path("shared")) - - deploy_to_latest_rev.run_action(:deploy) - deploy_to_previous_rev.run_action(:deploy) - deploy_to_latest_rev_again.run_action(:deploy) - end - - the_app_is_deployed_at_revision(:latest_rev) - - it "restarts the application after rolling back" do - actual_operations_order.should == %w[deploy_to_latest_rev deploy_to_previous_rev deploy_to_latest_rev_again] - end - - it "is marked updated" do - deploy_to_latest_rev_again.should be_updated_by_last_action - end - - it "deploys the right code" do - IO.read(rel_path("current/app/app.rb")).should include("this is the fourth version of the app") - end - end - - describe "for the first time, with no existing directory layout" do - before do - deploy_to_latest_rev.run_action(:deploy) - end - - it "creates the required directory tree" do - File.should be_directory(rel_path("releases")) - File.should be_directory(rel_path("shared")) - File.should be_directory(rel_path("releases/#{latest_rev}")) - - File.should be_directory(rel_path("current/tmp")) - File.should be_directory(rel_path("current/config")) - File.should be_directory(rel_path("current/public")) - - File.should be_symlink(rel_path("current")) - File.readlink(rel_path("current")).should == rel_path("releases/#{latest_rev}") - end - - the_app_is_deployed_at_revision(:latest_rev) - - it "restarts the application" do - File.should exist(rel_path("current/restart.txt")) - actual_operations_order.should == %w[deploy_to_latest_rev] - end - - it "is marked as updated" do - deploy_to_latest_rev.should be_updated_by_last_action - end - end - - describe "again to the current revision" do - before do - deploy_to_latest_rev.run_action(:deploy) - deploy_to_latest_rev.run_action(:deploy) - end - - the_app_is_deployed_at_revision(:latest_rev) - - it "does not restart the app" do - actual_operations_order.should == %w[deploy_to_latest_rev] - end - - it "is not marked updated" do - deploy_to_latest_rev.should_not be_updated_by_last_action - end - - end - - describe "again with force_deploy" do - before do - deploy_to_latest_rev.run_action(:force_deploy) - deploy_to_latest_rev_again.run_action(:force_deploy) - end - - the_app_is_deployed_at_revision(:latest_rev) - - it "restarts the app" do - actual_operations_order.should == %w[deploy_to_latest_rev deploy_to_latest_rev_again] - end - - it "is marked updated" do - deploy_to_latest_rev.should be_updated_by_last_action - end - - end - - describe "again to a new revision" do - before do - deploy_to_previous_rev.run_action(:deploy) - deploy_to_latest_rev.run_action(:deploy) - end - - the_app_is_deployed_at_revision(:latest_rev) - - it "restarts the application after the new deploy" do - actual_operations_order.should == %w[deploy_to_previous_rev deploy_to_latest_rev] - end - - it "is marked updated" do - deploy_to_previous_rev.should be_updated_by_last_action - end - - it "leaves the old copy of the app around for rollback" do - File.should exist(File.join(deploy_directory, "releases", previous_rev)) - end - - end - - describe "back to a previously deployed revision (implicit rollback)" do - before do - deploy_to_latest_rev.run_action(:deploy) - deploy_to_previous_rev.run_action(:deploy) - deploy_to_latest_rev_again.run_action(:deploy) - end - - the_app_is_deployed_at_revision(:latest_rev) - - it "restarts the application after rolling back" do - actual_operations_order.should == %w[deploy_to_latest_rev deploy_to_previous_rev deploy_to_latest_rev_again] - end - - it "is marked updated" do - deploy_to_latest_rev_again.should be_updated_by_last_action - end - - it "deploys the right code" do - IO.read(rel_path("current/app/app.rb")).should include("this is the fourth version of the app") - end - end - - describe "back to a previously deployed revision where resource rev == latest revision (explicit rollback)" do - before do - deploy_to_previous_rev.run_action(:deploy) - @previous_rev_all_releases = deploy_to_previous_rev.provider_for_action(:deploy).all_releases - deploy_to_latest_rev.run_action(:deploy) - @latest_rev_all_releases = deploy_to_latest_rev.provider_for_action(:deploy).all_releases - deploy_to_latest_rev_again.run_action(:rollback) - @previous_rev_again_all_releases = deploy_to_latest_rev_again.provider_for_action(:deploy).all_releases - end - - the_app_is_deployed_at_revision(:previous_rev) - - it "restarts the application after rolling back" do - actual_operations_order.should == %w[deploy_to_previous_rev deploy_to_latest_rev deploy_to_latest_rev_again] - end - - it "is marked updated" do - deploy_to_latest_rev_again.should be_updated_by_last_action - end - - it "deploys the right code" do - IO.read(rel_path("current/app/app.rb")).should include("this is the third version of the app") - end - - it "all_releases after first deploy should have one entry" do - @previous_rev_all_releases.length.should == 1 - end - - it "all_releases after second deploy should have two entries" do - @latest_rev_all_releases.length.should == 2 - end - - it "all_releases after rollback should have one entry" do - @previous_rev_again_all_releases.length.should == 1 - end - - it "all_releases after rollback should be the same as after the first deploy" do - @previous_rev_again_all_releases.should == @previous_rev_all_releases - end - - end - - describe "back to a previously deployed revision where resource rev == previous revision (explicit rollback)" do - before do - deploy_to_previous_rev.run_action(:deploy) - @previous_rev_all_releases = deploy_to_previous_rev.provider_for_action(:deploy).all_releases - deploy_to_latest_rev.run_action(:deploy) - @latest_rev_all_releases = deploy_to_latest_rev.provider_for_action(:deploy).all_releases - deploy_to_previous_rev_again.run_action(:rollback) - # FIXME: only difference with previous test is using latest_rev_again insetad of previous_rev_again - @previous_rev_again_all_releases = deploy_to_latest_rev_again.provider_for_action(:deploy).all_releases - end - - the_app_is_deployed_at_revision(:previous_rev) - - it "restarts the application after rolling back" do - actual_operations_order.should == %w[deploy_to_previous_rev deploy_to_latest_rev deploy_to_previous_rev_again] - end - - it "is marked updated" do - deploy_to_previous_rev_again.should be_updated_by_last_action - end - - it "deploys the right code" do - IO.read(rel_path("current/app/app.rb")).should include("this is the third version of the app") - end - - it "all_releases after first deploy should have one entry" do - @previous_rev_all_releases.length.should == 1 - end - - it "all_releases after second deploy should have two entries" do - @latest_rev_all_releases.length.should == 2 - end - - it "all_releases after rollback should have one entry" do - @previous_rev_again_all_releases.length.should == 1 - end - - it "all_releases after rollback should be the same as after the first deploy" do - @previous_rev_again_all_releases.should == @previous_rev_all_releases - end - end - - describe "back to a previously deployed revision where resource rev == latest revision (explicit rollback)" do - before do - deploy_to_second_rev.run_action(:deploy) - @first_deploy_all_releases = deploy_to_second_rev.provider_for_action(:deploy).all_releases - deploy_to_previous_rev.run_action(:deploy) - @second_deploy_all_releases = deploy_to_previous_rev.provider_for_action(:deploy).all_releases - deploy_to_previous_rev_again.run_action(:rollback) - @third_deploy_all_releases = deploy_to_previous_rev_again.provider_for_action(:deploy).all_releases - deploy_to_latest_rev.run_action(:deploy) - @fourth_deploy_all_releases = deploy_to_latest_rev.provider_for_action(:deploy).all_releases - deploy_to_latest_rev_again.run_action(:rollback) - @fifth_deploy_all_releases = deploy_to_latest_rev_again.provider_for_action(:deploy).all_releases - end - - the_app_is_deployed_at_revision(:second_rev) - - it "restarts the application after rolling back" do - actual_operations_order.should == %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 - deploy_to_latest_rev_again.should be_updated_by_last_action - end - - it "deploys the right code" do - IO.read(rel_path("current/app/app.rb")).should include("this is the second version of the app") - end - - it "all_releases after rollback should have one entry" do - @fifth_deploy_all_releases.length.should == 1 - end - - it "all_releases after rollback should be the same as after the first deploy" do - @fifth_deploy_all_releases.should == @first_deploy_all_releases - end - end - - describe "back to a previously deployed revision where resource rev == latest revision (explicit rollback)" do - before do - deploy_to_second_rev.run_action(:deploy) - @first_deploy_all_releases = deploy_to_second_rev.provider_for_action(:deploy).all_releases - deploy_to_previous_rev.run_action(:deploy) - @second_deploy_all_releases = deploy_to_previous_rev.provider_for_action(:deploy).all_releases - deploy_to_second_rev_again.run_action(:rollback) - @third_deploy_all_releases = deploy_to_second_rev_again.provider_for_action(:deploy).all_releases - deploy_to_latest_rev.run_action(:deploy) - @fourth_deploy_all_releases = deploy_to_latest_rev.provider_for_action(:deploy).all_releases - deploy_to_second_rev_again_again.run_action(:rollback) - @fifth_deploy_all_releases = deploy_to_second_rev_again_again.provider_for_action(:deploy).all_releases - end - - the_app_is_deployed_at_revision(:second_rev) - - it "restarts the application after rolling back" do - actual_operations_order.should == %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 - deploy_to_second_rev_again_again.should be_updated_by_last_action - end - - it "deploys the right code" do - IO.read(rel_path("current/app/app.rb")).should include("this is the second version of the app") - end - - it "all_releases after rollback should have one entry" do - @fifth_deploy_all_releases.length.should == 1 - end - - it "all_releases after rollback should be the same as after the first deploy" do - @fifth_deploy_all_releases.should == @first_deploy_all_releases - end - - end - - # CHEF-3435 - describe "to a deploy_to path that does not yet exist" do - - let(:top_level_tmpdir) { Dir.mktmpdir } - - # override top level deploy_directory let block with one that is two - # directories deeper - let(:deploy_directory) { File.expand_path("nested/deeper", top_level_tmpdir) } - - after do - FileUtils.remove_entry_secure top_level_tmpdir - end - - before do - File.should_not exist(deploy_directory) - deploy_to_latest_rev.run_action(:deploy) - end - - it "creates the required directory tree" do - File.should be_directory(rel_path("releases")) - File.should be_directory(rel_path("shared")) - File.should be_directory(rel_path("releases/#{latest_rev}")) - - File.should be_directory(rel_path("current/tmp")) - File.should be_directory(rel_path("current/config")) - File.should be_directory(rel_path("current/public")) - - File.should be_symlink(rel_path("current")) - File.readlink(rel_path("current")).should == rel_path("releases/#{latest_rev}") - end - - the_app_is_deployed_at_revision(:latest_rev) - - end - end - - context "when deploying an app with inline recipe callbacks" do - - # Use closures to capture and mutate this variable. This allows us to track - # ordering of operations. - callback_order = [] - - let(:deploy_to_latest_with_inline_recipes) do - deploy_to_latest_rev.dup.tap do |r| - r.symlink_before_migrate "config/config.ru" => "config.ru" - r.before_migrate do - callback_order << :before_migrate - - file "#{release_path}/before_migrate.txt" do - # The content here isn't relevant, but it gets printed when running - # the tests. Could be handy for debugging. - content callback_order.inspect - end - end - r.before_symlink do - callback_order << :before_symlink - - current_release_path = release_path - ruby_block "ensure before symlink" do - block do - if ::File.exist?(::File.join(current_release_path, "/tmp")) - raise "Ordering issue with provider, expected symlinks to not have been created" - end - end - end - - file "#{release_path}/before_symlink.txt" do - content callback_order.inspect - end - end - r.before_restart do - callback_order << :before_restart - - current_release_path = release_path - ruby_block "ensure after symlink" do - block do - unless ::File.exist?(::File.join(current_release_path, "/tmp")) - raise "Ordering issue with provider, expected symlinks to have been created" - end - end - end - - file "#{release_path}/tmp/before_restart.txt" do - content callback_order.inspect - end - end - r.after_restart do - callback_order << :after_restart - file "#{release_path}/tmp/after_restart.txt" do - content callback_order.inspect - end - end - end - end - - before do - callback_order.clear # callback_order variable is global for this context group - deploy_to_latest_with_inline_recipes.run_action(:deploy) - end - - the_app_is_deployed_at_revision(:latest_rev) - - it "is marked updated" do - deploy_to_latest_with_inline_recipes.should be_updated_by_last_action - end - - it "calls the callbacks in order" do - callback_order.should == [:before_migrate, :before_symlink, :before_restart, :after_restart] - end - - it "runs chef resources in the callbacks" do - File.should exist(rel_path("current/before_migrate.txt")) - File.should exist(rel_path("current/before_symlink.txt")) - File.should exist(rel_path("current/tmp/before_restart.txt")) - File.should exist(rel_path("current/tmp/after_restart.txt")) - end - end - - context "when deploying an app with in-repo callback scripts" do - let(:deploy_with_in_repo_callbacks) do - basic_deploy_resource.dup.tap do |r| - r.repo git_bundle_with_in_repo_callbacks - r.revision rev_with_in_repo_callbacks - end - end - - before do - deploy_with_in_repo_callbacks.run_action(:deploy) - end - - the_app_is_deployed_at_revision(:rev_with_in_repo_callbacks) - - it "runs chef resources in the callbacks" do - File.should exist(rel_path("current/before_migrate.txt")) - File.should exist(rel_path("current/before_symlink.txt")) - File.should exist(rel_path("current/tmp/before_restart.txt")) - File.should exist(rel_path("current/tmp/after_restart.txt")) - end - - end - - context "when deploying an app with migrations" do - let(:deploy_with_migration) do - basic_deploy_resource.dup.tap do |r| - - # Need this so we can call methods from this test inside the inline - # recipe callbacks - spec_context = self - - r.revision latest_rev - - # enable migrations - r.migrate true - # abuse `shell_restart_command` so we can observe order of when the - # miration command gets run - r.migration_command shell_restart_command("migration") - r.before_migrate do - - # inline recipe callbacks don't cwd, so you have to get the release - # directory as a local and "capture" it in the closure. - current_release = release_path - execute spec_context.shell_restart_command("before_migrate") do - cwd current_release - end - end - r.before_symlink do - current_release = release_path - execute spec_context.shell_restart_command("before_symlink") do - cwd current_release - end - end - - r.before_restart do - current_release = release_path - execute spec_context.shell_restart_command("before_restart") do - cwd current_release - end - end - - r.after_restart do - current_release = release_path - execute spec_context.shell_restart_command("after_restart") do - cwd current_release - end - end - - end - end - - before do - deploy_with_migration.run_action(:deploy) - end - - it "runs migrations in between the before_migrate and before_symlink steps" do - actual_operations_order.should == %w[before_migrate migration before_symlink before_restart after_restart] - end - end - - context "when deploying an app with in-repo symlinks" do - let(:deploy_with_in_repo_symlinks) do - basic_deploy_resource.dup.tap do |r| - r.repo git_bundle_with_in_repo_symlinks - r.revision rev_with_in_repo_symlinks - end - end - - it "should not raise an exception calling File.utime on symlinks" do - lambda { deploy_with_in_repo_symlinks.run_action(:deploy) }.should_not raise_error - end - end - - context "when a previously deployed application has been nuked" do - - shared_examples_for "a redeployed application" do - - it "should redeploy the application" do - File.should be_directory(rel_path("releases")) - File.should be_directory(rel_path("shared")) - File.should be_directory(rel_path("releases/#{latest_rev}")) - - File.should be_directory(rel_path("current/tmp")) - File.should be_directory(rel_path("current/config")) - File.should be_directory(rel_path("current/public")) - - File.should be_symlink(rel_path("current")) - File.readlink(rel_path("current")).should == rel_path("releases/#{latest_rev}") - end - end - - # background: If a deployment is hosed and the user decides to rm -rf the - # deployment dir, deploy resource should detect that and nullify its cache. - - context "by removing the entire deploy directory" do - - before do - deploy_to_latest_rev.dup.run_action(:deploy) - FileUtils.rm_rf(deploy_directory) - deploy_to_latest_rev.dup.run_action(:deploy) - end - - include_examples "a redeployed application" - - end - - context "by removing the current/ directory" do - - before do - deploy_to_latest_rev.dup.run_action(:deploy) - FileUtils.rm(rel_path("current")) - deploy_to_latest_rev.dup.run_action(:deploy) - end - - include_examples "a redeployed application" - - end - end - - context "when a deployment fails" do - - shared_examples_for "a recovered deployment" do - - it "should redeploy the application" do - File.should be_directory(rel_path("releases")) - File.should be_directory(rel_path("shared")) - File.should be_directory(rel_path("releases/#{latest_rev}")) - - File.should be_directory(rel_path("current/tmp")) - File.should be_directory(rel_path("current/config")) - File.should be_directory(rel_path("current/public")) - - File.should be_symlink(rel_path("current")) - File.readlink(rel_path("current")).should == rel_path("releases/#{latest_rev}") - - # if callbacks ran, we know the app was deployed and not merely rolled - # back to a (busted) prior deployment. - callback_order.should == [:before_migrate, - :before_symlink, - :before_restart, - :after_restart ] - end - end - - let!(:callback_order) { [] } - - let(:deploy_to_latest_with_callback_tracking) do - resource = deploy_to_latest_rev.dup - tracker = callback_order - resource.before_migrate { tracker << :before_migrate } - resource.before_symlink { tracker << :before_symlink } - resource.before_restart { tracker << :before_restart } - resource.after_restart { tracker << :after_restart } - resource - end - - [:before_migrate, :before_symlink, :before_restart, :after_restart].each do |callback| - - context "in the `#{callback}' callback" do - before do - lambda { deploy_that_fails.run_action(:deploy) }.should raise_error(Exception, %r{I am a failed deploy}) - deploy_to_latest_with_callback_tracking.run_action(:deploy) - end - - let(:deploy_that_fails) do - resource = deploy_to_latest_rev.dup - errant_callback = lambda {|x| raise Exception, "I am a failed deploy" } - resource.send(callback, &errant_callback) - resource - end - - include_examples "a recovered deployment" - - end - - end - - context "in the service restart step" do - - let(:deploy_that_fails) do - resource = deploy_to_latest_rev.dup - resource.restart_command("RUBYOPT=\"\" ruby -e 'exit 1'") - resource - end - - before do - lambda { deploy_that_fails.run_action(:deploy) }.should raise_error(Chef::Exceptions::Exec) - deploy_to_latest_with_callback_tracking.run_action(:deploy) - end - - include_examples "a recovered deployment" - end - - context "when cloning the app code" do - - class BadTimeScmProvider - def initialize(new_resource, run_context) - end - - def load_current_resource - end - - def revision_slug - "5" - end - - def run_action(action) - raise RuntimeError, "network error" - end - end - - let(:deploy_that_fails) do - resource = deploy_to_latest_rev.dup - resource.scm_provider(BadTimeScmProvider) - resource - end - - before do - lambda { deploy_that_fails.run_action(:deploy) }.should raise_error(RuntimeError, /network error/) - deploy_to_latest_with_callback_tracking.run_action(:deploy) - end - - include_examples "a recovered deployment" - end - - context "and then is deployed to a different revision" do - - let(:deploy_that_fails) do - resource = deploy_to_previous_rev.dup - resource.after_restart {|x| raise Exception, "I am a failed deploy" } - resource - end - - before do - lambda { deploy_that_fails.run_action(:deploy) }.should raise_error(Exception, %r{I am a failed deploy}) - deploy_to_latest_rev.run_action(:deploy) - end - - it "removes the unsuccessful deploy after a later successful deploy" do - ::File.should_not exist(File.join(deploy_directory, "releases", previous_rev)) - end - - end - - end -end diff --git a/spec/functional/resource/directory_spec.rb b/spec/functional/resource/directory_spec.rb deleted file mode 100644 index 2c4025f83e..0000000000 --- a/spec/functional/resource/directory_spec.rb +++ /dev/null @@ -1,43 +0,0 @@ -# -# Author:: Seth Chisamore (<schisamo@opscode.com>) -# Copyright:: Copyright (c) 2011 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::Directory do - include_context Chef::Resource::Directory - - let(:directory_base) { "directory_spec" } - - let(:default_mode) { ((0100777 - File.umask) & 07777).to_s(8) } - - def create_resource - events = Chef::EventDispatch::Dispatcher.new - node = Chef::Node.new - run_context = Chef::RunContext.new(node, {}, events) - Chef::Resource::Directory.new(path, run_context) - end - - let(:resource) do - create_resource - end - - it_behaves_like "a directory resource" - - it_behaves_like "a securable resource with reporting" - -end diff --git a/spec/functional/resource/dsc_script_spec.rb b/spec/functional/resource/dsc_script_spec.rb deleted file mode 100644 index fa13296c02..0000000000 --- a/spec/functional/resource/dsc_script_spec.rb +++ /dev/null @@ -1,337 +0,0 @@ -# -# Author:: Adam Edwards (<adamed@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 'chef/mixin/shell_out' -require 'chef/mixin/windows_architecture_helper' - -describe Chef::Resource::DscScript, :windows_powershell_dsc_only do - include Chef::Mixin::WindowsArchitectureHelper - before(:all) do - @temp_dir = ::Dir.mktmpdir("dsc-functional-test") - end - - after(:all) do - ::FileUtils.rm_rf(@temp_dir) if ::Dir.exist?(@temp_dir) - end - - include Chef::Mixin::ShellOut - - 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' - script_path = "#{@temp_dir}/dsc_functional_test#{data_suffix}.#{extension}" - ::File.open(script_path, 'wt') do | script | - script.write(script_code) - end - script_path - end - - def user_exists?(target_user) - result = false - begin - shell_out!("net user #{target_user}") - result = true - rescue Mixlib::ShellOut::ShellCommandFailed - end - result - end - - def delete_user(target_user) - begin - shell_out!("net user #{target_user} /delete") - rescue Mixlib::ShellOut::ShellCommandFailed - end - end - - 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' - empty_events = Chef::EventDispatch::Dispatcher.new - Chef::RunContext.new(node, {}, empty_events) - } - 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(:dsc_code) { <<-EOH - Registry "ChefRegKey" - { - Key = '#{test_registry_key}' - ValueName = '#{test_registry_value}' - ValueData = '#{test_registry_data}' - Ensure = 'Present' - } -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(:config_flags) { nil } - let(:config_params) { <<-EOH - - [CmdletBinding()] - param - ( - $#{dsc_user_prefix_param_name}, - $#{dsc_user_suffix_param_name} - ) -EOH - } - - 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 } - let(:dsc_script_environment_attribute) { nil } - let(:dsc_user_resources_code) { <<-EOH - #{config_param_section} -node localhost -{ -$testuser = #{dsc_user_code} -$testpassword = ConvertTo-SecureString -String "jf9a8m49jrajf4#" -AsPlainText -Force -$testcred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $testuser, $testpassword - -User dsctestusercreate -{ - UserName = $testuser - Password = $testcred - Description = "DSC test user" - Ensure = "Present" - Disabled = $false - PasswordNeverExpires = $true - PasswordChangeRequired = $false -} -} -EOH - } - - let(:dsc_user_config_data) { -<<-EOH -@{ - AllNodes = @( - @{ - NodeName = "localhost"; - PSDscAllowPlainTextPassword = $true - } - ) -} - -EOH - } - - 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(:dsc_environment_config) {<<-EOH -if (($pwd.path -eq '#{dsc_environment_fail_etc_directory}') -and (test-path('#{dsc_environment_fail_etc_directory}'))) -{ - throw 'Signature #{exception_message_signature}: Purposefully failing because cwd == #{dsc_environment_fail_etc_directory}' -} -environment "whatsmydir" -{ - Name = '#{dsc_environment_env_var_name}' - Value = $pwd.path - Ensure = 'Present' -} -EOH - } - - let(:dsc_config_name) { - dsc_test_resource_base.name - } - let(:dsc_resource_from_code) { - dsc_test_resource_base.code(dsc_code) - dsc_test_resource_base - } - let(:config_name_value) { dsc_test_resource_base.name } - - let(:dsc_resource_from_path) { - dsc_test_resource_base.command(create_config_script_from_code(dsc_code, config_name_value)) - dsc_test_resource_base - } - - before(:each) do - test_key_resource = Chef::Resource::RegistryKey.new(test_registry_key, dsc_test_run_context) - test_key_resource.recursive(true) - test_key_resource.run_action(:delete_key) - end - - after(:each) do - test_key_resource = Chef::Resource::RegistryKey.new(test_registry_key, dsc_test_run_context) - test_key_resource.recursive(true) - test_key_resource.run_action(:delete_key) - end - - 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 - 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) - end - - 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 - after(:each) do - removal_resource = Chef::Resource::DscScript.new(dsc_test_resource_name, dsc_test_run_context) - removal_resource.code <<-EOH -environment 'removethis' -{ - Name = '#{dsc_environment_env_var_name}' - Ensure = 'Absent' -} -EOH - removal_resource.run_action(:run) - end - let(:dsc_code) { dsc_environment_config } - 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 - end - - 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) - begin - dsc_test_resource.run_action(:run) - rescue Chef::Exceptions::PowershellCmdletException => e - expect(e.message).to match(exception_message_signature) - end - end - end - - shared_examples_for 'a parameterized DSC configuration script' do - context 'when specifying environment variables in the environment attribute' 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' - end - end - - shared_examples_for 'a dsc_script with configuration data' do - context 'when using the configuration_data attribute' do - let(:configuration_data_attribute) { 'configuration_data' } - it_behaves_like 'a dsc_script with configuration data set via an attribute' - end - - context 'when using the configuration_data_script attribute' do - let(:configuration_data_attribute) { 'configuration_data_script' } - it_behaves_like 'a dsc_script with configuration data set via an attribute' - end - 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 - 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) - 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.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(user_exists?(dsc_user)).to eq(true) - end - end - - shared_examples_for 'a dsc_script with configuration data that takes parameters' do - context 'when script code takes parameters for configuration' 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 | - file.read - end - expect(configuration_script_content.include?(dsc_user)).to be(false) - end - it_behaves_like 'a dsc_script with configuration data' - end - - end - - shared_examples_for 'a dsc_script with configuration data that uses environment variables' do - context 'when script code 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 | - file.read - end - expect(configuration_script_content.include?(dsc_user)).to be(false) - end - it_behaves_like 'a dsc_script with configuration data' - end - end - - 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' - end - - 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' - end - - 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(: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' - end -end diff --git a/spec/functional/resource/file_spec.rb b/spec/functional/resource/file_spec.rb deleted file mode 100644 index 99966f85c8..0000000000 --- a/spec/functional/resource/file_spec.rb +++ /dev/null @@ -1,141 +0,0 @@ -# -# Author:: Seth Chisamore (<schisamo@opscode.com>) -# Copyright:: Copyright (c) 2011 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::File do - include_context Chef::Resource::File - - let(:file_base) { "file_spec" } - let(:expected_content) { "Don't fear the ruby." } - - 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] - File.basename(path) - else - path - end - - Chef::Resource::File.new(use_path, run_context) - end - - let(:resource) do - r = create_resource - r.content(expected_content) - r - end - - let(:resource_without_content) do - create_resource - end - - let(:resource_with_relative_path) do - create_resource(:use_relative_path => true) - end - - let(:unmanaged_content) do - "This is file content that is not managed by chef" - end - - let(:current_resource) do - provider = resource.provider_for_action(resource.action) - provider.load_current_resource - provider.current_resource - end - - let(:default_mode) { ((0100666 - File.umask) & 07777).to_s(8) } - - it_behaves_like "a file resource" - - it_behaves_like "a securable resource with reporting" - - describe "when running action :create without content" do - before do - resource_without_content.run_action(:create) - end - - context "and the target file does not exist" do - it "creates the file" do - File.should exist(path) - end - - it "is marked updated by last action" do - resource_without_content.should be_updated_by_last_action - end - end - end - - # github issue 1842. - describe "when running action :create on a relative path" do - before do - resource_with_relative_path.run_action(:create) - end - - context "and the file exists" do - it "should run without an exception" do - resource_with_relative_path.run_action(:create) - end - end - end - - describe "when running action :touch" do - context "and the target file does not exist" do - before do - resource.run_action(:touch) - end - - it "it creates the file" do - File.should exist(path) - end - - it "is marked updated by last action" do - resource.should be_updated_by_last_action - end - end - - context "and the target file exists and has the correct content" do - before(:each) do - File.open(path, "w") { |f| f.print expected_content } - - @expected_checksum = sha256_checksum(path) - - now = Time.now.to_i - File.utime(now - 9000, now - 9000, path) - @expected_mtime = File.stat(path).mtime - - resource.run_action(:touch) - end - - it "updates the mtime of the file" do - File.stat(path).mtime.should > @expected_mtime - end - - it "does not change the content" do - sha256_checksum(path).should == @expected_checksum - end - - it "is marked as updated by last action" do - resource.should be_updated_by_last_action - end - end - end -end diff --git a/spec/functional/resource/git_spec.rb b/spec/functional/resource/git_spec.rb deleted file mode 100644 index f0bd94b0c0..0000000000 --- a/spec/functional/resource/git_spec.rb +++ /dev/null @@ -1,259 +0,0 @@ -# -# Author:: Seth Falcon (<seth@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' -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 - include Chef::Mixin::ShellOut - let(:file_cache_path) { Dir.mktmpdir } - # Some versions of git complains when the deploy directory is - # already created. Here we intentionally don't create the deploy - # directory beforehand. - let(:base_dir_path) { Dir.mktmpdir } - let(:deploy_directory) { File.join(base_dir_path, make_tmpname("git_base")) } - - let(:node) do - Chef::Node.new.tap do |n| - n.name "rspec-test" - n.consume_external_attrs(@ohai.data, {}) - end - end - - let(:event_dispatch) { Chef::EventDispatch::Dispatcher.new } - let(:run_context) { Chef::RunContext.new(node, {}, event_dispatch) } - - # These tests use git's bundle feature, which is a way to export an entire - # git repo (or subset of commits) as a single file. - # - # Generally you can treat a git bundle as a regular git remote. - # - # See also: http://git-scm.com/2010/03/10/bundles.html - # - # Beware that git bundles don't behave exactly the same as real - # remotes. To get closer to real remotes, we'll create a local clone - # of the bundle to use as a remote for the tests. This at least - # gives the expected responses for ls-remote using git version - # 1.7.12.4 - let(:git_bundle_repo) { File.expand_path("git_bundles/example-repo.gitbundle", CHEF_SPEC_DATA) } - let(:origin_repo_dir) { Dir.mktmpdir } - let(:origin_repo) { "#{origin_repo_dir}/example" } - - # This is the fourth version - let(:v1_commit) { "bc5ec79931ae74089aeadca6edc173527613e6d9" } - let(:v1_tag) { "9b73fb5e316bfaff7b822b0ccb3e1e08f9885085" } - let(:rev_foo) { "ed181b3419b6f489bedab282348162a110d6d3a1" } - let(:rev_testing) { "972d153654503bccec29f630c5dd369854a561e8" } - let(:rev_head) { "d294fbfd05aa7709ad9a9b8ef6343b17d355bf5f"} - - let(:git_user_config) do - <<-E -[user] - name = frodoTbaggins - email = frodo@shire.org -E - end - - before(:each) do - 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) } - Chef::Config[:file_cache_path] = file_cache_path - end - - after(:each) do - Chef::Config[:file_cache_path] = @old_file_cache_path - FileUtils.remove_entry_secure deploy_directory if File.exist?(deploy_directory) - FileUtils.remove_entry_secure file_cache_path - end - - after(:all) do - FileUtils.remove_entry_secure origin_repo_dir - end - - before(:all) do - @ohai = Ohai::System.new - @ohai.all_plugins("os") - end - - context "working with pathes with special characters" do - let(:path_with_spaces) { "#{origin_repo_dir}/path with spaces" } - - before(:each) do - FileUtils.mkdir(path_with_spaces) - FileUtils.cp(git_bundle_repo, path_with_spaces) - end - - it "clones a repository with a space in the path" do - Chef::Resource::Git.new(deploy_directory, run_context).tap do |r| - r.repository "#{path_with_spaces}/example-repo.gitbundle" - end.run_action(:sync) - end - end - - context "when deploying from an annotated tag" do - let(:basic_git_resource) do - Chef::Resource::Git.new(deploy_directory, run_context).tap do |r| - r.repository origin_repo - r.revision "v1.0.0" - end - end - - # We create a copy of the basic_git_resource so that we can run - # the resource again and verify that it doesn't update. - let(:copy_git_resource) do - Chef::Resource::Git.new(deploy_directory, run_context).tap do |r| - r.repository origin_repo - r.revision "v1.0.0" - end - end - - 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.should == 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.should == v1_tag - end - - it "doesn't update if up-to-date" do - # 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.should == v1_commit - - copy_git_resource.run_action(:sync) - copy_git_resource.should_not be_updated - end - end - - context "when deploying from a SHA revision" do - let(:basic_git_resource) do - Chef::Resource::Git.new(deploy_directory, run_context).tap do |r| - r.repository git_bundle_repo - end - end - - # We create a copy of the basic_git_resource so that we can run - # the resource again and verify that it doesn't update. - let(:copy_git_resource) do - Chef::Resource::Git.new(deploy_directory, run_context).tap do |r| - r.repository origin_repo - end - end - - 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.should == 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.should == rev_foo - - copy_git_resource.revision rev_foo - copy_git_resource.run_action(:sync) - copy_git_resource.should_not be_updated - end - - 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.should == rev_testing - end - end - - context "when deploying from a revision named 'HEAD'" do - let(:basic_git_resource) do - Chef::Resource::Git.new(deploy_directory, run_context).tap do |r| - r.repository origin_repo - 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.should == rev_head - end - end - - context "when deploying from the default revision" do - let(:basic_git_resource) do - Chef::Resource::Git.new(deploy_directory, run_context).tap do |r| - r.repository origin_repo - # use default - end - end - - 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.should == rev_head - end - end - - context "when dealing with a repo with a degenerate tag named 'HEAD'" do - before do - shell_out!("git tag -m\"degenerate tag\" HEAD ed181b3419b6f489bedab282348162a110d6d3a1", - :cwd => origin_repo) - end - - let(:basic_git_resource) do - Chef::Resource::Git.new(deploy_directory, run_context).tap do |r| - r.repository origin_repo - r.revision 'HEAD' - end - end - - let(:git_resource_default_rev) do - Chef::Resource::Git.new(deploy_directory, run_context).tap do |r| - r.repository origin_repo - # use default of revision - end - end - - 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', - :cwd => deploy_directory, - :returns => [0]).stdout.strip - head_rev.should == rev_head - end - - 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', - :cwd => deploy_directory, - :returns => [0]).stdout.strip - head_rev.should == rev_head - end - - end -end diff --git a/spec/functional/resource/group_spec.rb b/spec/functional/resource/group_spec.rb deleted file mode 100644 index 9c14232071..0000000000 --- a/spec/functional/resource/group_spec.rb +++ /dev/null @@ -1,430 +0,0 @@ -# -# Author:: Chirag Jog (<chirag@clogeny.com>) -# Author:: Siddheshwar More (<siddheshwar.more@clogeny.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' -require 'functional/resource/base' - -# 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 -# changes that are done on the system. Etc.endgrent is not functioning -# correctly on certain 10.6 boxes. -describe Chef::Resource::Group, :requires_root_or_running_windows, :not_supported_on_mac_osx_106 do - def group_should_exist(group) - case ohai[:platform_family] - when "debian", "fedora", "rhel", "suse", "gentoo", "slackware", "arch" - expect { Etc::getgrnam(group) }.not_to raise_error - expect(group).to eq(Etc::getgrnam(group).name) - when "windows" - expect { Chef::Util::Windows::NetGroup.new(group).local_get_members }.not_to raise_error - end - end - - def user_exist_in_group?(user) - case ohai[:platform_family] - when "windows" - user_sid = sid_string_from_user(user) - user_sid.nil? ? false : Chef::Util::Windows::NetGroup.new(group_name).local_get_members.include?(user_sid) - when "mac_os_x" - membership_info = shell_out("dscl . -read /Groups/#{group_name}").stdout - members = membership_info.split(" ") - members.shift # Get rid of GroupMembership: string - members.include?(user) - else - Etc::getgrnam(group_name).mem.include?(user) - end - end - - def group_should_not_exist(group) - case ohai[:platform_family] - 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.") - end - end - - def compare_gid(resource, gid) - return resource.gid == Etc::getgrnam(resource.name).gid if unix? - end - - def sid_string_from_user(user) - begin - sid = Chef::ReservedNames::Win32::Security.lookup_account_name(user) - rescue Chef::Exceptions::Win32APIError - sid = nil - end - - sid.nil? ? nil : sid[1].to_s - end - - def windows_domain_user?(user_name) - domain, user = user_name.split('\\') - - if user && domain != '.' - computer_name = ENV['computername'] - domain.downcase != computer_name.downcase - end - end - - def user(username) - usr = Chef::Resource::User.new("#{username}", run_context) - if ohai[:platform_family] == "windows" - usr.password("ComplexPass11!") - end - usr - end - - def create_user(username) - user(username).run_action(:create) if ! windows_domain_user?(username) - # TODO: User shouldn't exist - end - - def remove_user(username) - user(username).run_action(:remove) if ! windows_domain_user?(username) - # TODO: User shouldn't exist - end - - shared_examples_for "correct group management" do - def add_members_to_group(members) - temp_resource = group_resource.dup - temp_resource.members(members) - temp_resource.excluded_members([ ]) - temp_resource.append(true) - temp_resource.run_action(:modify) - members.each do |member| - user_exist_in_group?(member).should == true - end - end - - def create_group - temp_resource = group_resource.dup - temp_resource.members([ ]) - temp_resource.excluded_members([ ]) - temp_resource.run_action(:create) - group_should_exist(group_name) - included_members.each do |member| - user_exist_in_group?(member).should == false - end - end - - before(:each) do - create_group - end - - after(:each) do - group_resource.run_action(:remove) - group_should_not_exist(group_name) - end - - describe "when append is not set" do - let(:included_members) { [spec_members[1]] } - - 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]) - end - - it "should remove the existing users and add the new users to the group" do - group_resource.run_action(tested_action) - - user_exist_in_group?(spec_members[1]).should == true - user_exist_in_group?(spec_members[0]).should == false - end - end - - describe "when append is set" do - before(:each) do - group_resource.append(true) - end - - describe "when the users exist" do - before do - (included_members + excluded_members).each do |member| - create_user(member) - end - end - - after do - (included_members + excluded_members).each do |member| - remove_user(member) - end - end - - it "should add included members to the group" do - group_resource.run_action(tested_action) - - included_members.each do |member| - user_exist_in_group?(member).should == true - end - excluded_members.each do |member| - user_exist_in_group?(member).should == false - end - end - - describe "when group contains some users" do - before(:each) do - add_members_to_group([ spec_members[0], spec_members[2] ]) - end - - it "should add the included users and remove excluded users" do - group_resource.run_action(tested_action) - - included_members.each do |member| - user_exist_in_group?(member).should == true - end - excluded_members.each do |member| - user_exist_in_group?(member).should == false - end - end - end - end - - describe "when the users doesn't exist" do - describe "when append is not set" do - it "should raise an error" do - lambda { @grp_resource.run_action(tested_action) }.should raise_error - end - end - - describe "when append is set" do - it "should raise an error" do - lambda { @grp_resource.run_action(tested_action) }.should raise_error - end - end - end - end - end - - shared_examples_for "an expected invalid domain error case" do - let(:invalid_domain_user_name) { "no space\\administrator" } - let(:nonexistent_domain_user_name) { "xxfakedom\\administrator" } - before(:each) do - group_resource.members [] - group_resource.excluded_members [] - group_resource.append(true) - group_resource.run_action(:create) - group_should_exist(group_name) - end - - describe "when updating membership" do - it "raises an error for a non well-formed domain name" do - group_resource.members [invalid_domain_user_name] - lambda { group_resource.run_action(tested_action) }.should raise_error Chef::Exceptions::Win32APIError - end - - it "raises an error for a nonexistent domain" do - group_resource.members [nonexistent_domain_user_name] - lambda { group_resource.run_action(tested_action) }.should raise_error Chef::Exceptions::Win32APIError - end - end - - describe "when removing members" do - it "raises an error for a non well-formed domain name" do - group_resource.excluded_members [invalid_domain_user_name] - lambda { group_resource.run_action(tested_action) }.should raise_error Chef::Exceptions::Win32APIError - end - - it "raises an error for a nonexistent domain" do - group_resource.excluded_members [nonexistent_domain_user_name] - lambda { group_resource.run_action(tested_action) }.should raise_error Chef::Exceptions::Win32APIError - end - end - end - - let(:group_name) { "t-#{SecureRandom.random_number(9999)}" } - let(:included_members) { nil } - let(:excluded_members) { nil } - let(:group_resource) { - group = Chef::Resource::Group.new(group_name, run_context) - group.members(included_members) - group.excluded_members(excluded_members) - group - } - - it "append should be false by default" do - group_resource.append.should == false - end - - describe "group create action" do - after(:each) do - group_resource.run_action(:remove) - group_should_not_exist(group_name) - end - - it "should create a group" do - group_resource.run_action(:create) - group_should_exist(group_name) - end - - describe "when group name is length 256", :windows_only do - let!(:group_name) { "theoldmanwalkingdownthestreetalwayshadagood\ -smileonhisfacetheoldmanwalkingdownthestreetalwayshadagoodsmileonhisface\ -theoldmanwalkingdownthestreetalwayshadagoodsmileonhisfacetheoldmanwalking\ -downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestree" } - - it "should create a group" do - group_resource.run_action(:create) - group_should_exist(group_name) - end - end - - describe "when group name length is more than 256", :windows_only do - let!(:group_name) { "theoldmanwalkingdownthestreetalwayshadagood\ -smileonhisfacetheoldmanwalkingdownthestreetalwayshadagoodsmileonhisface\ -theoldmanwalkingdownthestreetalwayshadagoodsmileonhisfacetheoldmanwalking\ -downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" } - - it "should not create a group" do - lambda { group_resource.run_action(:create) }.should raise_error - group_should_not_exist(group_name) - end - end - - # not_supported_on_solaris because of the use of excluded_members - describe "should raise an error when same member is included in the members and excluded_members", :not_supported_on_solaris do - it "should raise an error" do - invalid_resource = group_resource.dup - invalid_resource.members(["Jack"]) - invalid_resource.excluded_members(["Jack"]) - lambda { invalid_resource.run_action(:create)}.should raise_error(Chef::Exceptions::ConflictingMembersInGroup) - end - end - end - - describe "group remove action" do - describe "when there is a group" do - before do - group_resource.run_action(:create) - group_should_exist(group_name) - end - - it "should remove a group" do - group_resource.run_action(:remove) - group_should_not_exist(group_name) - end - end - - describe "when there is no group" do - it "should be no-op" do - group_resource.run_action(:remove) - group_should_not_exist(group_name) - end - end - end - - describe "group modify action", :not_supported_on_solaris do - let(:spec_members){ ["Gordon", "Eric", "Anthony"] } - let(:included_members) { [spec_members[0], spec_members[1]] } - let(:excluded_members) { [spec_members[2]] } - let(:tested_action) { :modify } - - describe "when there is no group" do - it "should raise an error" do - lambda { group_resource.run_action(:modify) }.should raise_error - end - end - - describe "when there is a group" do - it_behaves_like "correct group management" - end - - 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"] } - - include_examples "correct group management" - end - - it_behaves_like "an expected invalid domain error case" - end - end - - describe "group manage action", :not_supported_on_solaris do - let(:spec_members){ ["Gordon", "Eric", "Anthony"] } - 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 - it "raises an error on modify" do - lambda { group_resource.run_action(:modify) }.should raise_error - end - - it "does not raise an error on manage" do - lambda { group_resource.run_action(:manage) }.should_not raise_error - end - end - - describe "when there is a group" do - it_behaves_like "correct group management" - end - - 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"] } - - include_examples "correct group management" - end - - it_behaves_like "an expected invalid domain error case" - end - end - - describe "group resource with Usermod provider", :solaris_only do - describe "when excluded_members is set" do - let(:excluded_members) { ["Anthony"] } - - it ":manage should raise an error" do - lambda {group_resource.run_action(:manage) }.should raise_error - end - - it ":modify should raise an error" do - lambda {group_resource.run_action(:modify) }.should raise_error - end - - it ":create should raise an error" do - lambda {group_resource.run_action(:create) }.should raise_error - end - end - - describe "when append is not set" do - let(:included_members) { ["Gordon", "Eric"] } - - before(:each) do - group_resource.append(false) - end - - it ":manage should raise an error" do - lambda {group_resource.run_action(:manage) }.should raise_error - end - - it ":modify should raise an error" do - lambda {group_resource.run_action(:modify) }.should raise_error - end - end - end -end diff --git a/spec/functional/resource/ifconfig_spec.rb b/spec/functional/resource/ifconfig_spec.rb deleted file mode 100644 index c36288498b..0000000000 --- a/spec/functional/resource/ifconfig_spec.rb +++ /dev/null @@ -1,163 +0,0 @@ -# -# Author:: Kaustubh Deorukhkar (<kaustubh@clogeny.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 'functional/resource/base' -require 'chef/mixin/shell_out' - -# run this test only for following platforms. -include_flag = !(['ubuntu', 'centos', 'aix'].include?(ohai[:platform])) - -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 - end - - let(:provider) do - provider = new_resource.provider_for_action(new_resource.action) - provider - end - - let(:current_resource) do - provider.load_current_resource - end - - def lo_interface_for_test - # use loopback interface for tests - case ohai[:platform] - when "aix" - 'lo0' - else - 'lo' - end - end - - # **Caution: any updates to core interfaces can be risky. - def en0_interface_for_test - case ohai[:platform] - when "aix" - 'en0' - else - 'eth0' - end - end - - def network_interface_alias(interface) - case ohai[:platform] - when "aix" - interface - else - interface + ":10" - end - end - - # platform specific test setup and validation routines - - def setup_add_interface(resource) - resource.device network_interface_alias(en0_interface_for_test) - end - - def setup_enable_interface(resource) - resource.device network_interface_alias(en0_interface_for_test) - end - - def interface_should_exists(interface) - expect(shell_out("ifconfig #{@interface} | grep 10.10.0.1").exitstatus).to eq(0) - end - - def interface_should_not_exists(interface) - expect(shell_out("ifconfig #{@interface} | grep 10.10.0.1").exitstatus).to eq(1) - end - - def interface_persistence_should_exists(interface) - case ohai[:platform] - when "aix" - expect(shell_out("lsattr -E -l #{@interface} | grep 10.10.0.1").exitstatus).to eq(0) - else - end - end - - def interface_persistence_should_not_exists(interface) - case ohai[:platform] - when "aix" - expect(shell_out("lsattr -E -l #{@interface} | grep 10.10.0.1").exitstatus).to eq(1) - else - end - end - - # Actual tests - - describe "#load_current_resource" 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' - describe "#action_add", :external => exclude_test do - after do - new_resource.run_action(:delete) - end - it "should add interface (vip)" do - setup_add_interface(new_resource) - new_resource.run_action(:add) - interface_should_exists(network_interface_alias(en0_interface_for_test)) - interface_persistence_should_exists(network_interface_alias(en0_interface_for_test)) - end - end - - describe "#action_enable", :external => exclude_test do - after do - new_resource.run_action(:disable) - end - it "should enable interface (vip)" do - setup_enable_interface(new_resource) - new_resource.run_action(:enable) - interface_should_exists(network_interface_alias(en0_interface_for_test)) - end - end - - describe "#action_disable", :external => exclude_test do - before do - setup_enable_interface(new_resource) - new_resource.run_action(:enable) - end - it "should disable interface (vip)" do - new_resource.run_action(:disable) - new_resource.should be_updated_by_last_action - interface_should_not_exists(network_interface_alias(en0_interface_for_test)) - end - end - - describe "#action_delete", :external => exclude_test do - before do - setup_add_interface(new_resource) - new_resource.run_action(:add) - end - it "should delete interface (vip)" do - new_resource.run_action(:delete) - new_resource.should be_updated_by_last_action - interface_should_not_exists(network_interface_alias(en0_interface_for_test)) - interface_persistence_should_not_exists(network_interface_alias(en0_interface_for_test)) - end - end -end diff --git a/spec/functional/resource/link_spec.rb b/spec/functional/resource/link_spec.rb deleted file mode 100644 index 2220e973cf..0000000000 --- a/spec/functional/resource/link_spec.rb +++ /dev/null @@ -1,616 +0,0 @@ -# -# Author:: John Keiser (<jkeiser@opscode.com>) -# Copyright:: Copyright (c) 2011 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' - -if windows? - 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} - - # 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") - else - File.join(CHEF_SPEC_DATA, "test-dir") - end - end - - before do - FileUtils::mkdir_p(test_file_dir) - end - - after do - FileUtils::rm_rf(test_file_dir) - end - - let(:to) do - File.join(test_file_dir, make_tmpname("to_spec")) - end - let(:target_file) do - File.join(test_file_dir, make_tmpname("from_spec")) - end - - after(:each) do - begin - cleanup_link(to) if File.exists?(to) - cleanup_link(target_file) if File.exists?(target_file) - cleanup_link(CHEF_SPEC_BACKUP_PATH) if File.exists?(CHEF_SPEC_BACKUP_PATH) - rescue - puts "Could not remove a file: #{$!}" - end - end - - def cleanup_link(path) - if windows? && File.directory?(path) - # If the link target is a directory rm_rf doesn't work all the - # time on windows. - system "rmdir '#{path}'" - else - FileUtils.rm_rf(path) - end - end - - def paths_eql?(path1, path2) - Chef::Util::PathHelper.paths_eql?(path1, path2) - end - - def symlink(a, b) - if windows? - Chef::ReservedNames::Win32::File.symlink(a, b) - else - File.symlink(a, b) - end - end - def symlink?(file) - if windows? - Chef::ReservedNames::Win32::File.symlink?(file) - else - File.symlink?(file) - end - end - def readlink(file) - if windows? - Chef::ReservedNames::Win32::File.readlink(file) - else - File.readlink(file) - end - end - def link(a, b) - if windows? - Chef::ReservedNames::Win32::File.link(a, b) - else - File.link(a, b) - end - end - - def create_resource - node = Chef::Node.new - events = Chef::EventDispatch::Dispatcher.new - cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks")) - cookbook_collection = Chef::CookbookCollection.new(Chef::CookbookLoader.new(cookbook_repo)) - run_context = Chef::RunContext.new(node, cookbook_collection, events) - resource = Chef::Resource::Link.new(target_file, run_context) - resource.to(to) - resource - end - - let(:resource) do - create_resource - end - - describe "when supported on platform", :not_supported_on_win2k3 do - shared_examples_for 'delete errors out' do - it 'delete errors out' do - lambda { resource.run_action(:delete) }.should raise_error(Chef::Exceptions::Link) - (File.exist?(target_file) || symlink?(target_file)).should be_true - end - end - - shared_context 'delete is noop' do - describe 'the :delete action' do - before(:each) do - @info = [] - Chef::Log.stub(:info) { |msg| @info << msg } - resource.run_action(:delete) - end - - it 'leaves the file deleted' do - File.exist?(target_file).should be_false - symlink?(target_file).should be_false - end - it 'does not mark the resource updated' do - resource.should_not be_updated - end - it 'does not log that it deleted' do - @info.include?("link[#{target_file}] deleted").should be_false - end - end - end - - shared_context 'delete succeeds' do - describe 'the :delete action' do - before(:each) do - @info = [] - Chef::Log.stub(:info) { |msg| @info << msg } - resource.run_action(:delete) - end - - it 'deletes the file' do - File.exist?(target_file).should be_false - symlink?(target_file).should be_false - end - it 'marks the resource updated' do - resource.should be_updated - end - it 'logs that it deleted' do - @info.include?("link[#{target_file}] deleted").should be_true - end - end - end - - shared_context 'create symbolic link succeeds' do - describe 'the :create action' do - before(:each) do - @info = [] - Chef::Log.stub(:info) { |msg| @info << msg } - resource.run_action(:create) - end - - it 'links to the target file' do - symlink?(target_file).should be_true - paths_eql?(readlink(target_file), to).should be_true - end - it 'marks the resource updated' do - resource.should be_updated - end - it 'logs that it created' do - @info.include?("link[#{target_file}] created").should be_true - end - end - end - - shared_context 'create symbolic link is noop' do - describe 'the :create action' do - before(:each) do - @info = [] - Chef::Log.stub(:info) { |msg| @info << msg } - resource.run_action(:create) - end - - it 'leaves the file linked' do - symlink?(target_file).should be_true - paths_eql?(readlink(target_file), to).should be_true - end - it 'does not mark the resource updated' do - resource.should_not be_updated - end - it 'does not log that it created' do - @info.include?("link[#{target_file}] created").should be_false - end - end - end - - shared_context 'create hard link succeeds' do - describe 'the :create action' do - before(:each) do - @info = [] - Chef::Log.stub(:info) { |msg| @info << msg } - resource.run_action(:create) - end - it 'preserves the hard link' do - File.exists?(target_file).should be_true - symlink?(target_file).should be_false - # Writing to one hardlinked file should cause both - # to have the new value. - IO.read(to).should == IO.read(target_file) - File.open(to, "w") { |file| file.write('wowzers') } - IO.read(target_file).should == 'wowzers' - end - it 'marks the resource updated' do - resource.should be_updated - end - it 'logs that it created' do - @info.include?("link[#{target_file}] created").should be_true - end - end - end - - shared_context 'create hard link is noop' do - describe 'the :create action' do - before(:each) do - @info = [] - Chef::Log.stub(:info) { |msg| @info << msg } - resource.run_action(:create) - end - it 'links to the target file' do - File.exists?(target_file).should be_true - symlink?(target_file).should be_false - # Writing to one hardlinked file should cause both - # to have the new value. - IO.read(to).should == IO.read(target_file) - File.open(to, "w") { |file| file.write('wowzers') } - IO.read(target_file).should == 'wowzers' - end - it 'does not mark the resource updated' do - resource.should_not be_updated - end - it 'does not log that it created' do - @info.include?("link[#{target_file}] created").should be_false - end - end - end - - context "is symbolic" do - - context 'when the link destination is a file' do - before(:each) do - File.open(to, "w") do |file| - 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' - end - 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) - symlink?(target_file).should be_true - paths_eql?(readlink(target_file), to).should be_true - end - 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) - File.exists?(to).should be_true - end - end - 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') } - symlink(@other_target, target_file) - symlink?(target_file).should be_true - paths_eql?(readlink(target_file), @other_target).should be_true - end - 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 - resource.run_action(:delete) - File.exists?(to).should be_true - end - end - context 'pointing nowhere' do - before(:each) do - nonexistent = File.join(test_file_dir, make_tmpname('nonexistent_spec')) - symlink(nonexistent, target_file) - symlink?(target_file).should be_true - paths_eql?(readlink(target_file), nonexistent).should be_true - end - 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 - before(:each) do - link(to, target_file) - File.exists?(target_file).should be_true - symlink?(target_file).should be_false - end - include_context 'create symbolic link succeeds' - it_behaves_like 'delete errors out' - end - context 'and the link already exists and is a file' do - before(:each) do - File.open(target_file, 'w') { |file| file.write('eek') } - end - include_context 'create symbolic 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 'create errors out' do - if windows? - lambda { resource.run_action(:create) }.should raise_error(Errno::EACCES) - elsif os_x? or solaris? or freebsd? or aix? - lambda { resource.run_action(:create) }.should raise_error(Errno::EPERM) - else - lambda { resource.run_action(:create) }.should 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', :pending do - end - 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) - 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 - 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' - end - 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' - end - end - context "when the link destination is a symbolic link" 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") } - symlink(@other_target, to) - symlink?(to).should be_true - paths_eql?(readlink(to), @other_target).should be_true - end - 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' - end - end - 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) - symlink?(to).should be_true - paths_eql?(readlink(to), @other_target).should be_true - end - 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", :pending do - end - context "when the link destination does not exist" do - 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' - }.each do |prefix, desc| - context desc do - let(:to) { "#{prefix}#{File.basename(absolute_to)}" } - let(:absolute_to) { File.join(test_file_dir, make_tmpname("to_spec")) } - 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' - end - context 'when the link already exists and points at the target' do - before(:each) do - symlink(to, target_file) - symlink?(target_file).should be_true - paths_eql?(readlink(target_file), to).should be_true - end - 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 - before(:each) do - symlink(absolute_to, target_file) - symlink?(target_file).should be_true - paths_eql?(readlink(target_file), absolute_to).should be_true - end - include_context 'create symbolic link succeeds' - include_context 'delete succeeds' - end - end - end - end - - context "is a hard link" do - before(:each) do - resource.link_type(:hard) - end - - context "when the link destination is a file" do - before(:each) do - File.open(to, "w") do |file| - 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' - end - context "and the link already exists and is a symbolic link pointing at the same file" do - before(:each) do - symlink(to, target_file) - symlink?(target_file).should be_true - paths_eql?(readlink(target_file), to).should be_true - end - 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 - before(:each) do - link(to, target_file) - File.exists?(target_file).should be_true - symlink?(target_file).should be_false - end - 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) - File.exists?(to).should be_true - 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') } - end - 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 - if windows? - lambda { resource.run_action(:create) }.should raise_error(Errno::EACCES) - elsif os_x? or solaris? or freebsd? or aix? - lambda { resource.run_action(:create) }.should raise_error(Errno::EPERM) - else - lambda { resource.run_action(:create) }.should 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", :pending do - end - context "and specifies security attributes" do - before(:each) do - resource.owner(windows? ? 'Guest' : 'nobody') - end - it 'ignores them' do - resource.run_action(:create) - if windows? - Chef::ReservedNames::Win32::Security.get_named_security_info(target_file).owner.should_not == SID.Guest - else - File.lstat(target_file).uid.should_not == Etc.getpwnam('nobody').uid - end - end - end - end - context "when the link destination is a directory" do - before(:each) do - Dir.mkdir(to) - end - context 'and the link does not yet exist' do - it 'create errors out' do - lambda { resource.run_action(:create) }.should raise_error(windows? ? Chef::Exceptions::Win32APIError : Errno::EPERM) - end - include_context 'delete is noop' - end - end - context "when the link destination is a symbolic link" 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") } - symlink(@other_target, to) - symlink?(to).should be_true - paths_eql?(readlink(to), @other_target).should be_true - end - after(:each) do - File.delete(@other_target) - end - context 'and the link does not yet exist' do - it 'links to the target file' do - resource.run_action(:create) - File.exists?(target_file).should be_true - # 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?)) do - symlink?(target_file).should be_true - paths_eql?(readlink(target_file), @other_target).should be_true - end - end - include_context 'delete is noop' - end - end - context 'to a nonexistent file' do - before(:each) do - @other_target = File.join(test_file_dir, make_tmpname("other_spec")) - symlink(@other_target, to) - symlink?(to).should be_true - paths_eql?(readlink(to), @other_target).should be_true - 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?)) do - resource.run_action(:create) - # Windows and Unix have different definitions of exists? here, and that's OK. - if windows? - File.exists?(target_file).should be_true - else - File.exists?(target_file).should be_false - end - symlink?(target_file).should be_true - paths_eql?(readlink(target_file), @other_target).should be_true - end - end - include_context 'delete is noop' - end - end - end - context "when the link destination is not readable to this user", :pending 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 - lambda { resource.run_action(:create) }.should raise_error(Errno::ENOENT) - end - include_context 'delete is noop' - end - end - end - end - - describe "when not supported on platform", :win2k3_only do - it "raises error" do - lambda {resource}.should raise_error(Chef::Exceptions::Win32APIFunctionNotImplemented) - end - end -end diff --git a/spec/functional/resource/mount_spec.rb b/spec/functional/resource/mount_spec.rb deleted file mode 100644 index 962c02670c..0000000000 --- a/spec/functional/resource/mount_spec.rb +++ /dev/null @@ -1,212 +0,0 @@ -# -# Author:: Kaustubh Deorukhkar (<kaustubh@clogeny.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 '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])) - -describe Chef::Resource::Mount, :requires_root, :external => include_flag do - - include Chef::Mixin::ShellOut - - # Platform specific setup, cleanup and validation helpers. - - def setup_device_for_mount - # use ramdisk for creating a test device for mount. - # 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}") - when "ubuntu", "centos" - device = "/dev/ram1" - shell_out("ls -1 /dev/ram*").stdout.each_line do |d| - if shell_out("mount | grep #{d}").exitstatus == "1" - # this device is not mounted, so use it. - device = d - break - end - end - fstype = "tmpfs" - shell_out!("mkfs -q #{device} 512") - when "solaris2" - device = "swap" - fstype = "tmpfs" - else - end - [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 - - # platform specific validations. - def mount_should_exist(mount_point, device, fstype = nil, options = nil) - validation_cmd = "mount | grep #{mount_point} | grep #{device} " - validation_cmd << " | grep #{fstype} " unless fstype.nil? - validation_cmd << " | grep #{options.join(',')} " unless options.nil? || options.empty? - expect(shell_out(validation_cmd).exitstatus).to eq(0) - end - - def mount_should_not_exists(mount_point) - shell_out("mount").stdout.should_not include(mount_point) - end - - def unix_mount_config_file - case ohai[:platform] - when 'aix' - mount_config = "/etc/filesystems" - when 'solaris2' - mount_config = "/etc/vfstab" - else - mount_config = "/etc/fstab" - end - end - - def mount_should_be_enabled(mount_point, device) - case ohai[:platform] - 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) - end - end - - def mount_should_be_disabled(mount_point) - shell_out("cat #{unix_mount_config_file}").stdout.should_not include("#{mount_point}:") - end - - let(:new_resource) do - new_resource = Chef::Resource::Mount.new(@mount_point, run_context) - new_resource.device @device - new_resource.name @mount_point - new_resource.fstype @fstype - new_resource.options "log=NULL" if ohai[:platform] == 'aix' - new_resource - end - - let(:provider) do - provider = new_resource.provider_for_action(new_resource.action) - provider - end - - let(:current_resource) do - provider.load_current_resource - provider.current_resource - end - - # Actual tests begin here. - before(:all) do - @device, @fstype = setup_device_for_mount - - @mount_point = Dir.mktmpdir("testmount") - - # Make sure all the potentially leaked mounts are cleared up - shell_out("mount").stdout.each_line do |line| - if line.include? "testmount" - line.split(" ").each do |section| - cleanup_mount(section) if section.include? "testmount" - end - end - end - end - - after(:all) do - Dir.rmdir(@mount_point) - cleanup_device(@device) - end - - after(:each) do - cleanup_mount(new_resource.mount_point) - end - - describe "when the target state is a mounted filesystem" do - it "should mount the filesystem if it isn't mounted" do - current_resource.enabled.should be_false - current_resource.mounted.should be_false - new_resource.run_action(:mount) - new_resource.should be_updated - mount_should_exist(new_resource.mount_point, new_resource.device) - end - end - - # don't run the remount tests on solaris2 (tmpfs does not support remount) - # Need to make sure the platforms we've already excluded are considered: - skip_remount = include_flag || (ohai[:platform] == "solaris2") - describe "when the filesystem should be remounted and the resource supports remounting", :external => skip_remount do - it "should remount the filesystem if it is mounted" do - new_resource.run_action(:mount) - 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.run_action(:remount) - - mount_should_exist(new_resource.mount_point, new_resource.device, nil, (ohai[:platform] == 'aix') ? new_resource.options : nil) - end - end - - describe "when the target state is a unmounted filesystem" do - it "should umount the filesystem if it is mounted" do - new_resource.run_action(:mount) - mount_should_exist(new_resource.mount_point, new_resource.device) - - new_resource.run_action(:umount) - mount_should_not_exists(new_resource.mount_point) - end - end - - describe "when enabling the filesystem to be mounted" do - after do - new_resource.run_action(:disable) - end - - it "should enable the mount if it isn't enable" do - new_resource.run_action(:mount) - new_resource.run_action(:enable) - mount_should_be_enabled(new_resource.mount_point, new_resource.device) - end - end - - describe "when the target state is to disable the mount" do - it "should disable the mount if it is enabled" do - new_resource.run_action(:mount) - new_resource.run_action(:enable) - new_resource.run_action(:disable) - mount_should_be_disabled(new_resource.mount_point) - end - end -end diff --git a/spec/functional/resource/ohai_spec.rb b/spec/functional/resource/ohai_spec.rb deleted file mode 100644 index b1e4891293..0000000000 --- a/spec/functional/resource/ohai_spec.rb +++ /dev/null @@ -1,65 +0,0 @@ -# -# Author:: Serdar Sutay (<serdar@opscode.com>) -# Copyright:: Copyright (c) 2014 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::Ohai do - let(:ohai) { - o = Ohai::System.new - o.all_plugins - o - } - - let(:node) { Chef::Node.new } - - let(:run_context) { - node.default[:platform] = ohai[:platform] - node.default[:platform_version] = ohai[:platform_version] - events = Chef::EventDispatch::Dispatcher.new - Chef::RunContext.new(node, {}, events) - } - - shared_examples_for "reloaded :uptime" do - it "should reload :uptime" do - initial_uptime = ohai[:uptime] - - # Sleep for a second so the uptime gets updated. - sleep 1 - - ohai_resource.run_action(:reload) - node[:uptime].should_not == initial_uptime - end - end - - describe "when reloading all plugins" do - let(:ohai_resource) { Chef::Resource::Ohai.new("reload all", run_context)} - - it_behaves_like "reloaded :uptime" - end - - describe "when reloading only uptime" do - let(:ohai_resource) { - r = Chef::Resource::Ohai.new("reload all", run_context) - r.plugin("uptime") - r - } - - - it_behaves_like "reloaded :uptime" - end -end diff --git a/spec/functional/resource/package_spec.rb b/spec/functional/resource/package_spec.rb deleted file mode 100644 index 548db40e79..0000000000 --- a/spec/functional/resource/package_spec.rb +++ /dev/null @@ -1,390 +0,0 @@ -# encoding: UTF-8 -# -# Author:: Daniel DeLeo (<dan@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' -require 'webrick' - -module AptServer - def enable_testing_apt_source - File.open("/etc/apt/sources.list.d/chef-integration-test.list", "w+") do |f| - f.puts "deb http://localhost:9000/ sid main" - end - # Magic to update apt cache for only our repo - shell_out!("apt-get update " + - '-o Dir::Etc::sourcelist="sources.list.d/chef-integration-test.list" ' + - '-o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0"') - end - - def disable_testing_apt_source - FileUtils.rm("/etc/apt/sources.list.d/chef-integration-test.list") - rescue Errno::ENOENT - puts("Attempted to remove integration test from /etc/apt/sources.list.d but it didn't exist") - end - - def tcp_test_port(hostname, port) - tcp_socket = TCPSocket.new(hostname, port) - true - rescue Errno::ETIMEDOUT - false - rescue Errno::ECONNREFUSED - false - ensure - tcp_socket && tcp_socket.close - end - - def apt_server - @apt_server ||= WEBrick::HTTPServer.new( - :Port => 9000, - :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 ] - ) - end - - def run_apt_server - apt_server.start - end - - def start_apt_server - @apt_server_thread = Thread.new do - run_apt_server - end - until tcp_test_port("localhost", 9000) do - if @apt_server_thread.alive? - sleep 1 - else - @apt_server_thread.join - raise "apt server failed to start" - end - end - end - - def stop_apt_server - apt_server.shutdown - @apt_server_thread.join - end - - def apt_data_dir - File.join(CHEF_SPEC_DATA, "apt") - end -end - -metadata = { :unix_only => true, - :requires_root => true, - :provider => {:package => Chef::Provider::Package::Apt}, - :arch => "x86_64" # test packages are 64bit -} - -describe Chef::Resource::Package, metadata do - include Chef::Mixin::ShellOut - - context "with a remote package source" do - - include AptServer - - before(:all) do - # Disable mixlib-shellout live streams - Chef::Log.level = :warn - start_apt_server - enable_testing_apt_source - end - - after(:all) do - stop_apt_server - disable_testing_apt_source - shell_out!("apt-get clean") - end - - - after do - shell_out!("dpkg -r chef-integration-test") - shell_out("dpkg --clear-avail") - shell_out!("apt-get clean") - end - - let(:node) do - n = Chef::Node.new - n.consume_external_attrs(OHAI_SYSTEM.data.dup, {}) - n - end - - let(:events) do - Chef::EventDispatch::Dispatcher.new - end - - # TODO: lots of duplication from client.rb; - # All of this must be setup for preseed files to get found - let(:cookbook_collection) do - cookbook_path = File.join(CHEF_SPEC_DATA, "cookbooks") - cl = Chef::CookbookLoader.new(cookbook_path) - cl.load_cookbooks - Chef::Cookbook::FileVendor.fetch_from_disk(cookbook_path) - Chef::CookbookCollection.new(cl) - end - - let(:run_context) do - Chef::RunContext.new(node, cookbook_collection, events) - end - - def base_resource - r = Chef::Resource::Package.new("chef-integration-test", run_context) - # The apt repository in the spec data is not gpg signed, so we need to - # force apt to accept the package: - r.options("--force-yes") - r - end - - let(:package_resource) do - base_resource - end - - context "when the package is not yet installed" do - it "installs the package with action :install" do - package_resource.run_action(:install) - shell_out!("dpkg -l chef-integration-test") - package_resource.should be_updated_by_last_action - end - - it "installs the package for action :upgrade" do - package_resource.run_action(:upgrade) - shell_out!("dpkg -l chef-integration-test") - package_resource.should be_updated_by_last_action - end - - it "does nothing for action :remove" do - package_resource.run_action(:remove) - shell_out!("dpkg -l chef-integration-test", :returns => [1]) - package_resource.should_not be_updated_by_last_action - end - - it "does nothing for action :purge" do - package_resource.run_action(:purge) - shell_out!("dpkg -l chef-integration-test", :returns => [1]) - package_resource.should_not be_updated_by_last_action - end - - context "and a not-available package version is specified" do - let(:package_resource) do - r = base_resource - r.version("2.0") - r - end - - it "raises a reasonable error for action :install" do - expect do - package_resource.run_action(:install) - end.to raise_error(Mixlib::ShellOut::ShellCommandFailed) - end - - end - - describe "when preseeding the install" do - - let(:file_cache_path) { Dir.mktmpdir } - - before do - Chef::Config[:file_cache_path] = file_cache_path - debconf_reset = 'chef-integration-test chef-integration-test/sample-var string "INVALID"' - shell_out!("echo #{debconf_reset} |debconf-set-selections") - end - - after do - FileUtils.rm_rf(file_cache_path) - end - - context "with a preseed file" do - - let(:package_resource) do - r = base_resource - r.cookbook_name = "preseed" - r.response_file("preseed-file.seed") - r - end - - it "preseeds the package, then installs it" do - package_resource.run_action(:install) - cmd = shell_out!("debconf-show chef-integration-test") - cmd.stdout.should include('chef-integration-test/sample-var: "hello world"') - package_resource.should be_updated_by_last_action - end - - context "and the preseed file exists and is up-to-date" do - - before do - # Code here is duplicated from the implementation. Not great, but - # it should at least fail if the code gets out of sync. - source = File.join(CHEF_SPEC_DATA, "cookbooks/preseed/files/default/preseed-file.seed") - file_cache_dir = Chef::FileCache.create_cache_path("preseed/preseed") - dest = "#{file_cache_dir}/chef-integration-test-1.1-1.seed" - FileUtils.cp(source, dest) - end - - it "does not update the package configuration" do - package_resource.run_action(:install) - cmd = shell_out!("debconf-show chef-integration-test") - cmd.stdout.should include('chef-integration-test/sample-var: INVALID') - package_resource.should be_updated_by_last_action - end - - end - - end - - context "with a preseed template" do - - # NOTE: in the fixtures, there is also a cookbook_file named - # "preseed-template.seed". This implicitly tests that templates are - # preferred over cookbook_files when both are present. - - let(:package_resource) do - r = base_resource - r.cookbook_name = "preseed" - r.response_file("preseed-template.seed") - r - end - - before do - node.set[:preseed_value] = "FROM TEMPLATE" - end - - it "preseeds the package, then installs it" do - package_resource.run_action(:install) - cmd = shell_out!("debconf-show chef-integration-test") - cmd.stdout.should include('chef-integration-test/sample-var: "FROM TEMPLATE"') - package_resource.should be_updated_by_last_action - end - - context "with variables" do - let(:package_resource) do - r = base_resource - r.cookbook_name = "preseed" - r.response_file("preseed-template-variables.seed") - r.response_file_variables({ :template_variable => 'SUPPORTS VARIABLES' }) - r - end - - it "preseeds the package, then installs it" do - package_resource.run_action(:install) - cmd = shell_out!("debconf-show chef-integration-test") - cmd.stdout.should include('chef-integration-test/sample-var: "SUPPORTS VARIABLES"') - package_resource.should be_updated_by_last_action - end - end - - end - end # installing w/ preseed - end # when package not installed - - context "and the desired version of the package is installed" do - - before do - v_1_1_package = File.expand_path("apt/chef-integration-test_1.1-1_amd64.deb", CHEF_SPEC_DATA) - shell_out!("dpkg -i #{v_1_1_package}") - end - - it "does nothing for action :install" do - package_resource.run_action(:install) - shell_out!("dpkg -l chef-integration-test", :returns => [0]) - package_resource.should_not be_updated_by_last_action - end - - it "does nothing for action :upgrade" do - package_resource.run_action(:upgrade) - shell_out!("dpkg -l chef-integration-test", :returns => [0]) - package_resource.should_not be_updated_by_last_action - end - - # Verify that the package is removed by running `dpkg -l PACKAGE` - # On Ubuntu 12.10 and newer, the command exits 1. - # - # On Ubuntu 12.04 and older, the `dpkg -l` command will exit 0 and - # display a package status message like this: - # - # Desired=Unknown/Install/Remove/Purge/Hold - # | Status=Not/Inst/Cfg-files/Unpacked/Failed-cfg/Half-inst/trig-aWait/Trig-pend - # |/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad) - # ||/ Name Version Description - # +++-=================================-=========================================-============================================ - # 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]) - - if pkg_check.exitstatus == 0 - pkg_check.stdout.should =~ /un[\s]+chef-integration-test/ - end - end - - - it "removes the package for action :remove" do - package_resource.run_action(:remove) - pkg_should_be_removed - package_resource.should be_updated_by_last_action - end - - it "removes the package for action :purge" do - package_resource.run_action(:purge) - pkg_should_be_removed - package_resource.should be_updated_by_last_action - end - - end - - context "and an older version of the package is installed" do - before do - v_1_0_package = File.expand_path("apt/chef-integration-test_1.0-1_amd64.deb", CHEF_SPEC_DATA) - shell_out!("dpkg -i #{v_1_0_package}") - end - - it "does nothing for action :install" do - package_resource.run_action(:install) - shell_out!("dpkg -l chef-integration-test", :returns => [0]) - package_resource.should_not be_updated_by_last_action - end - - it "upgrades the package for action :upgrade" do - package_resource.run_action(:upgrade) - dpkg_l = shell_out!("dpkg -l chef-integration-test", :returns => [0]) - dpkg_l.stdout.should =~ /chef\-integration\-test[\s]+1\.1\-1/ - package_resource.should be_updated_by_last_action - end - - context "and the resource specifies the new version" do - let(:package_resource) do - r = base_resource - r.version("1.1-1") - r - end - - it "upgrades the package for action :install" do - package_resource.run_action(:install) - dpkg_l = shell_out!("dpkg -l chef-integration-test", :returns => [0]) - dpkg_l.stdout.should =~ /chef\-integration\-test[\s]+1\.1\-1/ - package_resource.should be_updated_by_last_action - end - end - - end - - end - -end - - diff --git a/spec/functional/resource/powershell_spec.rb b/spec/functional/resource/powershell_spec.rb deleted file mode 100644 index 96a356f441..0000000000 --- a/spec/functional/resource/powershell_spec.rb +++ /dev/null @@ -1,449 +0,0 @@ -# -# Author:: Adam Edwards (<adamed@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(: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 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' ) - - is_64_bit.should == 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) - - source_contains_case_insensitive_content?( get_script_output, 'x86' ).should == true - end - - it "raises an exception if :x86_64 process architecture is specified" do - begin - resource.architecture(:x86_64).should 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) - - source_contains_case_insensitive_content?( get_script_output, 'AMD64' ).should == 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) - - source_contains_case_insensitive_content?( get_script_output, 'x86' ).should == true - end - end - - describe "when executing guards" do - before(:each) do - resource.not_if.clear - resource.only_if.clear - # resource.guard_interpreter should be :default by default - end - - it "evaluates a succeeding not_if block using cmd.exe as false by default" do - resource.not_if "exit /b 0" - resource.should_skip?(:run).should be_true - end - - it "evaluates a failing not_if block using cmd.exe as true by default" do - resource.not_if "exit /b 2" - resource.should_skip?(:run).should be_false - end - - it "evaluates an succeeding only_if block using cmd.exe as true by default" do - resource.only_if "exit /b 0" - resource.should_skip?(:run).should be_false - end - - it "evaluates a failing only_if block using cmd.exe as false by default" do - resource.only_if "exit /b 2" - resource.should_skip?(:run).should be_true - end - - context "the only_if is specified before the guard" do - before do - # force the guard_interpreter to :default in case the default changes later - 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 - resource.should_skip?(:run).should be_false - end - end - - context "with powershell_script as the guard_interpreter" do - before(:each) do - resource.guard_interpreter :powershell_script - end - - it "evaluates a powershell $false for a not_if block as true" do - resource.not_if "$false" - resource.should_skip?(:run).should be_false - end - - it "evaluates a powershell $true for a not_if block as false" do - resource.not_if "$true" - resource.should_skip?(:run).should be_true - end - - it "evaluates a powershell $false for an only_if block as false" do - resource.only_if "$false" - resource.should_skip?(:run).should be_true - end - - it "evaluates a powershell $true for a only_if block as true" do - resource.only_if "$true" - resource.should_skip?(:run).should be_false - end - - it "evaluates a not_if block using powershell.exe" do - resource.not_if "exit([int32](![System.Environment]::CommandLine.Contains('powershell.exe')))" - resource.should_skip?(:run).should be_true - end - - it "evaluates an only_if block using powershell.exe" do - resource.only_if "exit([int32](![System.Environment]::CommandLine.Contains('powershell.exe')))" - resource.should_skip?(:run).should be_false - end - - it "evaluates a non-zero powershell exit status for not_if as true" do - resource.not_if "exit 37" - resource.should_skip?(:run).should be_false - end - - it "evaluates a zero powershell exit status for not_if as false" do - resource.not_if "exit 0" - resource.should_skip?(:run).should be_true - end - - it "evaluates a failed executable exit status for not_if as false" do - resource.not_if windows_process_exit_code_not_found_content - resource.should_skip?(:run).should be_false - end - - it "evaluates a successful executable exit status for not_if as true" do - resource.not_if windows_process_exit_code_success_content - resource.should_skip?(:run).should be_true - end - - it "evaluates a failed executable exit status for only_if as false" do - resource.only_if windows_process_exit_code_not_found_content - resource.should_skip?(:run).should be_true - end - - it "evaluates a successful executable exit status for only_if as true" do - resource.only_if windows_process_exit_code_success_content - resource.should_skip?(:run).should be_false - end - - it "evaluates a failed cmdlet exit status for not_if as true" do - resource.not_if "throw 'up'" - resource.should_skip?(:run).should be_false - end - - it "evaluates a successful cmdlet exit status for not_if as true" do - resource.not_if "cd ." - resource.should_skip?(:run).should be_true - end - - it "evaluates a failed cmdlet exit status for only_if as false" do - resource.only_if "throw 'up'" - resource.should_skip?(:run).should be_true - end - - it "evaluates a successful cmdlet exit status for only_if as true" do - resource.only_if "cd ." - resource.should_skip?(:run).should be_false - 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 - resource.should_skip?(:run).should be_true - 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 - resource.should_skip?(:run).should be_false - 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}')" - resource.should_skip?(:run).should be_false - 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}')" - resource.should_skip?(:run).should be_true - 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')" - resource.should_skip?(:run).should be_false - 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')" - resource.should_skip?(:run).should be_true - 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')" - resource.should_skip?(:run).should be_false - 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')" - resource.should_skip?(:run).should be_true - 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" - resource.should_skip?(:run).should be_true - 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" - resource.should_skip?(:run).should be_false - 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" - resource.should_skip?(:run).should be_false - 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" - resource.should_skip?(:run).should be_true - 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'" - resource.should_skip?(:run).should be_false - 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'" - resource.should_skip?(:run).should be_false - 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'" - resource.should_skip?(:run).should be_true - 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'" - resource.should_skip?(:run).should be_true - 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 deleted file mode 100644 index 735ca994c8..0000000000 --- a/spec/functional/resource/reboot_spec.rb +++ /dev/null @@ -1,103 +0,0 @@ -# -# Author:: Chris Doherty <cdoherty@getchef.com>) -# Copyright:: Copyright (c) 2014 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::Resource::Reboot do - - let(:expected) do - { - :delay_mins => 5, - :requested_by => "reboot resource functional test", - :reason => "reboot resource spec test" - } - end - - def create_resource - node = Chef::Node.new - events = Chef::EventDispatch::Dispatcher.new - run_context = Chef::RunContext.new(node, {}, events) - resource = Chef::Resource::Reboot.new(expected[:requested_by], run_context) - resource.delay_mins(expected[:delay_mins]) - resource.reason(expected[:reason]) - resource - end - - let(:resource) do - create_resource - end - - 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]) - expect(reboot_info[:delay_mins]).to eq(expected[:delay_mins]) - expect(reboot_info[:reason]).to eq(expected[:reason]) - expect(reboot_info[:requested_by]).to eq(expected[:requested_by]) - - expect(resource.run_context.reboot_requested?).to be_true - end - 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' - - before do - resource.run_action(:request_reboot) - end - - after do - resource.run_context.cancel_reboot - end - - 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' - - after do - resource.run_context.cancel_reboot - end - - 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) - }.to throw_symbol(:end_client_run_early) - - test_reboot_action(resource) - end - end - - describe "the cancel action" do - before do - resource.run_context.request_reboot(expected) - resource.run_action(:cancel) - end - - 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_false - end - end -end diff --git a/spec/functional/resource/registry_spec.rb b/spec/functional/resource/registry_spec.rb deleted file mode 100644 index 2d24eee6a3..0000000000 --- a/spec/functional/resource/registry_spec.rb +++ /dev/null @@ -1,561 +0,0 @@ -# -# Author:: Prajakta Purohit (<prajakta@opscode.com>) -# Author:: Lamont Granquist (<lamont@opscode.com>) -# Copyright:: Copyright (c) 2011 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/win32/registry" -require "chef/resource_reporter" -require "spec_helper" - -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"}]) - lambda{@resource.run_action(:create)}.should raise_error(Chef::Exceptions::Win32NotWindows) - end - end -end - -describe Chef::Resource::RegistryKey, :windows_only do - - # parent and key must be single keys, not paths - 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 - let(:reg_parent) { "HKLM\\" + key_parent } - let(:reg_child) { "HKLM\\" + key_child } - let(:hive_class) { ::Win32::Registry::HKEY_LOCAL_MACHINE } - let(:resource_name) { "This is the name of my Resource" } - - def clean_registry - if windows64? - # clean 64-bit space on WOW64 - @registry.architecture = :x86_64 - @registry.delete_key(reg_parent, true) - @registry.architecture = :machine - end - # clean 32-bit space on WOW64 - @registry.architecture = :i386 - @registry.delete_key(reg_parent, true) - @registry.architecture = :machine - end - - def reset_registry - clean_registry - hive_class.create(key_parent, Win32::Registry::KEY_WRITE | 0x0100) - hive_class.create(key_parent, Win32::Registry::KEY_WRITE | 0x0200) - end - - def create_deletable_keys - # create them both 32-bit and 64-bit - [ 0x0100, 0x0200 ].each do |flag| - hive_class.create(key_parent + '\Opscode', Win32::Registry::KEY_WRITE | flag) - hive_class.open(key_parent + '\Opscode', Win32::Registry::KEY_ALL_ACCESS | flag) do |reg| - reg["Color", Win32::Registry::REG_SZ] = "Orange" - reg.write("Opscode", Win32::Registry::REG_MULTI_SZ, ["Seattle", "Washington"]) - reg["AKA", Win32::Registry::REG_SZ] = "OC" - end - hive_class.create(key_parent + '\ReportKey', Win32::Registry::KEY_WRITE | flag) - hive_class.open(key_parent + '\ReportKey', Win32::Registry::KEY_ALL_ACCESS | flag) do |reg| - reg["ReportVal4", Win32::Registry::REG_SZ] = "report4" - reg["ReportVal5", Win32::Registry::REG_SZ] = "report5" - end - hive_class.create(key_parent + '\OpscodeWhyRun', Win32::Registry::KEY_WRITE | flag) - hive_class.open(key_parent + '\OpscodeWhyRun', Win32::Registry::KEY_ALL_ACCESS | flag) do |reg| - reg["BriskWalk", Win32::Registry::REG_SZ] = "is good for health" - end - end - end - - 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) - - @new_resource = Chef::Resource::RegistryKey.new(resource_name, @run_context) - @registry = Chef::Win32::Registry.new(@run_context) - - reset_registry - end - - #Reporting setup - before do - @node.name("windowsbox") - - @rest_client = double("Chef::REST (mock)") - @rest_client.stub(:create_url).and_return("reports/nodes/windowsbox/runs/#{@run_id}"); - @rest_client.stub(:raw_http_request).and_return({"result"=>"ok"}); - @rest_client.stub(: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) - @run_status = Chef::RunStatus.new(@node, @events) - @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") - @new_resource.stub(:cookbook_version).and_return(@cookbook_version) - end - - after (:all) do - clean_registry - end - - context "when action is create" do - before (:all) do - reset_registry - 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.run_action(:create) - - @registry.key_exists?(reg_child).should == true - @registry.data_exists?(reg_child, {:name=>"Color", :type=>:string, :data=>"Orange"}).should == 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.run_action(:create) - - @registry.key_exists?(reg_child).should == true - @registry.data_exists?(reg_child, {:name=>"Color", :type=>:string, :data=>"Orange"}).should == 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.run_action(:create) - - @registry.data_exists?(reg_child, {:name=>"Mango", :type=>:string, :data=>"Yellow"}).should == 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.run_action(:create) - - @registry.data_exists?(reg_child, {:name=>"Color", :type=>:string, :data=>"Not just Orange - OpscodeOrange!"}).should == 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.run_action(:create) - - @registry.data_exists?(reg_child, {:name=>"Color", :type=>:multi_string, :data=>["Not just Orange - OpscodeOrange!"]}).should == 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.recursive(false) - @new_resource.run_action(:create) - - @registry.key_exists?(reg_child + '\OpscodeTest').should == true - @registry.value_exists?(reg_child + '\OpscodeTest', {:name=>"Chef", :type=>:multi_string, :data=>["OpscodeOrange", "Rules"]}).should == 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.recursive(false) - lambda{@new_resource.run_action(:create)}.should 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.recursive(true) - @new_resource.run_action(:create) - - @registry.key_exists?(reg_child + '\Missing1\Missing2').should == true - @registry.value_exists?(reg_child + '\Missing1\Missing2', {:name=>"OC", :type=>:string, :data=>"MissingData"}).should == 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.recursive(true) - @new_resource.run_action(:create) - - @new_resource.values.each do |value| - @registry.value_exists?(reg_child, value).should == true - end - end - - context "when running on 64-bit server", :windows64_only do - before(:all) do - reset_registry - end - after(:all) do - @new_resource.architecture(:machine) - @registry.architecture = :machine - 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.recursive(true) - @new_resource.architecture(:i386) - @new_resource.run_action(:create) - @registry.architecture = :i386 - @registry.data_exists?(reg_child + '\Atraxi', {:name=>"OC", :type=>:string, :data=>"Data"}).should == true - @registry.architecture = :x86_64 - @registry.key_exists?(reg_child + '\Atraxi').should == false - end - end - - 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.recursive(true) - @new_resource.run_action(:create) - @report = @resource_reporter.prepare_run_data - - @report["action"].should == "end" - @report["resources"][0]["type"].should == "registry_key" - @report["resources"][0]["name"].should == resource_name - @report["resources"][0]["id"].should == reg_child + '\Ood' - @report["resources"][0]["after"][:values].should == [{:name=>"ReportingVal1", :type=>:string, :data=>"report1"}, - {:name=>"ReportingVal2", :type=>:string, :data=>"report2"}] - @report["resources"][0]["before"][:values].should == [] - @report["resources"][0]["result"].should == "create" - @report["status"].should == "success" - @report["total_res_count"].should == "1" - end - - context "while running in whyrun mode" do - before (:each) do - Chef::Config[:why_run] = true - end - - 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.recursive(false) - @new_resource.run_action(:create) # should not raise_error - @registry.key_exists?(reg_child + '\Slitheen').should == false - @registry.key_exists?(reg_child + '\Slitheen\Raxicoricofallapatorius').should == false - 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.recursive(false) - @new_resource.run_action(:create) - @registry.key_exists?(reg_child + '\Slitheen').should == false - end - end - end - - context "when action is create_if_missing" do - before (:all) do - reset_registry - 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.run_action(:create_if_missing) - - @registry.key_exists?(reg_parent).should == true - @registry.key_exists?(reg_child).should == true - @registry.data_exists?(reg_child, {:name=>"Color", :type=>:string, :data=>"Orange"}).should == 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.run_action(:create_if_missing) - - @registry.key_exists?(reg_child).should == true - @registry.data_exists?(reg_child, {:name=>"Color", :type=>:string, :data=>"Orange"}).should == 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.run_action(:create_if_missing) - - @registry.data_exists?(reg_child, {:name=>"Mango", :type=>:string, :data=>"Yellow"}).should == 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.recursive(false) - @new_resource.run_action(:create_if_missing) - - @registry.key_exists?(reg_child + '\Pyrovile').should == true - @registry.value_exists?(reg_child + '\Pyrovile', {:name=>"Chef", :type=>:multi_string, :data=>["OpscodeOrange", "Rules"]}).should == 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.recursive(false) - lambda{@new_resource.run_action(:create_if_missing)}.should 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.recursive(true) - @new_resource.run_action(:create_if_missing) - - @registry.key_exists?(reg_child + '\Sontaran\Sontar').should == true - @registry.value_exists?(reg_child + '\Sontaran\Sontar', {:name=>"OC", :type=>:string, :data=>"MissingData"}).should == 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.recursive(true) - @new_resource.run_action(:create_if_missing) - - @new_resource.values.each do |value| - @registry.value_exists?(reg_child + '\Adipose', value).should == true - end - end - - 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.recursive(true) - @new_resource.run_action(:create_if_missing) - @report = @resource_reporter.prepare_run_data - - @report["action"].should == "end" - @report["resources"][0]["type"].should == "registry_key" - @report["resources"][0]["name"].should == resource_name - @report["resources"][0]["id"].should == reg_child + '\Judoon' - @report["resources"][0]["after"][:values].should == [{:name=>"ReportingVal3", :type=>:string, :data=>"report3"}] - @report["resources"][0]["before"][:values].should == [] - @report["resources"][0]["result"].should == "create_if_missing" - @report["status"].should == "success" - @report["total_res_count"].should == "1" - end - - context "while running in whyrun mode" do - before (:each) do - Chef::Config[:why_run] = true - end - - 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.recursive(false) - @new_resource.run_action(:create_if_missing) # should not raise_error - @registry.key_exists?(reg_child + '\Zygons').should == false - @registry.key_exists?(reg_child + '\Zygons\Zygor').should == false - 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.recursive(false) - @new_resource.run_action(:create_if_missing) - @registry.key_exists?(reg_child + '\Zygons').should == false - end - end - end - - context "when the action is delete" do - before(:all) do - reset_registry - create_deletable_keys - end - - it "takes no action if the specified key path does not exist in the system" do - @registry.key_exists?(reg_parent + '\Osirian').should == false - - @new_resource.key(reg_parent+ '\Osirian') - @new_resource.recursive(false) - @new_resource.run_action(:delete) - - @registry.key_exists?(reg_parent + '\Osirian').should == false - end - - it "takes no action if the key exists but the value does not" do - @registry.data_exists?(reg_parent + '\Opscode', {:name=>"Color", :type=>:string, :data=>"Orange"}).should == true - - @new_resource.key(reg_parent + '\Opscode') - @new_resource.values([{:name=>"LooksLike", :type=>:multi_string, :data=>["SeattleGrey", "OCOrange"]}]) - @new_resource.recursive(false) - @new_resource.run_action(:delete) - - @registry.data_exists?(reg_parent + '\Opscode', {:name=>"Color", :type=>:string, :data=>"Orange"}).should == 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.recursive(false) - @new_resource.run_action(:delete) - - @registry.data_exists?(reg_parent + '\Opscode', {:name=>"Color", :type=>:string, :data=>"Orange"}).should == true - @registry.value_exists?(reg_parent + '\Opscode', {:name=>"AKA", :type=>:string, :data=>"OC"}).should == false - @registry.value_exists?(reg_parent + '\Opscode', {:name=>"Opscode", :type=>:multi_string, :data=>["Seattle", "Washington"]}).should == 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.recursive(false) - @new_resource.run_action(:delete) - - @registry.value_exists?(reg_parent + '\Opscode', {:name=>"Color", :type=>:string, :data=>"Orange"}).should == 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.recursive(true) - @new_resource.run_action(:delete) - - @report = @resource_reporter.prepare_run_data - - @registry.value_exists?(reg_parent + '\ReportKey', [{:name=>"ReportVal4", :type=>:string, :data=>"report4"},{:name=>"ReportVal5", :type=>:string, :data=>"report5"}]).should == false - - @report["action"].should == "end" - @report["resources"].count.should == 1 - @report["resources"][0]["type"].should == "registry_key" - @report["resources"][0]["name"].should == resource_name - @report["resources"][0]["id"].should == reg_parent + '\ReportKey' - @report["resources"][0]["before"][:values].should == [{:name=>"ReportVal4", :type=>:string, :data=>"report4"}, - {:name=>"ReportVal5", :type=>:string, :data=>"report5"}] - #Not testing for after values to match since after -> new_resource values. - @report["resources"][0]["result"].should == "delete" - @report["status"].should == "success" - @report["total_res_count"].should == "1" - end - - context "while running in whyrun mode" do - before (:each) do - Chef::Config[:why_run] = true - 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.recursive(false) - @new_resource.run_action(:delete) - - @registry.key_exists?(reg_parent + '\OpscodeWhyRun').should == true - end - end - end - - context "when the action is delete_key" do - before (:all) do - reset_registry - create_deletable_keys - end - - it "takes no action if the specified key path does not exist in the system" do - @registry.key_exists?(reg_parent + '\Osirian').should == false - - @new_resource.key(reg_parent + '\Osirian') - @new_resource.recursive(false) - @new_resource.run_action(:delete_key) - - @registry.key_exists?(reg_parent + '\Osirian').should == false - end - - it "deletes key if it has no subkeys and recursive == false" do - @new_resource.key(reg_parent + '\OpscodeTest') - @new_resource.recursive(false) - @new_resource.run_action(:delete_key) - - @registry.key_exists?(reg_parent + '\OpscodeTest').should == false - end - - it "raises an exception if the key has subkeys and recursive == false" do - @new_resource.key(reg_parent) - @new_resource.recursive(false) - lambda{@new_resource.run_action(:delete_key)}.should raise_error(Chef::Exceptions::Win32RegNoRecursive) - end - - it "ignores the values under a key" do - @new_resource.key(reg_parent + '\OpscodeIgnoredValues') - #@new_resource.values([{:name=>"DontExist", :type=>:string, :data=>"These will be ignored anyways"}]) - @new_resource.recursive(true) - @new_resource.run_action(:delete_key) - end - - it "deletes the key if it has subkeys and recursive == true" do - @new_resource.key(reg_parent + '\Opscode') - @new_resource.recursive(true) - @new_resource.run_action(:delete_key) - - @registry.key_exists?(reg_parent + '\Opscode').should == false - end - - it "prepares the reporting data for action :delete_key" do - @new_resource.key(reg_parent + '\ReportKey') - @new_resource.recursive(true) - @new_resource.run_action(:delete_key) - - @report = @resource_reporter.prepare_run_data - @report["action"].should == "end" - @report["resources"][0]["type"].should == "registry_key" - @report["resources"][0]["name"].should == resource_name - @report["resources"][0]["id"].should == reg_parent + '\ReportKey' - #Not testing for before or after values to match since - #after -> new_resource.values and - #before -> current_resource.values - @report["resources"][0]["result"].should == "delete_key" - @report["status"].should == "success" - @report["total_res_count"].should == "1" - end - context "while running in whyrun mode" do - before (:each) do - Chef::Config[:why_run] = true - end - - 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.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.recursive(false) - @new_resource.run_action(:delete_key) - - @registry.key_exists?(reg_parent + '\OpscodeWhyRun').should == true - end - end - end -end diff --git a/spec/functional/resource/remote_directory_spec.rb b/spec/functional/resource/remote_directory_spec.rb deleted file mode 100644 index f9eb20711e..0000000000 --- a/spec/functional/resource/remote_directory_spec.rb +++ /dev/null @@ -1,220 +0,0 @@ -# -# Author:: Seth Chisamore (<schisamo@opscode.com>) -# Copyright:: Copyright (c) 2011 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::RemoteDirectory do - include_context Chef::Resource::Directory - - let(:directory_base) { "directory_spec" } - let(:default_mode) { ((0100777 - File.umask) & 07777).to_s(8) } - - def create_resource - 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) - events = Chef::EventDispatch::Dispatcher.new - run_context = Chef::RunContext.new(node, cookbook_collection, events) - - resource = Chef::Resource::RemoteDirectory.new(path, run_context) - resource.source "remotedir" - 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.touch(@existing1) - FileUtils.touch(@existing2) - end - - let(:resource) do - create_resource - end - - let(:resource_second_pass) do - create_resource - end - - # 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') - ] - end - - it_behaves_like "a directory resource" - - it_behaves_like "a securable resource with reporting" - - context "when creating the remote directory with purging disabled" do - - context "and the directory does not yet exist" do - before do - resource.run_action(:create) - end - - it "transfers the directory with all contents" do - expected_files.each do |file_path| - File.should exist(file_path) - end - end - - it "is marked as updated by last action" do - resource.should be_updated_by_last_action - end - end - - context "and there are extraneous files in the directory" do - before do - create_extraneous_files - resource.run_action(:create) - end - - it "does not modify the expected state of the directory" do - expected_files.each do |file_path| - File.should exist(file_path) - end - end - - it "does not remove unmanaged files" do - File.should exist(@existing1) - File.should exist(@existing2) - end - end - - context "and the directory is in the desired state" do - before do - resource.run_action(:create) - resource_second_pass.run_action(:create) - end - - it "does not modify the expected state of the directory" do - expected_files.each do |file_path| - File.should exist(file_path) - end - end - - it "is not marked as updated by last action" do - resource_second_pass.should_not be_updated_by_last_action - end - - end - - describe "with overwrite disabled" do - before(:each) do - resource.purge(false) - resource.overwrite(false) - 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"} - modified_file_checksum = sha256_checksum(modified_file) - modified_subdir_file_checksum = sha256_checksum(modified_subdir_file) - - resource.run_action(:create) - sha256_checksum(modified_file).should == modified_file_checksum - sha256_checksum(modified_subdir_file).should == modified_subdir_file_checksum - end - end - end - - context "when creating the directory with purging enabled" do - before(:each) do - resource.purge(true) - end - - context "and there are no extraneous files in the directory" do - before do - resource.run_action(:create) - end - - it "creates the directory contents as normal" do - expected_files.each do |file_path| - File.should exist(file_path) - end - end - - end - - context "and there are extraneous files in the directory" do - before do - create_extraneous_files - resource.run_action(:create) - end - - it "removes unmanaged files" do - File.should_not exist(@existing1) - File.should_not exist(@existing2) - end - - it "does not modify managed files" do - expected_files.each do |file_path| - File.should exist(file_path) - end - end - - it "is marked as updated by last action" do - resource.should be_updated_by_last_action - end - end - - 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.touch(@existing1) - FileUtils.touch(@existing2) - FileUtils.touch(@existing3) - FileUtils.touch(@existing4) - - resource.run_action(:create) - end - - it "removes files in subdirectories before files above" do - File.should_not exist(@existing1) - File.should_not exist(@existing2) - File.should_not exist(@existing3) - File.should_not exist(@existing4) - end - - it "is marked as updated by last action" do - resource.should be_updated_by_last_action - end - - end - end - -end diff --git a/spec/functional/resource/remote_file_spec.rb b/spec/functional/resource/remote_file_spec.rb deleted file mode 100644 index ccdf1cb812..0000000000 --- a/spec/functional/resource/remote_file_spec.rb +++ /dev/null @@ -1,240 +0,0 @@ -# -# Author:: Seth Chisamore (<schisamo@opscode.com>) -# Copyright:: Copyright (c) 2011 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 'tiny_server' -require 'support/shared/functional/http' - -describe Chef::Resource::RemoteFile do - include ChefHTTPShared - - let(:file_cache_path) { Dir.mktmpdir } - - before(:each) do - @old_file_cache = Chef::Config[:file_cache_path] - Chef::Config[:file_cache_path] = file_cache_path - end - - after(:each) do - Chef::Config[:file_cache_path] = @old_file_cache - FileUtils.rm_rf(file_cache_path) - end - - include_context Chef::Resource::File - - let(:file_base) { "remote_file_spec" } - - def create_resource - node = Chef::Node.new - events = Chef::EventDispatch::Dispatcher.new - run_context = Chef::RunContext.new(node, {}, events) - resource = Chef::Resource::RemoteFile.new(path, run_context) - resource.source(source) - resource - end - - let(:resource) do - create_resource - end - - let(:default_mode) { ((0100666 - File.umask) & 07777).to_s(8) } - - context "when fetching files over HTTP" do - before(:all) do - start_tiny_server - end - - after(:all) do - stop_tiny_server - end - - describe "when redownload isn't necessary" do - let(:source) { 'http://localhost:9000/seattle_capo.png' } - - before do - @api.get("/seattle_capo.png", 304, "", { 'Etag' => 'abcdef' } ) - end - - it "does not fetch the file" do - resource.run_action(:create) - end - end - - context "when using normal encoding" do - let(:source) { 'http://localhost:9000/nyan_cat.png' } - let(:expected_content) { binread(nyan_uncompressed_filename) } - - it_behaves_like "a file resource" - - it_behaves_like "a securable resource with reporting" - end - - context "when using gzip encoding" do - let(:source) { 'http://localhost:9000/nyan_cat.png.gz' } - let(:expected_content) { binread(nyan_compressed_filename) } - - it_behaves_like "a file resource" - - it_behaves_like "a securable resource with reporting" - end - - end - - context "when fetching files over HTTPS" do - - before(:all) do - cert_text = File.read(File.expand_path("ssl/chef-rspec.cert", CHEF_SPEC_DATA)) - cert = OpenSSL::X509::Certificate.new(cert_text) - key_text = File.read(File.expand_path("ssl/chef-rspec.key", CHEF_SPEC_DATA)) - key = OpenSSL::PKey::RSA.new(key_text) - - server_opts = { :SSLEnable => true, - :SSLVerifyClient => OpenSSL::SSL::VERIFY_NONE, - :SSLCertificate => cert, - :SSLPrivateKey => key } - - start_tiny_server(server_opts) - end - - after(:all) do - stop_tiny_server - end - - let(:source) { 'https://localhost:9000/nyan_cat.png' } - - let(:expected_content) { binread(nyan_uncompressed_filename) } - - it_behaves_like "a file resource" - - end - - context "when dealing with content length checking" do - before(:all) do - start_tiny_server - end - - after(:all) do - stop_tiny_server - end - - context "when downloading compressed data" do - let(:expected_content) { binread(nyan_uncompressed_filename) } - let(:source) { 'http://localhost:9000/nyan_cat_content_length_compressed.png' } - - before do - File.should_not exist(path) - resource.run_action(:create) - end - - it "should create the file" do - File.should exist(path) - end - - it "should mark the resource as updated" do - resource.should be_updated_by_last_action - end - - it "has the correct content" do - binread(path).should == expected_content - end - end - - context "when downloding uncompressed data" do - let(:expected_content) { binread(nyan_uncompressed_filename) } - let(:source) { 'http://localhost:9000/nyan_cat_content_length.png' } - - before do - File.should_not exist(path) - resource.run_action(:create) - end - - it "should create the file" do - File.should exist(path) - end - - it "should mark the resource as updated" do - resource.should be_updated_by_last_action - end - - it "has the correct content" do - binread(path).should == expected_content - end - end - - context "when downloading truncated compressed data" do - let(:source) { 'http://localhost:9000/nyan_cat_truncated_compressed.png' } - - before do - File.should_not exist(path) - end - - it "should raise ContentLengthMismatch" do - lambda { resource.run_action(:create) }.should raise_error(Chef::Exceptions::ContentLengthMismatch) - #File.should_not exist(path) # XXX: CHEF-5081 - end - end - - context "when downloding truncated uncompressed data" do - let(:source) { 'http://localhost:9000/nyan_cat_truncated.png' } - - before do - File.should_not exist(path) - end - - it "should raise ContentLengthMismatch" do - lambda { resource.run_action(:create) }.should raise_error(Chef::Exceptions::ContentLengthMismatch) - #File.should_not exist(path) # XXX: CHEF-5081 - end - end - - 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' } - - before do - File.should_not exist(path) - resource.run_action(:create) - end - - it "should create the file" do - File.should exist(path) - end - - it "should mark the resource as updated" do - resource.should be_updated_by_last_action - end - - it "has the correct content" do - binread(path).should == expected_content - end - end - - describe "when the download of the source raises an exception" do - let(:source) { 'http://localhost:0000/seattle_capo.png' } - - before do - File.should_not exist(path) - end - - it "should not create the file" do - expect{ resource.run_action(:create) }.to raise_error - File.should_not exist(path) - end - end - end -end diff --git a/spec/functional/resource/rpm_spec.rb b/spec/functional/resource/rpm_spec.rb deleted file mode 100644 index 7825377c6b..0000000000 --- a/spec/functional/resource/rpm_spec.rb +++ /dev/null @@ -1,122 +0,0 @@ -# -# Author:: Prabhu Das (<prabhu.das@clogeny.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 'functional/resource/base' -require 'chef/mixin/shell_out' - -# run this test only for following platforms. -exclude_test = !['aix', 'centos', 'redhat', 'suse'].include?(ohai[:platform]) -describe Chef::Resource::RpmPackage, :requires_root, :external => exclude_test do - include Chef::Mixin::ShellOut - - let(:new_resource) do - new_resource = Chef::Resource::RpmPackage.new(@pkg_name, run_context) - new_resource.source @pkg_path - new_resource - end - - def rpm_pkg_should_be_installed(resource) - case ohai[:platform] - # Due to dependency issues , different rpm pkgs are used in different platforms. - # dummy rpm package works in aix, without any dependency issues. - when "aix" - expect(shell_out("rpm -qa | grep dummy").exitstatus).to eq(0) - # mytest rpm package works in centos, redhat and in suse without any dependency issues. - when "centos", "redhat", "suse" - expect(shell_out("rpm -qa | grep mytest").exitstatus).to eq(0) - ::File.exists?("/opt/mytest/mytest.sh") # The mytest rpm package contains the mytest.sh file - end - end - - def rpm_pkg_should_not_be_installed(resource) - case ohai[:platform] - when "aix" - expect(shell_out("rpm -qa | grep dummy").exitstatus).to eq(1) - when "centos", "redhat", "suse" - expect(shell_out("rpm -qa | grep mytest").exitstatus).to eq(1) - !::File.exists?("/opt/mytest/mytest.sh") - end - end - - before(:all) do - case ohai[:platform] - # Due to dependency issues , different rpm pkgs are used in different platforms. - when "aix" - @pkg_name = "dummy" - @pkg_version = "1-0" - @pkg_path = "/tmp/dummy-1-0.aix6.1.noarch.rpm" - FileUtils.cp 'spec/functional/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 'spec/functional/assets/mytest-1.0-1.noarch.rpm' , @pkg_path - end - end - - after(:all) do - FileUtils.rm @pkg_path - end - - context "package install action" do - it "should create a package" do - new_resource.run_action(:install) - rpm_pkg_should_be_installed(new_resource) - end - - after(:each) do - shell_out("rpm -qa | grep #{@pkg_name}-#{@pkg_version} | xargs rpm -e") - end - end - - context "package remove action" do - before(:each) do - shell_out("rpm -i #{@pkg_path}") - end - - it "should remove an existing package" do - new_resource.run_action(:remove) - rpm_pkg_should_not_be_installed(new_resource) - end - end - - context "package upgrade action" do - before(:each) do - shell_out("rpm -i #{@pkg_path}") - if ohai[:platform] == 'aix' - @pkg_version = "2-0" - @pkg_path = "/tmp/dummy-2-0.aix6.1.noarch.rpm" - FileUtils.cp 'spec/functional/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 'spec/functional/assets/mytest-2.0-1.noarch.rpm' , @pkg_path - end - end - - it "should upgrade a package" do - new_resource.run_action(:install) - rpm_pkg_should_be_installed(new_resource) - end - - after(:each) do - shell_out("rpm -qa | grep #{@pkg_name}-#{@pkg_version} | xargs rpm -e") - FileUtils.rm @pkg_path - end - end -end diff --git a/spec/functional/resource/template_spec.rb b/spec/functional/resource/template_spec.rb deleted file mode 100644 index fefd995743..0000000000 --- a/spec/functional/resource/template_spec.rb +++ /dev/null @@ -1,212 +0,0 @@ -# -# Author:: Seth Chisamore (<schisamo@opscode.com>) -# Copyright:: Copyright (c) 2011 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::Template do - - def binread(file) - File.open(file,"rb") {|f| f.read } - end - - include_context Chef::Resource::File - - let(:file_base) { "template_spec" } - let(:expected_content) { "slappiness is a warm gun" } - - let(:node) do - node = Chef::Node.new - node.normal[:slappiness] = "a warm gun" - node - end - - def create_resource - cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks")) - Chef::Cookbook::FileVendor.fetch_from_disk(cookbook_repo) - cl = Chef::CookbookLoader.new(cookbook_repo) - cl.load_cookbooks - cookbook_collection = Chef::CookbookCollection.new(cl) - 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') - - # NOTE: partials rely on `cookbook_name` getting set by chef internals and - # ignore the user-set `cookbook` attribute. - resource.cookbook_name = "openldap" - - resource - end - - let(:resource) do - create_resource - end - - let(:default_mode) { ((0100666 - File.umask) & 07777).to_s(8) } - - it_behaves_like "a file resource" - - it_behaves_like "a securable resource with reporting" - - 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.variables(:secret => "nutella") - resource.run_action(:create) - IO.read(path).should == "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.cookbook(nil) - resource.local(true) - resource.run_action(:create) - IO.read(path).should == expected_content - end - end - - describe "when the template resource defines helper methods" do - - include_context "diff disabled" - - let(:resource) do - r = create_resource - r.source "helper_test.erb" - r - end - - let(:expected_content) { "value from helper method" } - - shared_examples "a template with helpers" do - it "generates expected content by calling helper methods" do - resource.run_action(:create) - binread(path).strip.should == expected_content - end - end - - context "using single helper syntax" do - before do - resource.helper(:helper_method) { "value from helper method" } - end - - it_behaves_like "a template with helpers" - end - - context "using single helper syntax referencing @node" do - before do - node.set[:helper_test_attr] = "value from helper method" - resource.helper(:helper_method) { "#{@node[:helper_test_attr]}" } - end - - it_behaves_like "a template with helpers" - end - - context "using an inline block to define helpers" do - before do - resource.helpers do - def helper_method - "value from helper method" - end - end - end - - it_behaves_like "a template with helpers" - end - - context "using an inline block referencing @node" do - before do - node.set[:helper_test_attr] = "value from helper method" - - resource.helpers do - def helper_method - @node[:helper_test_attr] - end - end - end - - it_behaves_like "a template with helpers" - - end - - context "using a module from a library" do - - module ExampleModule - def helper_method - "value from helper method" - end - end - - before do - resource.helpers(ExampleModule) - end - - it_behaves_like "a template with helpers" - - end - context "using a module from a library referencing @node" do - - module ExampleModuleReferencingATNode - def helper_method - @node[:helper_test_attr] - end - end - - before do - node.set[:helper_test_attr] = "value from helper method" - - resource.helpers(ExampleModuleReferencingATNode) - end - - it_behaves_like "a template with helpers" - - end - - context "using helpers with partial templates" do - before do - resource.source("helpers_via_partial_test.erb") - resource.helper(:helper_method) { "value from helper method" } - end - - it_behaves_like "a template with helpers" - - end - end - - describe "when template source contains windows style line endings" do - include_context "diff disabled" - - ["all", "some", "no"].each do |test_case| - context "for #{test_case} lines" do - let(:resource) do - r = create_resource - r.source "#{test_case}_windows_line_endings.erb" - r - end - - it "output should contain platform's line endings" do - resource.run_action(:create) - binread(path).each_line do |line| - line.should end_with(Chef::Platform.windows? ? "\r\n" : "\n") - end - end - end - end - end - -end diff --git a/spec/functional/resource/user/dscl_spec.rb b/spec/functional/resource/user/dscl_spec.rb deleted file mode 100644 index ba508e3258..0000000000 --- a/spec/functional/resource/user/dscl_spec.rb +++ /dev/null @@ -1,199 +0,0 @@ -# -# 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 'chef/mixin/shell_out' - -metadata = { - :unix_only => true, - :requires_root => true, - :provider => {:user => Chef::Provider::User::Dscl}, - :not_supported_on_mac_osx_106 => true, -} - -describe "Chef::Resource::User with Chef::Provider::User::Dscl provider", metadata do - include Chef::Mixin::ShellOut - - def clean_user - begin - shell_out!("/usr/bin/dscl . -delete '/Users/#{username}'") - rescue Mixlib::ShellOut::ShellCommandFailed - # Raised when the user is already cleaned - end - end - - def user_should_exist - shell_out("/usr/bin/dscl . -ls /Users").stdout.should include username - end - - def check_password(pass) - # In order to test the password we use dscl passwd command since - # that's the only command that gets the user password from CLI. - shell_out("dscl . -passwd /Users/greatchef #{pass} new_password").exitstatus.should == 0 - # Now reset the password back - shell_out("dscl . -passwd /Users/greatchef new_password #{pass}").exitstatus.should == 0 - end - - let(:node) do - n = Chef::Node.new - n.consume_external_attrs(OHAI_SYSTEM.data.dup, {}) - n - end - - let(:events) do - Chef::EventDispatch::Dispatcher.new - end - - let(:run_context) do - Chef::RunContext.new(node, {}, events) - end - - let(:username) do - "greatchef" - end - - let(:uid) { nil } - let(:gid) { 20 } - let(:home) { nil } - let(:manage_home) { false } - let(:password) { "XXXYYYZZZ" } - let(:comment) { "Great Chef" } - let(:shell) { "/bin/bash" } - let(:salt) { nil } - let(:iterations) { nil } - - let(:user_resource) do - r = Chef::Resource::User.new("TEST USER RESOURCE", run_context) - r.username(username) - r.uid(uid) - r.gid(gid) - r.home(home) - r.shell(shell) - r.comment(comment) - r.manage_home(manage_home) - r.password(password) - r.salt(salt) - r.iterations(iterations) - r - end - - before do - clean_user - end - - after(:each) do - clean_user - end - - describe "action :create" do - it "should create the user" do - user_resource.run_action(:create) - user_should_exist - check_password(password) - end - end - - describe "when user exists" do - before do - existing_resource = user_resource.dup - existing_resource.run_action(:create) - user_should_exist - end - - describe "when password is updated" do - it "should update the password of the user" do - user_resource.password("mykitchen") - user_resource.run_action(:create) - check_password("mykitchen") - end - end - end - - describe "when password is being set via shadow hash" do - let(:password) { - if node[:platform_version].start_with?("10.7.") - # On Mac 10.7 we only need to set the password - "c9b3bd1a0cde797eef0eff16c580dab996ba3a21961cccc\ -d0f5e65c61558243e50b1a490088bd4824e3b35562d383ca02260398\ -ef1979b302212ec1c5383d1d05fc8d843" - else - "c734b6e4787c3727bb35e29fdd92b97c\ -1de12df509577a045728255ec7c6c5f5\ -c18efa05ed02b682ffa7ebc05119900e\ -b1d4880833aa7a190afc13e2bf0936b8\ -20123e8c98f0f9bcac2a629d9163caac\ -9464a8c234f3919082400b4f939bb77b\ -c5adbbac718b7eb99463a7b679571e0f\ -1c9fef2ef08d0b9e9c2bcf644eed2ffc" - end - } - - let(:iterations) { 25000 } - let(:salt) { "9e2e7d5ee473b496fd24cf0bbfcaedfcb291ee21740e570d1e917e874f8788ca" } - - it "action :create should create the user" do - user_resource.run_action(:create) - user_should_exist - check_password("soawesome") - end - - describe "when user exists" do - before do - existing_resource = user_resource.dup - existing_resource.run_action(:create) - user_should_exist - end - - describe "when password is updated" do - it "should update the password of the user" do - user_resource.password("mykitchen") - user_resource.run_action(:create) - check_password("mykitchen") - end - end - end - end - - describe "when a user is member of some groups" do - let(:groups) { ["staff", "operator"] } - - before do - existing_resource = user_resource.dup - existing_resource.run_action(:create) - - groups.each do |group| - shell_out!("/usr/bin/dscl . -append '/Groups/#{group}' GroupMembership #{username}") - end - end - - after do - groups.each do |group| - # Do not raise an error when user is correctly removed - shell_out("/usr/bin/dscl . -delete '/Groups/#{group}' GroupMembership #{username}") - end - end - - it ":remove action removes the user from the groups and deletes the user"do - user_resource.run_action(:remove) - groups.each do |group| - # Do not raise an error when group is empty - shell_out("dscl . read /Groups/staff GroupMembership").stdout.should_not include(group) - end - end - end - -end diff --git a/spec/functional/resource/user/useradd_spec.rb b/spec/functional/resource/user/useradd_spec.rb deleted file mode 100644 index 1fbe6fcb4d..0000000000 --- a/spec/functional/resource/user/useradd_spec.rb +++ /dev/null @@ -1,686 +0,0 @@ -# encoding: UTF-8 -# -# Author:: Daniel DeLeo (<dan@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' -require 'functional/resource/base' -require 'chef/mixin/shell_out' - -def user_provider_for_platform - case ohai[:platform] - when "aix" - Chef::Provider::User::Aix - else - Chef::Provider::User::Useradd - end -end - -metadata = { :unix_only => true, - :requires_root => 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} - matcher = /^#{Regexp.escape(username)}.+$/ - if passwd_entry = passwd_file.scan(matcher).first - PwEntry.new(*passwd_entry.split(':')) - else - raise UserNotFound, "no entry matching #{matcher.inspect} found in /etc/passwd" - end - end - - def etc_shadow - case ohai[:platform] - when "aix" - File.open("/etc/security/passwd") {|f| f.read } - else - File.open("/etc/shadow") {|f| f.read } - end - end - - def supports_quote_in_username? - OHAI_SYSTEM["platform_family"] == "debian" - end - - def password_should_be_set - if ohai[:platform] == "aix" - pw_entry.passwd.should == "!" - else - pw_entry.passwd.should == "x" - end - end - - before do - # Silence shell_out live stream - Chef::Log.level = :warn - end - - after do - begin - pw_entry # will raise if the user doesn't exist - shell_out!("userdel", "-r", username, :returns => [0,12]) - rescue UserNotFound - # nothing to remove - end - end - - let(:node) do - n = Chef::Node.new - n.consume_external_attrs(OHAI_SYSTEM.data.dup, {}) - n - end - - let(:events) do - Chef::EventDispatch::Dispatcher.new - end - - let(:run_context) do - Chef::RunContext.new(node, {}, events) - end - - let(:username) do - "cf-test" - end - - let(:uid) { nil } - let(:home) { nil } - let(:manage_home) { false } - let(:password) { nil } - let(:system) { false } - let(:comment) { nil } - - let(:user_resource) do - r = Chef::Resource::User.new("TEST USER RESOURCE", run_context) - r.username(username) - r.uid(uid) - r.home(home) - r.comment(comment) - r.manage_home(manage_home) - r.password(password) - r.system(system) - r - end - - let(:expected_shadow) do - if ohai[:platform] == "aix" - 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) - user_resource.should be_updated_by_last_action - end - - - it "ensures the user exists" do - pw_entry.name.should == username - end - - # On Debian, the only constraints are that usernames must neither start - # with a dash ('-') nor plus ('+') nor tilde ('~') nor contain a colon - # (':'), a comma (','), or a whitespace (space: ' ', end of line: '\n', - # 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 - - let(:username) { "t'bilisi" } - - it "ensures the user exists" do - pw_entry.name.should == username - end - end - - - context "when uid is set" do - # Should verify uid not in use... - let(:uid) { 1999 } - - it "ensures the user has the given uid" do - pw_entry.uid.should == "1999" - end - end - - context "when comment is set" do - let(:comment) { "hello this is dog" } - - it "ensures the comment is set" do - pw_entry.gecos.should == "hello this is dog" - end - - context "in standard gecos format" do - let(:comment) { "Bobo T. Clown,some building,555-555-5555,@boboclown" } - - it "ensures the comment is set" do - pw_entry.gecos.should == comment - end - end - - context "to a string containing multibyte characters" do - let(:comment) { "(╯°□°)╯︵ ┻━┻" } - - it "ensures the comment is set" do - actual = pw_entry.gecos - actual.force_encoding(Encoding::UTF_8) if "".respond_to?(:force_encoding) - actual.should == comment - end - end - - context "to a string containing an apostrophe `'`" do - let(:comment) { "don't go" } - - it "ensures the comment is set" do - pw_entry.gecos.should == comment - end - end - end - - context "when home is set" do - let(:home) { "/home/#{username}" } - - it "ensures the user's home is set to the given path" do - pw_entry.home.should == "/home/#{username}" - end - - if %w{rhel fedora}.include?(OHAI_SYSTEM["platform_family"]) - # Inconsistent behavior. See: CHEF-2205 - it "creates the home dir when not explicitly asked to on RHEL (XXX)" do - File.should exist("/home/#{username}") - end - else - it "does not create the home dir without `manage_home'" do - File.should_not exist("/home/#{username}") - end - end - - context "and manage_home is enabled" do - let(:manage_home) { true } - - it "ensures the user's home directory exists" do - File.should exist("/home/#{username}") - end - end - end - - context "when a password is specified" do - # openssl passwd -1 "secretpassword" - let(:password) do - case ohai[:platform] - when "aix" - "eL5qfEVznSNss" - else - "$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/" - end - end - - it "sets the user's shadow password" do - password_should_be_set - etc_shadow.should include(expected_shadow) - end - end - - context "when a system user is specified" do - let(:system) { true } - 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 - 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 } - uid_min_scan = /^UID_MIN\s+(\d+)/ - login_defs.match(uid_min_scan)[1] - end - end - - it "ensures the user has the properties of a system user" do - pw_entry.uid.to_i.should be < uid_min.to_i - end - end - end # when the user does not exist beforehand - - context "when the user already exists" do - - let(:expect_updated?) { true } - - let(:existing_uid) { nil } - let(:existing_home) { nil } - let(:existing_manage_home) { false } - let(:existing_password) { nil } - let(:existing_system) { false } - let(:existing_comment) { nil } - - let(:existing_user) do - r = Chef::Resource::User.new("TEST USER RESOURCE", run_context) - # username is identity attr, must match. - r.username(username) - r.uid(existing_uid) - r.home(existing_home) - r.comment(existing_comment) - r.manage_home(existing_manage_home) - r.password(existing_password) - r.system(existing_system) - r - end - - before do - if reason = skip - pending(reason) - end - existing_user.run_action(:create) - existing_user.should be_updated_by_last_action - user_resource.run_action(:create) - user_resource.updated_by_last_action?.should == expect_updated? - end - - context "and all properties are in the desired state" do - let(:uid) { 1999 } - let(:home) { "/home/bobo" } - let(:manage_home) { true } - # openssl passwd -1 "secretpassword" - let(:password) do - case ohai[:platform] - when "aix" - "eL5qfEVznSNss" - else - "$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/" - end - end - - let(:system) { false } - let(:comment) { "hello this is dog" } - - let(:existing_uid) { uid } - let(:existing_home) { home } - let(:existing_manage_home) { manage_home } - let(:existing_password) { password } - let(:existing_system) { false } - let(:existing_comment) { comment } - - let(:expect_updated?) { false } - - it "does not update the user" do - user_resource.should_not be_updated - end - end - - context "and the uid is updated" do - let(:uid) { 1999 } - let(:existing_uid) { 1998 } - - it "ensures the uid is set to the desired value" do - pw_entry.uid.should == "1999" - end - end - - context "and the comment is updated" do - let(:comment) { "hello this is dog" } - let(:existing_comment) { "woof" } - - it "ensures the comment field is set to the desired value" do - pw_entry.gecos.should == "hello this is dog" - end - end - - context "and home directory is updated" do - let(:existing_home) { "/home/foo" } - let(:home) { "/home/bar" } - it "ensures the home directory is set to the desired value" do - pw_entry.home.should == "/home/bar" - end - - context "and manage_home is enabled" do - let(:existing_manage_home) { true } - let(:manage_home) { true } - it "moves the home directory to the new location" do - File.should_not exist("/home/foo") - File.should exist("/home/bar") - end - end - - context "and manage_home wasn't enabled but is now" do - let(:existing_manage_home) { false } - let(:manage_home) { true } - - if %w{rhel fedora}.include?(OHAI_SYSTEM["platform_family"]) - # Inconsistent behavior. See: CHEF-2205 - it "created the home dir b/c of CHEF-2205 so it still exists" do - # This behavior seems contrary to expectation and non-convergent. - File.should_not exist("/home/foo") - File.should exist("/home/bar") - end - elsif ohai[:platform] == "aix" - it "creates the home dir in the desired location" do - File.should_not exist("/home/foo") - File.should exist("/home/bar") - end - else - it "does not create the home dir in the desired location (XXX)" do - # This behavior seems contrary to expectation and non-convergent. - File.should_not exist("/home/foo") - File.should_not exist("/home/bar") - end - end - end - - context "and manage_home was enabled but is not now" do - let(:existing_manage_home) { true } - let(:manage_home) { false } - - it "leaves the old home directory around (XXX)" do - # Would it be better to remove the old home? - File.should exist("/home/foo") - File.should_not exist("/home/bar") - end - end - end - - context "and a password is added" do - # openssl passwd -1 "secretpassword" - let(:password) do - case ohai[:platform] - when "aix" - "eL5qfEVznSNss" - else - "$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/" - end - end - - - it "ensures the password is set" do - password_should_be_set - etc_shadow.should include(expected_shadow) - end - - end - - context "and the password is updated" do - # openssl passwd -1 "OLDpassword" - let(:existing_password) do - case ohai[:platform] - when "aix" - "jkzG6MvUxjk2g" - else - "$1$1dVmwm4z$CftsFn8eBDjDRUytYKkXB." - end - end - - # openssl passwd -1 "secretpassword" - let(:password) do - case ohai[:platform] - when "aix" - "eL5qfEVznSNss" - else - "$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/" - end - end - - - it "ensures the password is set to the desired value" do - password_should_be_set - etc_shadow.should include(expected_shadow) - end - end - - context "and the user is changed from not-system to system" do - let(:existing_system) { false } - let(:system) { true } - - let(:expect_updated?) { false } - - it "does not modify the user at all" do - end - end - - context "and the user is changed from system to not-system" do - let(:existing_system) { true } - let(:system) { false } - - let(:expect_updated?) { false } - - it "does not modify the user at all" do - end - end - - end # when the user already exists - end # action :create - - shared_context "user exists for lock/unlock" do - let(:user_locked_context?) { false } - - def shadow_entry - etc_shadow.lines.select {|l| l.include?(username) }.first - end - - def shadow_password - 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] - end - - def user_account_should_be_locked - case ohai[:platform] - when "aix" - aix_user_lock_status.should == "true" - else - shadow_password.should include("!") - end - end - - def user_account_should_be_unlocked - case ohai[:platform] - when "aix" - aix_user_lock_status.should == "false" - else - shadow_password.should_not include("!") - end - end - - def lock_user_account - case ohai[:platform] - when "aix" - shell_out!("chuser account_locked=true #{username}") - else - shell_out!("usermod -L #{username}") - end - end - - before do - # create user and setup locked/unlocked state - user_resource.dup.run_action(:create) - - if user_locked_context? - lock_user_account - user_account_should_be_locked - elsif password - user_account_should_be_unlocked - end - end - end - - describe "action :lock" do - context "when the user does not exist" do - it "raises a sensible error" do - expect { user_resource.run_action(:lock) }.to raise_error(Chef::Exceptions::User) - end - end - - context "when the user exists" do - - include_context "user exists for lock/unlock" - - before do - user_resource.run_action(:lock) - end - - context "and the user is not locked" do - # user will be locked if it has no password - let(:password) do - case ohai[:platform] - when "aix" - "eL5qfEVznSNss" - else - "$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/" - end - end - - - it "locks the user's password" do - user_account_should_be_locked - end - end - - context "and the user is locked" do - # user will be locked if it has no password - let(:password) do - case ohai[:platform] - when "aix" - "eL5qfEVznSNss" - else - "$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/" - end - end - - let(:user_locked_context?) { true } - it "does not update the user" do - user_resource.should_not be_updated_by_last_action - end - end - end - end # action :lock - - describe "action :unlock" do - context "when the user does not exist" do - it "raises a sensible error" do - expect { user_resource.run_action(:unlock) }.to raise_error(Chef::Exceptions::User) - end - end - - context "when the user exists" do - - include_context "user exists for lock/unlock" - - before do - begin - user_resource.run_action(:unlock) - @error = nil - rescue Exception => e - @error = e - end - end - - 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"]) - # suse gets this right: - it "errors out trying to unlock the user" do - @error.should be_a(Mixlib::ShellOut::ShellCommandFailed) - @error.message.should include("Cannot unlock the password") - end - else - - # borked on all other platforms: - it "is marked as updated but doesn't modify the user (XXX)" do - # This should be an error instead; note that usermod still exits 0 - # (which is probably why this case silently fails): - # - # DEBUG: ---- Begin output of usermod -U chef-functional-test ---- - # DEBUG: STDOUT: - # DEBUG: STDERR: usermod: unlocking the user's password would result in a passwordless account. - # You should set a password with usermod -p to unlock this user's password. - # DEBUG: ---- End output of usermod -U chef-functional-test ---- - # DEBUG: Ran usermod -U chef-functional-test returned 0 - @error.should be_nil - if ohai[:platform] == "aix" - pw_entry.passwd.should == '*' - user_account_should_be_unlocked - else - pw_entry.passwd.should == 'x' - shadow_password.should include("!") - end - end - end - end - - context "and has a password" do - let(:password) do - case ohai[:platform] - when "aix" - "eL5qfEVznSNss" - else - "$1$RRa/wMM/$XltKfoX5ffnexVF4dHZZf/" - end - end - - context "and the user is not locked" do - it "does not update the user" do - user_resource.should_not be_updated_by_last_action - end - end - - context "and the user is locked" do - let(:user_locked_context?) { true } - - it "unlocks the user's password" do - user_account_should_be_unlocked - end - end - end - end - end # action :unlock - -end diff --git a/spec/functional/rest_spec.rb b/spec/functional/rest_spec.rb deleted file mode 100644 index 7c6b1872ef..0000000000 --- a/spec/functional/rest_spec.rb +++ /dev/null @@ -1,94 +0,0 @@ -# -# Author:: Lamont Granquist (<lamont@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 'tiny_server' -require 'support/shared/functional/http' - -describe Chef::REST do - include ChefHTTPShared - - let(:http_client) { described_class.new(source) } - let(:http_client_disable_gzip) { described_class.new(source, Chef::Config[:node_name], Chef::Config[:client_key], { :disable_gzip => true } ) } - - shared_examples_for "downloads requests correctly" do - it "successfully downloads a streaming request" do - tempfile = http_client.streaming_request(source, {}) - tempfile.close - expect(Digest::MD5.hexdigest(binread(tempfile.path))).to eq(Digest::MD5.hexdigest(expected_content)) - end - - it "successfully downloads a GET request" do - tempfile = http_client.get(source, {}) - tempfile.close - expect(Digest::MD5.hexdigest(binread(tempfile.path))).to eq(Digest::MD5.hexdigest(expected_content)) - end - end - - shared_examples_for "validates content length and throws an exception" do - it "fails validation on a streaming download" do - expect { http_client.streaming_request(source, {}) }.to raise_error(Chef::Exceptions::ContentLengthMismatch) - end - - it "fails validation on a GET request" do - expect { http_client.get(source, {}) }.to raise_error(Chef::Exceptions::ContentLengthMismatch) - end - end - - shared_examples_for "an endpoint that 403s" do - it "fails with a Net::HTTPServerException on a streaming download" do - expect { http_client.streaming_request(source, {}) }.to raise_error(Net::HTTPServerException) - end - - it "fails with a Net::HTTPServerException on a GET request" do - expect { http_client.get(source, {}) }.to raise_error(Net::HTTPServerException) - end - end - - # see CHEF-5100 - shared_examples_for "a 403 after a successful request when reusing the request object" do - it "fails with a Net::HTTPServerException on a streaming download" do - tempfile = http_client.streaming_request(source, {}) - tempfile.close - expect(Digest::MD5.hexdigest(binread(tempfile.path))).to eq(Digest::MD5.hexdigest(expected_content)) - expect { http_client.streaming_request(source2, {}) }.to raise_error(Net::HTTPServerException) - end - - it "fails with a Net::HTTPServerException on a GET request" do - tempfile = http_client.get(source, {}) - tempfile.close - expect(Digest::MD5.hexdigest(binread(tempfile.path))).to eq(Digest::MD5.hexdigest(expected_content)) - expect { http_client.get(source2, {}) }.to raise_error(Net::HTTPServerException) - end - end - - before do - Chef::Config[:node_name] = "webmonkey.example.com" - Chef::Config[:client_key] = CHEF_SPEC_DATA + "/ssl/private_key.pem" - end - - before(:all) do - start_tiny_server - end - - after(:all) do - stop_tiny_server - end - - it_behaves_like "downloading all the things" -end diff --git a/spec/functional/run_lock_spec.rb b/spec/functional/run_lock_spec.rb deleted file mode 100644 index 9eec0dab04..0000000000 --- a/spec/functional/run_lock_spec.rb +++ /dev/null @@ -1,286 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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 File.expand_path('../../spec_helper', __FILE__) -require 'chef/client' - -describe Chef::RunLock do - - # This behavior works on windows, but the tests use fork :( - describe "when locking the chef-client run", :unix_only => true do - - ## - # Lockfile location and helpers - - let(:random_temp_root) do - Kernel.srand(Time.now.to_i + Process.pid) - "/tmp/#{Kernel.rand(Time.now.to_i + Process.pid)}" - end - - 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) } - - 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 - 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] - 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? - 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 - - # 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 - begin - # ArgumentError from Marshal.load indicates no data, which we assume - # means no error in child process. - raise Marshal.load(err) - rescue ArgumentError - nil - 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 - 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 - lambda { run_lock.acquire }.should_not raise_error - File.should exist(lockfile) - end - - it "sets FD_CLOEXEC on the lockfile", :supports_cloexec => true do - run_lock.acquire - (run_lock.runlock.fcntl(Fcntl::F_GETFD, 0) & Fcntl::FD_CLOEXEC).should == 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) - 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) - end - - Process.waitpid2(p1) - Process.waitpid2(p2) - - raise_side_channel_error! - - expected=<<-E -p1 has lock -p1 releasing lock -p2 has lock -E - results.should == 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 - 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 - end - - Process.waitpid2(p2) - - results.should =~ /p2 has lock\Z/ - end - - it "test returns true and acquires the lock" do - p1 = fork do - run_lock.test.should == true - sleep 2 - exit! 1 - end - - wait_on_lock - - p2 = fork do - run_lock.test.should == false - exit! 0 - end - - Process.waitpid2(p2) - Process.waitpid2(p1) - end - - it "test returns without waiting when the lock is acquired" do - p1 = fork do - run_lock.acquire - sleep 2 - exit! 1 - end - - wait_on_lock - - run_lock.test.should == false - 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 - - wait_on_lock - sleep 0.5 # Possible race condition on Solaris which pid is observed as 0 - File.read(lockfile).should == p1.to_s - - Process.waitpid2(p1) - end - - end -end diff --git a/spec/functional/shell_spec.rb b/spec/functional/shell_spec.rb deleted file mode 100644 index f2ce3f53e4..0000000000 --- a/spec/functional/shell_spec.rb +++ /dev/null @@ -1,132 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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 'functional/resource/base' -require 'chef/version' -require 'chef/shell' -require 'chef/mixin/command/unix' - -describe Shell do - - # chef-shell's unit tests are by necessity very mock-heavy, and frequently do - # not catch cases where chef-shell fails to boot because of changes in - # chef/client.rb - describe "smoke tests", :unix_only => true do - include Chef::Mixin::Command::Unix - - def read_until(io, expected_value) - start = Time.new - buffer = "" - until buffer.include?(expected_value) - begin - buffer << io.read_nonblock(1) - 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 - end - end - buffer - end - - def wait_or_die(pid) - start = Time.new - - until exitstatus = Process.waitpid2(pid, Process::WNOHANG) - if Time.new - start > 5 - STDERR.puts("chef-shell tty did not exit cleanly, killing it") - Process.kill(:KILL, pid) - end - sleep 0.01 - end - exitstatus[1] - end - - def run_chef_shell_with(options) - case ohai[:platform] - when "aix" - config = File.expand_path("shef-config.rb", CHEF_SPEC_DATA) - path_to_chef_shell = File.expand_path("../../../bin/chef-shell", __FILE__) - output = '' - status = popen4("#{path_to_chef_shell} -c #{config} #{options}", :waitlast => true) do |pid, stdin, stdout, stderr| - read_until(stdout, "chef >") - yield stdout, stdin if block_given? - stdin.write("'done'\n") - output = read_until(stdout, '=> "done"') - stdin.print("exit\n") - read_until(stdout, "\n") - end - - [output, status.exitstatus] - else - # Windows ruby installs don't (always?) have PTY, - # so hide the require here - begin - 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 >") - 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") - writer.close - - exitstatus = wait_or_die(pid) - - [output, exitstatus] - rescue PTY::ChildExited => e - [output, e.status] - end - end - end - - it "boots correctly with -lauto" do - output, exitstatus = run_chef_shell_with("-lauto") - output.should include("done") - expect(exitstatus).to eq(0) - end - - it "sets the log_level from the command line" do - output, exitstatus = run_chef_shell_with("-lfatal") do |out, keyboard| - show_log_level_code = %q[puts "===#{Chef::Log.level}==="] - keyboard.puts(show_log_level_code) - read_until(out, show_log_level_code) - end - output.should include("===fatal===") - expect(exitstatus).to eq(0) - end - - it "sets the override_runlist from the command line" do - output, exitstatus = run_chef_shell_with("-o 'override::foo,override::bar'") do |out, keyboard| - show_recipes_code = %q[puts "#{node.recipes.inspect}"] - keyboard.puts(show_recipes_code) - read_until(out, show_recipes_code) - end - output.should include(%q{["override::foo", "override::bar"]}) - expect(exitstatus).to eq(0) - end - end -end diff --git a/spec/functional/tiny_server_spec.rb b/spec/functional/tiny_server_spec.rb deleted file mode 100644 index bfa6ff1ddb..0000000000 --- a/spec/functional/tiny_server_spec.rb +++ /dev/null @@ -1,78 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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. -# - -require 'spec_helper' -require 'tiny_server' - -describe TinyServer::API do - before do - @api = TinyServer::API.instance - @api.clear - end - - it "is a Singleton" do - lambda {TinyServer::API.new}.should raise_error - end - - it "clears the router" do - @api.get('/blargh', 200, "blargh") - @api.clear - @api.routes["GET"].should be_empty - end - - it "creates a route for a GET request" do - @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') - response.should == [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') - response.should == [200, {'Content-Type' => 'application/json'}, [ 'hello barbaz' ]] - block_called.should be_true - end - - it "returns debugging info for 404s" do - response = @api.call("REQUEST_METHOD" => "GET", "REQUEST_URI" => '/no_such_thing') - response[0].should == 404 - response[1].should == {'Content-Type' => 'application/json'} - response[2].should be_a_kind_of(Array) - response_obj = Chef::JSONCompat.from_json(response[2].first) - response_obj["message"].should == "no data matches the request for /no_such_thing" - response_obj["available_routes"].should == {"GET"=>[], "PUT"=>[], "POST"=>[], "DELETE"=>[]} - response_obj["request"].should == {"REQUEST_METHOD"=>"GET", "REQUEST_URI"=>"/no_such_thing"} - end - -end - -describe TinyServer::Manager do - it "runs the server" do - @server = TinyServer::Manager.new - @server.start - - TinyServer::API.instance.get("/index", 200, "[\"hello\"]") - - rest = Chef::REST.new('http://localhost:9000', false, false) - rest.get_rest("index").should == ["hello"] - - @server.stop - end -end diff --git a/spec/functional/util/path_helper_spec.rb b/spec/functional/util/path_helper_spec.rb deleted file mode 100644 index ccdf383c22..0000000000 --- a/spec/functional/util/path_helper_spec.rb +++ /dev/null @@ -1,37 +0,0 @@ -# -# 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 'tmpdir' -require 'chef/util/path_helper' -require 'spec_helper' - -describe Chef::Util::PathHelper, "escape_glob" do - PathHelper = Chef::Util::PathHelper - - it "escapes the glob metacharacters so globbing succeeds" do - # make a dir - Dir.mktmpdir("\\silly[dir]") do |dir| - # add some files - files = ["some.rb", "file.txt", "names.csv"] - files.each do |file| - File.new(File.join(dir, file), 'w').close - end - - pattern = File.join(PathHelper.escape_glob(dir), "*") - Dir.glob(pattern).map { |x| File.basename(x) }.should match_array(files) - end - end -end diff --git a/spec/functional/util/powershell/cmdlet_spec.rb b/spec/functional/util/powershell/cmdlet_spec.rb deleted file mode 100644 index 63d1ac09b5..0000000000 --- a/spec/functional/util/powershell/cmdlet_spec.rb +++ /dev/null @@ -1,114 +0,0 @@ -# -# Author:: Adam Edwards (<adamed@getchef.com>) -# -# 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. -# - -require 'json' -require File.expand_path('../../../../spec_helper', __FILE__) - -describe Chef::Util::Powershell::Cmdlet, :windows_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, {}) - 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(:etc_directory) { "#{ENV['systemroot']}\\system32\\drivers\\etc" } - let(:architecture_cmdlet) { Chef::Util::Powershell::Cmdlet.new(@node, "$env:PROCESSOR_ARCHITECTURE")} - - it "executes a simple process" do - result = simple_cmdlet.run - expect(result.succeeded?).to eq(true) - end - - it "#run does not raise a PowershellCmdletException exception if the command cannot be executed" do - 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) - end - - it "executes a 64-bit command on a 64-bit OS, 32-bit otherwise" do - os_arch = ENV['PROCESSOR_ARCHITEW6432'] - if os_arch.nil? - os_arch = ENV['PROCESSOR_ARCHITECTURE'] - end - - result = architecture_cmdlet.run - execution_arch = result.return_value - execution_arch.strip! - expect(execution_arch).to eq(os_arch) - end - - it "passes command line switches to the command" do - 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') - 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') - expect(result.succeeded?).to eq(true) - returned_directory = result.return_value - returned_directory.strip! - expect(returned_directory).to eq(etc_directory) - 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') - expect(result.succeeded?).to eq(true) - returned_directory = result.return_value - returned_directory.strip! - expect(returned_directory).to eq(etc_directory) - end - - context "when returning json" do - let(:cmd_output_format) { :json } - it "returns json format data", :windows_powershell_dsc_only do - result = cmdlet_alias_requires_switch_or_argument.run({},{},'ls') - expect(result.succeeded?).to eq(true) - expect(lambda{JSON.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", :windows_powershell_dsc_only do - result = simple_cmdlet.run({},{:cwd => etc_directory}, 'hosts') - expect(result.succeeded?).to eq(true) - data = result.return_value - 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 - end - end -end diff --git a/spec/functional/version_spec.rb b/spec/functional/version_spec.rb deleted file mode 100644 index a342206161..0000000000 --- a/spec/functional/version_spec.rb +++ /dev/null @@ -1,35 +0,0 @@ -# -# Author:: Serdar Sutay (<dan@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 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 - let(:chef_dir) { File.join(File.dirname(__FILE__), "..", "..") } - - binaries = [ "chef-client", "chef-shell", "chef-apply", "knife", "chef-solo" ] - - binaries.each do |binary| - it "#{binary} version should be sane" do - shell_out!("ruby #{File.join("bin", binary)} -v", :cwd => chef_dir).stdout.chomp.should == "Chef: #{Chef::VERSION}" - end - end - -end diff --git a/spec/functional/win32/registry_helper_spec.rb b/spec/functional/win32/registry_helper_spec.rb deleted file mode 100644 index 830d6f4777..0000000000 --- a/spec/functional/win32/registry_helper_spec.rb +++ /dev/null @@ -1,632 +0,0 @@ -# -# Author:: Prajakta Purohit (<prajakta@opscode.com>) -# Author:: Lamont Granquist (<lamont@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"}]) - lambda{@resource.run_action(:create)}.should 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 - @registry.hive_exists?("HKCU\\Software\\Root").should == true - end - - it "returns false if the hive does not exist" do - hive = @registry.hive_exists?("LYRU\\Software\\Root").should == false - end - end - - describe "key_exists?" do - it "returns true if the key path exists" do - @registry.key_exists?("HKCU\\Software\\Root\\Branch\\Flower").should == true - end - - it "returns false if the key path does not exist" do - @registry.key_exists?("HKCU\\Software\\Branch\\Flower").should == false - end - - it "throws an exception if the hive does not exist" do - lambda {@registry.key_exists?("JKLM\\Software\\Branch\\Flower")}.should raise_error(Chef::Exceptions::Win32RegHiveMissing) - end - end - - describe "key_exists!" do - it "returns true if the key path exists" do - @registry.key_exists!("HKCU\\Software\\Root\\Branch\\Flower").should == true - end - - it "throws an exception if the key path does not exist" do - lambda {@registry.key_exists!("HKCU\\Software\\Branch\\Flower")}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) - end - - it "throws an exception if the hive does not exist" do - lambda {@registry.key_exists!("JKLM\\Software\\Branch\\Flower")}.should raise_error(Chef::Exceptions::Win32RegHiveMissing) - end - end - - describe "value_exists?" do - it "throws an exception if the hive does not exist" do - lambda {@registry.value_exists?("JKLM\\Software\\Branch\\Flower", {:name=>"Petals"})}.should raise_error(Chef::Exceptions::Win32RegHiveMissing) - end - it "throws an exception if the key does not exist" do - lambda {@registry.value_exists?("HKCU\\Software\\Branch\\Flower", {:name=>"Petals"})}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) - end - it "returns true if the value exists" do - @registry.value_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals"}).should == true - end - it "returns false if the value does not exist" do - @registry.value_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"FOOBAR"}).should == false - end - end - - describe "value_exists!" do - it "throws an exception if the hive does not exist" do - lambda {@registry.value_exists!("JKLM\\Software\\Branch\\Flower", {:name=>"Petals"})}.should raise_error(Chef::Exceptions::Win32RegHiveMissing) - end - it "throws an exception if the key does not exist" do - lambda {@registry.value_exists!("HKCU\\Software\\Branch\\Flower", {:name=>"Petals"})}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) - end - it "returns true if the value exists" do - @registry.value_exists!("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals"}).should == true - end - it "throws an exception if the value does not exist" do - lambda {@registry.value_exists!("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"FOOBAR"})}.should raise_error(Chef::Exceptions::Win32RegValueMissing) - end - end - - describe "data_exists?" do - it "throws an exception if the hive does not exist" do - lambda {@registry.data_exists?("JKLM\\Software\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Pink", "Delicate"]})}.should raise_error(Chef::Exceptions::Win32RegHiveMissing) - end - it "throws an exception if the key does not exist" do - lambda {@registry.data_exists?("HKCU\\Software\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Pink", "Delicate"]})}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) - end - it "returns true if all the data matches" do - @registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Pink", "Delicate"]}).should == true - end - it "returns false if the name does not exist" do - @registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"slateP", :type=>:multi_string, :data=>["Pink", "Delicate"]}).should == false - end - it "returns false if the types do not match" do - @registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:string, :data=>"Pink"}).should == false - end - it "returns false if the data does not match" do - @registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Mauve", "Delicate"]}).should == false - end - end - - describe "data_exists!" do - it "throws an exception if the hive does not exist" do - lambda {@registry.data_exists!("JKLM\\Software\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Pink", "Delicate"]})}.should raise_error(Chef::Exceptions::Win32RegHiveMissing) - end - it "throws an exception if the key does not exist" do - lambda {@registry.data_exists!("HKCU\\Software\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Pink", "Delicate"]})}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) - end - it "returns true if all the data matches" do - @registry.data_exists!("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Pink", "Delicate"]}).should == true - end - it "throws an exception if the name does not exist" do - lambda {@registry.data_exists!("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"slateP", :type=>:multi_string, :data=>["Pink", "Delicate"]})}.should raise_error(Chef::Exceptions::Win32RegDataMissing) - end - it "throws an exception if the types do not match" do - lambda {@registry.data_exists!("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:string, :data=>"Pink"})}.should raise_error(Chef::Exceptions::Win32RegDataMissing) - end - it "throws an exception if the data does not match" do - lambda {@registry.data_exists!("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Mauve", "Delicate"]})}.should 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") - values.should be_an_instance_of Array - values.should == [{: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 - lambda {@registry.get_values("HKCU\\Software\\Branch\\Flower")}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) - end - - it "throws an exception if the hive does not exist" do - lambda {@registry.get_values("JKLM\\Software\\Branch\\Flower")}.should 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 - @registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Yellow", "Changed Color"]}).should == true - @registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Yellow", "Changed Color"]}).should == true - end - - it "updates a value if the type does match and the values are different" do - @registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:string, :data=>"Yellow"}).should == true - @registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:string, :data=>"Yellow"}).should == true - @registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Yellow", "Changed Color"]}).should == false - end - - it "creates a value if key exists and value does not" do - @registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Stamen", :type=>:multi_string, :data=>["Yellow", "Changed Color"]}).should == true - @registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Stamen", :type=>:multi_string, :data=>["Yellow", "Changed Color"]}).should == true - end - - it "does nothing if data,type and name parameters for the value are same" do - @registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Stamen", :type=>:multi_string, :data=>["Yellow", "Changed Color"]}).should == false - @registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"Stamen", :type=>:multi_string, :data=>["Yellow", "Changed Color"]}).should == true - end - - it "throws an exception if the key does not exist" do - lambda {@registry.set_value("HKCU\\Software\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Yellow", "Changed Color"]})}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) - end - - it "throws an exception if the hive does not exist" do - lambda {@registry.set_value("JKLM\\Software\\Root\\Branch\\Flower", {:name=>"Petals", :type=>:multi_string, :data=>["Yellow", "Changed Color"]})}.should 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 - @registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBe32767", :type=>:dword, :data=>"32767"}).should == true - @registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBe32767", :type=>:dword, :data=>32767}).should == true - end - - it "casts a nonsense string given as a dword into zero" do - @registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBeZero", :type=>:dword, :data=>"whatdoesthisdo"}).should == true - @registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBeZero", :type=>:dword, :data=>0}).should == true - end - - it "throws an exception when trying to cast an array to an int for a dword" do - lambda {@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldThrow", :type=>:dword, :data=>["one","two"]})}.should 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 - @registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBePainful", :type=>:string, :data=>["one","two"]}).should == true - @registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBePainful", :type=>:string, :data=>'["one", "two"]'}).should == true - end - - it "stores the string representation of a number into a string if you pass it an number" do - @registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBe65535", :type=>:string, :data=>65535}).should == true - @registry.data_exists?("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBe65535", :type=>:string, :data=>"65535"}).should == 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 - lambda {@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldThrow", :type=>:multi_string, :data=>65535})}.should raise_error - end - - it "throws an exception when a multi-string is passed a string" do - lambda {@registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", {:name=>"ShouldBeWat", :type=>:multi_string, :data=>"foo"})}.should 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 - lambda {@registry.create_key("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", false)}.should raise_error(Chef::Exceptions::Win32RegNoRecursive) - @registry.key_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker").should == false - end - - it "creates the key_path if the keys were missing but recursive was set to true" do - @registry.create_key("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", true).should == true - @registry.key_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker").should == true - end - - it "does nothing if the key already exists" do - @registry.create_key("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", false).should == true - @registry.key_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker").should == true - end - - it "throws an exception of the hive does not exist" do - lambda {@registry.create_key("JKLM\\Software\\Root\\Trunk\\Peck\\Woodpecker", false)}.should 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 - @registry.delete_value("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", {:name=>"Peter", :type=>:string, :data=>"Tiny"}).should == true - @registry.value_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", {:name=>"Peter", :type=>:string, :data=>"Tiny"}).should == false - end - - it "does nothing if value does not exist" do - @registry.delete_value("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", {:name=>"Peter", :type=>:string, :data=>"Tiny"}).should == true - @registry.value_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker", {:name=>"Peter", :type=>:string, :data=>"Tiny"}).should == false - end - - it "throws an exception if the key does not exist?" do - lambda {@registry.delete_value("HKCU\\Software\\Trunk\\Peck\\Woodpecker", {:name=>"Peter", :type=>:string, :data=>"Tiny"})}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) - end - - it "throws an exception if the hive does not exist" do - lambda {@registry.delete_value("JKLM\\Software\\Root\\Trunk\\Peck\\Woodpecker", {:name=>"Peter", :type=>:string, :data=>"Tiny"})}.should 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 - @registry.delete_key("HKCU\\Software\\Root\\Branch\\Fruit", false).should == true - @registry.key_exists?("HKCU\\Software\\Root\\Branch\\Fruit").should == false - end - - it "throws an exception if key to delete has subkeys and recursive is false" do - lambda { @registry.delete_key("HKCU\\Software\\Root\\Trunk", false) }.should raise_error(Chef::Exceptions::Win32RegNoRecursive) - @registry.key_exists?("HKCU\\Software\\Root\\Trunk\\Peck\\Woodpecker").should == true - end - - it "deletes a key if it has subkeys and recursive true" do - @registry.delete_key("HKCU\\Software\\Root\\Trunk", true).should == true - @registry.key_exists?("HKCU\\Software\\Root\\Trunk").should == false - end - - it "does nothing if the key does not exist" do - @registry.delete_key("HKCU\\Software\\Root\\Trunk", true).should == true - @registry.key_exists?("HKCU\\Software\\Root\\Trunk").should == false - end - - it "throws an exception if the hive does not exist" do - lambda {@registry.delete_key("JKLM\\Software\\Root\\Branch\\Flower", false)}.should 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 - lambda {@registry.has_subkeys?("LMNO\\Software\\Root")}.should raise_error(Chef::Exceptions::Win32RegHiveMissing) - end - - it "throws an exception if the key is missing" do - lambda {@registry.has_subkeys?("HKCU\\Software\\Root\\Trunk\\Red")}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) - end - - it "returns true if the key has subkeys" do - @registry.has_subkeys?("HKCU\\Software\\Root").should == true - end - - it "returns false if the key has no subkeys" do - ::Win32::Registry::HKEY_CURRENT_USER.create "Software\\Root\\Trunk\\Red" - @registry.has_subkeys?("HKCU\\Software\\Root\\Trunk\\Red").should == false - end - end - - describe "get_subkeys" do - it "throws an exception if the key is missing" do - lambda {@registry.get_subkeys("HKCU\\Software\\Trunk\\Red")}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) - end - it "throws an exception if the hive does not exist" do - lambda {@registry.get_subkeys("JKLM\\Software\\Root")}.should 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 - reg_subkeys.should == 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 - lambda {Chef::Win32::Registry.new(@run_context, :x86_64)}.should 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) - @r.architecture.should == :i386 - @r.registry_system_architecture.should == 0x0200 - end - - it "can correctly set the requested architecture to :machine" do - @r = Chef::Win32::Registry.new(@run_context, :machine) - @r.architecture.should == :machine - @r.registry_system_architecture.should == 0x0200 - end - end - - context "architecture setter" do - it "throws an exception if requested architecture is 64bit but running on 32bit" do - lambda {@registry.architecture = :x86_64}.should raise_error(Chef::Exceptions::Win32RegArchitectureIncorrect) - end - - it "sets the requested architecture to :machine if passed :machine" do - @registry.architecture = :machine - @registry.architecture.should == :machine - @registry.registry_system_architecture.should == 0x0200 - end - - it "sets the requested architecture to 32-bit if passed i386 as a string" do - @registry.architecture = :i386 - @registry.architecture.should == :i386 - @registry.registry_system_architecture.should == 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) - @r.architecture.should == :i386 - @r.registry_system_architecture.should == 0x0200 - end - - it "can correctly set the requested architecture to 64-bit" do - @r = Chef::Win32::Registry.new(@run_context, :x86_64) - @r.architecture.should == :x86_64 - @r.registry_system_architecture.should == 0x0100 - end - - it "can correctly set the requested architecture to :machine" do - @r = Chef::Win32::Registry.new(@run_context, :machine) - @r.architecture.should == :machine - @r.registry_system_architecture.should == 0x0100 - end - end - - context "architecture setter" do - it "sets the requested architecture to 64-bit if passed 64-bit" do - @registry.architecture = :x86_64 - @registry.architecture.should == :x86_64 - @registry.registry_system_architecture.should == 0x0100 - end - - it "sets the requested architecture to :machine if passed :machine" do - @registry.architecture = :machine - @registry.architecture.should == :machine - @registry.registry_system_architecture.should == 0x0100 - end - - it "sets the requested architecture to 32-bit if passed 32-bit" do - @registry.architecture = :i386 - @registry.architecture.should == :i386 - @registry.registry_system_architecture.should == 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 - @registry.key_exists?("HKLM\\Software\\Root\\Mauve").should == false - end - it "finds 32-bit keys in the 32-bit registry" do - @registry.architecture=:i386 - @registry.key_exists?("HKLM\\Software\\Root\\Poosh").should == true - end - it "does not find 32-bit keys in the 64-bit registry" do - @registry.architecture=:x86_64 - @registry.key_exists?("HKLM\\Software\\Root\\Mauve").should == true - end - it "finds 64-bit keys in the 64-bit registry" do - @registry.architecture=:x86_64 - @registry.key_exists?("HKLM\\Software\\Root\\Poosh").should == false - end - end - - describe "value_exists?" do - it "does not find 64-bit values in the 32-bit registry" do - @registry.architecture=:i386 - lambda{@registry.value_exists?("HKLM\\Software\\Root\\Mauve", {:name=>"Alert"})}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) - end - it "finds 32-bit values in the 32-bit registry" do - @registry.architecture=:i386 - @registry.value_exists?("HKLM\\Software\\Root\\Poosh", {:name=>"Status"}).should == true - end - it "does not find 32-bit values in the 64-bit registry" do - @registry.architecture=:x86_64 - @registry.value_exists?("HKLM\\Software\\Root\\Mauve", {:name=>"Alert"}).should == true - end - it "finds 64-bit values in the 64-bit registry" do - @registry.architecture=:x86_64 - lambda{@registry.value_exists?("HKLM\\Software\\Root\\Poosh", {:name=>"Status"})}.should 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 - lambda{@registry.data_exists?("HKLM\\Software\\Root\\Mauve", {:name=>"Alert", :type=>:string, :data=>"Universal"})}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) - end - it "finds 32-bit keys in the 32-bit registry" do - @registry.architecture=:i386 - @registry.data_exists?("HKLM\\Software\\Root\\Poosh", {:name=>"Status", :type=>:string, :data=>"Lost"}).should == true - end - it "does not find 32-bit keys in the 64-bit registry" do - @registry.architecture=:x86_64 - @registry.data_exists?("HKLM\\Software\\Root\\Mauve", {:name=>"Alert", :type=>:string, :data=>"Universal"}).should == true - end - it "finds 64-bit keys in the 64-bit registry" do - @registry.architecture=:x86_64 - lambda{@registry.data_exists?("HKLM\\Software\\Root\\Poosh", {:name=>"Status", :type=>:string, :data=>"Lost"})}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) - end - end - - describe "create_key" do - it "can create a 32-bit only registry key" do - @registry.architecture = :i386 - @registry.create_key("HKLM\\Software\\Root\\Trunk\\Red", true).should == true - @registry.key_exists?("HKLM\\Software\\Root\\Trunk\\Red").should == true - @registry.architecture = :x86_64 - @registry.key_exists?("HKLM\\Software\\Root\\Trunk\\Red").should == false - end - - it "can create a 64-bit only registry key" do - @registry.architecture = :x86_64 - @registry.create_key("HKLM\\Software\\Root\\Trunk\\Blue", true).should == true - @registry.key_exists?("HKLM\\Software\\Root\\Trunk\\Blue").should == true - @registry.architecture = :i386 - @registry.key_exists?("HKLM\\Software\\Root\\Trunk\\Blue").should == false - end - end - - end - end -end diff --git a/spec/functional/win32/security_spec.rb b/spec/functional/win32/security_spec.rb deleted file mode 100644 index 4ad9b07b74..0000000000 --- a/spec/functional/win32/security_spec.rb +++ /dev/null @@ -1,37 +0,0 @@ -# -# Author:: Serdar Sutay (<serdar@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' -if Chef::Platform.windows? - require 'chef/win32/security' -end - -describe 'Chef::Win32::Security', :windows_only do - it "has_admin_privileges? returns true when running as admin" do - Chef::ReservedNames::Win32::Security.has_admin_privileges?.should == true - end - - # We've done some investigation adding a negative test and it turned - # out to be a lot of work since mixlib-shellout doesn't have user - # support for windows. - # - # TODO - Add negative tests once mixlib-shellout has user support - it "has_admin_privileges? returns false when running as non-admin" do - pending "requires user support in mixlib-shellout" - end -end diff --git a/spec/functional/win32/service_manager_spec.rb b/spec/functional/win32/service_manager_spec.rb deleted file mode 100644 index b5b2e20825..0000000000 --- a/spec/functional/win32/service_manager_spec.rb +++ /dev/null @@ -1,275 +0,0 @@ -# -# Author:: Serdar Sutay (<serdar@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' -if Chef::Platform.windows? - require 'chef/application/windows_service_manager' -end - -# -# ATTENTION: -# This test creates a windows service for testing purposes and runs it -# as Local System on windows boxes. -# This test will fail if you run the tests inside a Windows VM by -# sharing the code from your host since Local System account by -# default can't see the mounted partitions. -# Run this test by copying the code to a local VM directory or setup -# Local System account to see the maunted partitions for the shared -# directories. -# - -describe "Chef::Application::WindowsServiceManager", :windows_only, :system_windows_service_gem_only do - - # Some helper methods. - - def test_service_exists? - ::Win32::Service.exists?("spec-service") - end - - def test_service_state - ::Win32::Service.status("spec-service").current_state - end - - def service_manager - Chef::Application::WindowsServiceManager.new(test_service) - end - - def cleanup - # Uninstall if the test service is installed. - if test_service_exists? - - # We can only uninstall when the service is stopped. - if test_service_state != "stopped" - ::Win32::Service.send("stop", "spec-service") - while test_service_state != "stopped" - sleep 1 - end - end - - ::Win32::Service.delete("spec-service") - end - - # Delete the test_service_file if it exists - if File.exists?(test_service_file) - File.delete(test_service_file) - end - - end - - - # Definition for the test-service - - let(:test_service) { - { - :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__), '../../support/platforms/win32/spec_service.rb')) - } - } - - # Test service creates a file for us to verify that it is running. - # Since our test service is running as Local System we should look - # for the file it creates under SYSTEM temp directory - - let(:test_service_file) { - "#{ENV['SystemDrive']}\\windows\\temp\\spec_service_file" - } - - context "with invalid service definition" do - it "throws an error when initialized with no service definition" do - lambda { Chef::Application::WindowsServiceManager.new(nil) }.should raise_error(ArgumentError) - end - - it "throws an error with required missing options" do - test_service.each do |key,value| - service_def = test_service.dup - service_def.delete(key) - - lambda { Chef::Application::WindowsServiceManager.new(service_def) }.should raise_error(ArgumentError) - end - end - end - - context "with valid definition" do - before(:each) do - @service_manager_output = [ ] - # Uncomment below lines to debug this test - # original_puts = $stdout.method(:puts) - $stdout.stub(:puts) do |message| - @service_manager_output << message - # original_puts.call(message) - end - end - - after(:each) do - cleanup - end - - context "when service doesn't exist" do - it "default => should say service don't exist" do - service_manager.run - - @service_manager_output.grep(/doesn't exist on the system/).length.should > 0 - end - - it "install => should install the service" do - service_manager.run(["-a", "install"]) - - test_service_exists?.should be_true - end - - it "other actions => should say service doesn't exist" do - ["delete", "start", "stop", "pause", "resume", "uninstall"].each do |action| - service_manager.run(["-a", action]) - @service_manager_output.grep(/doesn't exist on the system/).length.should > 0 - @service_manager_output = [ ] - end - end - end - - context "when service exists" do - before(:each) do - service_manager.run(["-a", "install"]) - end - - it "should have an own-process, non-interactive type" do - status = ::Win32::Service.status("spec-service") - status[:service_type].should == "own process" - status[:interactive].should be_false - end - - it "install => should say service already exists" do - service_manager.run(["-a", "install"]) - @service_manager_output.grep(/already exists/).length.should > 0 - end - - context "and service is stopped" do - ["delete", "uninstall"].each do |action| - it "#{action} => should remove the service", :volatile do - service_manager.run(["-a", action]) - test_service_exists?.should be_false - end - end - - it "default, status => should say service is stopped" do - service_manager.run([ ]) - @service_manager_output.grep(/stopped/).length.should > 0 - @service_manager_output = [ ] - - service_manager.run(["-a", "status"]) - @service_manager_output.grep(/stopped/).length.should > 0 - end - - it "start should start the service", :volatile do - service_manager.run(["-a", "start"]) - test_service_state.should == "running" - File.exists?(test_service_file).should be_true - end - - it "stop should not affect the service" do - service_manager.run(["-a", "stop"]) - test_service_state.should == "stopped" - end - - - ["pause", "resume"].each do |action| - it "#{action} => should raise error" do - lambda {service_manager.run(["-a", action])}.should raise_error(::Win32::Service::Error) - end - end - - context "and service is started", :volatile do - before(:each) do - service_manager.run(["-a", "start"]) - end - - ["delete", "uninstall"].each do |action| - it "#{action} => should remove the service", :volatile do - service_manager.run(["-a", action]) - test_service_exists?.should be_false - end - end - - it "default, status => should say service is running" do - service_manager.run([ ]) - @service_manager_output.grep(/running/).length.should > 0 - @service_manager_output = [ ] - - service_manager.run(["-a", "status"]) - @service_manager_output.grep(/running/).length.should > 0 - end - - it "stop should stop the service" do - service_manager.run(["-a", "stop"]) - test_service_state.should == "stopped" - end - - it "pause should pause the service" do - service_manager.run(["-a", "pause"]) - test_service_state.should == "paused" - end - - it "resume should have no affect" do - service_manager.run(["-a", "resume"]) - test_service_state.should == "running" - end - end - - context "and service is paused", :volatile do - before(:each) do - service_manager.run(["-a", "start"]) - service_manager.run(["-a", "pause"]) - end - - actions = ["delete", "uninstall"] - actions.each do |action| - it "#{action} => should remove the service" do - service_manager.run(["-a", action]) - test_service_exists?.should be_false - end - end - - it "default, status => should say service is paused" do - service_manager.run([ ]) - @service_manager_output.grep(/paused/).length.should > 0 - @service_manager_output = [ ] - - service_manager.run(["-a", "status"]) - @service_manager_output.grep(/paused/).length.should > 0 - end - - it "stop should stop the service" do - service_manager.run(["-a", "stop"]) - test_service_state.should == "stopped" - end - - it "pause should not affect the service" do - service_manager.run(["-a", "pause"]) - test_service_state.should == "paused" - end - - it "start should raise an error" do - lambda {service_manager.run(["-a", "start"])}.should raise_error(::Win32::Service::Error) - end - - end - end - end - end -end diff --git a/spec/functional/win32/versions_spec.rb b/spec/functional/win32/versions_spec.rb deleted file mode 100644 index 6c8f6b2aaa..0000000000 --- a/spec/functional/win32/versions_spec.rb +++ /dev/null @@ -1,117 +0,0 @@ -# -# Author:: Chirag Jog (<chirag@clogeny.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' -if Chef::Platform.windows? - 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') - - # Use WMI to determine current OS version. - # On Win2k8R2 and later, we can dynamically obtain marketing - # names for comparison from WMI so the test should not - # need to be modified when new Windows releases arise. - # For Win2k3 and Win2k8, we use static names in this test - # based on the version number information from WMI. The names - # from WMI contain extended characters such as registered - # 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' - elsif is_windows_server_2008?(host) - @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'] - end - - @version = Chef::ReservedNames::Win32::Version.new - end - - 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) } - yield method_name - end - end - end - - context "Win32 version object" do - it "should have have one method for each marketing version" do - versions = 0 - for_each_windows_version { versions += 1 } - versions.should > 0 - versions.should == Chef::ReservedNames::Win32::Version::WIN_VERSIONS.length - end - - it "should only contain version methods with legal method names" do - method_name_pattern = /[a-z]+([a-z]|[0-9]|_)*\?{0,1}/ - - for_each_windows_version do |method_name| - method_match = method_name_pattern.match(method_name.to_s) - method_match.should_not be_nil - method_name.to_s.should == method_match[0] - end - end - - it "should have exactly one method that returns true" do - true_versions = 0 - for_each_windows_version do |method_name| - true_versions += 1 if @version.send(method_name) - end - true_versions.should == 1 - end - - it "should successfully execute all version methods" do - for_each_windows_version { |method_name| @version.send(method_name.to_sym) } - end - end - - context "Windows Operating System version" do - it "should match the version from WMI" do - @current_os_version.should include(@version.marketing_name) - end - end - - def is_windows_server_2008?(wmi_host) - is_win2k8 = false - - 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('.') - - 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.' - 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' - end -end diff --git a/spec/integration/client/client_spec.rb b/spec/integration/client/client_spec.rb deleted file mode 100644 index 0144ae0ce3..0000000000 --- a/spec/integration/client/client_spec.rb +++ /dev/null @@ -1,242 +0,0 @@ -require 'support/shared/integration/integration_helper' -require 'chef/mixin/shell_out' - -describe "chef-client" do - include IntegrationSupport - include Chef::Mixin::ShellOut - - 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'" } - - when_the_repository "has a cookbook with a no-op recipe" do - before { file 'cookbooks/x/recipes/default.rb', '' } - - it "should complete with success" 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'", :cwd => chef_dir) - 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('')) - 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')) - 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(''))) - result.exitstatus.should == 1 - end - end - - 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('')) - # FATAL: Configuration error NoMethodError: undefined method `xxx' for nil:NilClass - result.stdout.should include("xxx") - end - - end - - it "should complete with success" 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'", :cwd => chef_dir) - result.error! - end - - context 'and a private key' do - before do - file 'mykey.pem', <<EOM ------BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEApubutqtYYQ5UiA9QhWP7UvSmsfHsAoPKEVVPdVW/e8Svwpyf -0Xef6OFWVmBE+W442ZjLOe2y6p2nSnaq4y7dg99NFz6X+16mcKiCbj0RCiGqCvCk -NftHhTgO9/RFvCbmKZ1RKNob1YzLrFpxBHaSh9po+DGWhApcd+I+op+ZzvDgXhNn -0nauZu3rZmApI/r7EEAOjFedAXs7VPNXhhtZAiLSAVIrwU3ZajtSzgXOxbNzgj5O -AAAMmThK+71qPdffAdO4J198H6/MY04qgtFo7vumzCq0UCaGZfmeI1UNE4+xQWwP -HJ3pDAP61C6Ebx2snI2kAd9QMx9Y78nIedRHPwIDAQABAoIBAHssRtPM1GacWsom -8zfeN6ZbI4KDlbetZz0vhnqDk9NVrpijWlcOP5dwZXVNitnB/HaqCqFvyPDY9JNB -zI/pEFW4QH59FVDP42mVEt0keCTP/1wfiDDGh1vLqVBYl/ZphscDcNgDTzNkuxMx -k+LFVxKnn3w7rGc59lALSkpeGvbbIDjp3LUMlUeCF8CIFyYZh9ZvXe4OCxYdyjxb -i8tnMLKvJ4Psbh5jMapsu3rHQkfPdqzztQUz8vs0NYwP5vWge46FUyk+WNm/IhbJ -G3YM22nwUS8Eu2bmTtADSJolATbCSkOwQ1D+Fybz/4obfYeGaCdOqB05ttubhenV -ShsAb7ECgYEA20ecRVxw2S7qA7sqJ4NuYOg9TpfGooptYNA1IP971eB6SaGAelEL -awYkGNuu2URmm5ElZpwJFFTDLGA7t2zB2xI1FeySPPIVPvJGSiZoFQOVlIg9WQzK -7jTtFQ/tOMrF+bigEUJh5bP1/7HzqSpuOsPjEUb2aoCTp+tpiRGL7TUCgYEAwtns -g3ysrSEcTzpSv7fQRJRk1lkBhatgNd0oc+ikzf74DaVLhBg1jvSThDhiDCdB59mr -Jh41cnR1XqE8jmdQbCDRiFrI1Pq6TPaDZFcovDVE1gue9x86v3FOH2ukPG4d2/Xy -HevXjThtpMMsWFi0JYXuzXuV5HOvLZiP8sN3lSMCgYANpdxdGM7RRbE9ADY0dWK2 -V14ReTLcxP7fyrWz0xLzEeCqmomzkz3BsIUoouu0DCTSw+rvAwExqcDoDylIVlWO -fAifz7SeZHbcDxo+3TsXK7zwnLYsx7YNs2+aIv6hzUUbMNmNmXMcZ+IEwx+mRMTN -lYmZdrA5mr0V83oDFPt/jQKBgC74RVE03pMlZiObFZNtheDiPKSG9Bz6wMh7NWMr -c37MtZLkg52mEFMTlfPLe6ceV37CM8WOhqe+dwSGrYhOU06dYqUR7VOZ1Qr0aZvo -fsNPu/Y0+u7rMkgv0fs1AXQnvz7kvKaF0YITVirfeXMafuKEtJoH7owRbur42cpV -YCAtAoGAP1rHOc+w0RUcBK3sY7aErrih0OPh9U5bvJsrw1C0FIZhCEoDVA+fNIQL -syHLXYFNy0OxMtH/bBAXBGNHd9gf5uOnqh0pYcbe/uRAxumC7Rl0cL509eURiA2T -+vFmf54y9YdnLXaqv+FhJT6B6V7WX7IpU9BMqJY1cJYXHuHG2KA= ------END RSA PRIVATE KEY----- -EOM - end - - it "should complete with success even with a client key" do - file 'config/client.rb', <<EOM -local_mode true -client_key #{path_to('mykey.pem').inspect} -cookbook_path #{path_to('cookbooks').inspect} -EOM - - result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'x::default'", :cwd => chef_dir) - result.error! - end - - it "should run recipes specified directly on the command line" do - 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 #{path_to('tempfile.txt').inspect} do - content '1' -end -EOM - - file 'arbitrary2.rb', <<EOM -file #{path_to('tempfile2.txt').inspect} do - content '2' -end -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! - - IO.read(path_to('tempfile.txt')).should == '1' - IO.read(path_to('tempfile2.txt')).should == '2' - end - - it "should run recipes specified as relative paths directly on the command line" do - 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 #{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.error! - - IO.read(path_to('tempfile.txt')).should == '1' - end - - it "should run recipes specified directly on the command line AFTER recipes in the run list" do - 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 -class ::Blah - THECONSTANT = '1' -end -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.error! - - IO.read(path_to('tempfile.txt')).should == '1' - end - - end - - it "should complete with success when passed the -z flag" do - file 'config/client.rb', <<EOM -chef_server_url 'http://omg.com/blah' -cookbook_path "#{path_to('cookbooks')}" -EOM - - result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'x::default' -z", :cwd => chef_dir) - result.error! - end - - it "should complete with success when passed the --local-mode flag" do - file 'config/client.rb', <<EOM -chef_server_url 'http://omg.com/blah' -cookbook_path "#{path_to('cookbooks')}" -EOM - - result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'x::default' --local-mode", :cwd => chef_dir) - result.error! - end - - it "should not print SSL warnings when running in local-mode" do - file 'config/client.rb', <<EOM -chef_server_url 'http://omg.com/blah' -cookbook_path "#{path_to('cookbooks')}" -EOM - - result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'x::default' --local-mode", :cwd => chef_dir) - result.stdout.should_not include("SSL validation of HTTPS requests is disabled.") - result.error! - end - - it "should complete with success when passed -z and --chef-zero-port" do - file 'config/client.rb', <<EOM -chef_server_url 'http://omg.com/blah' -cookbook_path "#{path_to('cookbooks')}" -EOM - - result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'x::default' -z", :cwd => chef_dir) - result.error! - end - - it "should complete with success when setting the run list with -r" do - file 'config/client.rb', <<EOM -chef_server_url 'http://omg.com/blah' -cookbook_path "#{path_to('cookbooks')}" -EOM - - result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" -r 'x::default' -z", :cwd => chef_dir) - result.stdout.should_not include("Overridden Run List") - result.stdout.should include("Run List is [recipe[x::default]]") - #puts result.stdout - result.error! - end - - end -end diff --git a/spec/integration/client/ipv6_spec.rb b/spec/integration/client/ipv6_spec.rb deleted file mode 100644 index 76dd1938f7..0000000000 --- a/spec/integration/client/ipv6_spec.rb +++ /dev/null @@ -1,135 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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 '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(:validation_pem) do - <<-END_VALIDATION_PEM ------BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEApubutqtYYQ5UiA9QhWP7UvSmsfHsAoPKEVVPdVW/e8Svwpyf -0Xef6OFWVmBE+W442ZjLOe2y6p2nSnaq4y7dg99NFz6X+16mcKiCbj0RCiGqCvCk -NftHhTgO9/RFvCbmKZ1RKNob1YzLrFpxBHaSh9po+DGWhApcd+I+op+ZzvDgXhNn -0nauZu3rZmApI/r7EEAOjFedAXs7VPNXhhtZAiLSAVIrwU3ZajtSzgXOxbNzgj5O -AAAMmThK+71qPdffAdO4J198H6/MY04qgtFo7vumzCq0UCaGZfmeI1UNE4+xQWwP -HJ3pDAP61C6Ebx2snI2kAd9QMx9Y78nIedRHPwIDAQABAoIBAHssRtPM1GacWsom -8zfeN6ZbI4KDlbetZz0vhnqDk9NVrpijWlcOP5dwZXVNitnB/HaqCqFvyPDY9JNB -zI/pEFW4QH59FVDP42mVEt0keCTP/1wfiDDGh1vLqVBYl/ZphscDcNgDTzNkuxMx -k+LFVxKnn3w7rGc59lALSkpeGvbbIDjp3LUMlUeCF8CIFyYZh9ZvXe4OCxYdyjxb -i8tnMLKvJ4Psbh5jMapsu3rHQkfPdqzztQUz8vs0NYwP5vWge46FUyk+WNm/IhbJ -G3YM22nwUS8Eu2bmTtADSJolATbCSkOwQ1D+Fybz/4obfYeGaCdOqB05ttubhenV -ShsAb7ECgYEA20ecRVxw2S7qA7sqJ4NuYOg9TpfGooptYNA1IP971eB6SaGAelEL -awYkGNuu2URmm5ElZpwJFFTDLGA7t2zB2xI1FeySPPIVPvJGSiZoFQOVlIg9WQzK -7jTtFQ/tOMrF+bigEUJh5bP1/7HzqSpuOsPjEUb2aoCTp+tpiRGL7TUCgYEAwtns -g3ysrSEcTzpSv7fQRJRk1lkBhatgNd0oc+ikzf74DaVLhBg1jvSThDhiDCdB59mr -Jh41cnR1XqE8jmdQbCDRiFrI1Pq6TPaDZFcovDVE1gue9x86v3FOH2ukPG4d2/Xy -HevXjThtpMMsWFi0JYXuzXuV5HOvLZiP8sN3lSMCgYANpdxdGM7RRbE9ADY0dWK2 -V14ReTLcxP7fyrWz0xLzEeCqmomzkz3BsIUoouu0DCTSw+rvAwExqcDoDylIVlWO -fAifz7SeZHbcDxo+3TsXK7zwnLYsx7YNs2+aIv6hzUUbMNmNmXMcZ+IEwx+mRMTN -lYmZdrA5mr0V83oDFPt/jQKBgC74RVE03pMlZiObFZNtheDiPKSG9Bz6wMh7NWMr -c37MtZLkg52mEFMTlfPLe6ceV37CM8WOhqe+dwSGrYhOU06dYqUR7VOZ1Qr0aZvo -fsNPu/Y0+u7rMkgv0fs1AXQnvz7kvKaF0YITVirfeXMafuKEtJoH7owRbur42cpV -YCAtAoGAP1rHOc+w0RUcBK3sY7aErrih0OPh9U5bvJsrw1C0FIZhCEoDVA+fNIQL -syHLXYFNy0OxMtH/bBAXBGNHd9gf5uOnqh0pYcbe/uRAxumC7Rl0cL509eURiA2T -+vFmf54y9YdnLXaqv+FhJT6B6V7WX7IpU9BMqJY1cJYXHuHG2KA= ------END RSA PRIVATE KEY----- -END_VALIDATION_PEM - end - - let(:cache_path) do - Dir.mktmpdir - end - - let(:basic_config_file) do - <<-END_CLIENT_RB -chef_server_url "http://[::1]:8900" -validation_key '#{path_to('config/validator.pem')}' -cache_path '#{cache_path}' -client_key '#{cache_path}/client.pem' -END_CLIENT_RB - end - - let(:client_rb_content) do - basic_config_file - end - - - let(:chef_dir) { File.join(File.dirname(__FILE__), "..", "..", "..", "bin") } - - let(:chef_client_cmd) { %Q[ruby '#{chef_dir}/chef-client' -c "#{path_to('config/client.rb')}" -lwarn] } - - after do - FileUtils.rm_rf(cache_path) - end - - # 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_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 - end - - it "should complete with success" do - result = shell_out("#{chef_client_cmd} -o 'noop::default'", :cwd => chef_dir) - result.error! - end - - end - - when_the_repository "has a cookbook that hits server APIs" do - - before do - 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" - else - Chef::Log.error("!" * 80) - raise "unexpected data bag item content \#{actual_item.inspect}" - Chef::Log.error("!" * 80) - end - - END_RECIPE - - data_bag('expect_bag', { 'expect_item' => {"expect_key" => "expect_value"} }) - - 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 - end - - it "should complete with success" do - result = shell_out("#{chef_client_cmd} -o 'api-smoke-test::default'", :cwd => chef_dir) - result.error! - end - - end - end -end diff --git a/spec/integration/knife/chef_fs_data_store_spec.rb b/spec/integration/knife/chef_fs_data_store_spec.rb deleted file mode 100644 index a4d62673de..0000000000 --- a/spec/integration/knife/chef_fs_data_store_spec.rb +++ /dev/null @@ -1,366 +0,0 @@ -# -# Author:: John Keiser (<jkeiser@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 '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 - 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 - 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', {} - 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 - - 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 /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 /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 /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 - - 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 /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 /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 '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 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 empty.json -m PUT /nodes/x' do - knife("raw -z -i #{path_to('empty.json')} -m PUT /nodes/x").should_succeed( /"x"/ ) - knife('list --local /nodes').should_succeed "/nodes/x.json\n" - 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', :pending => (RUBY_VERSION < "1.9") do - knife("raw -z -i #{path_to('rolestuff.json')} -m PUT /roles/x").should_succeed( /"x"/ ) - IO.read(path_to('roles/x.json')).should == <<EOM.strip -{ - "name": "x", - "description": "hi there" -} -EOM - end - end - end - - when_the_repository 'is empty' do - context 'POST /TYPE/NAME' do - before do - file 'empty.json', { 'name' => 'z' } - 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 empty.json -m POST /nodes' do - knife("raw -z -i #{path_to('empty.json')} -m POST /nodes").should_succeed( /uri/ ) - knife('list --local /nodes').should_succeed "/nodes/z.json\n" - 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', :pending => (RUBY_VERSION < "1.9") do - knife("raw -z -i #{path_to('rolestuff.json')} -m POST /roles").should_succeed( /uri/ ) - IO.read(path_to('roles/x.json')).should == <<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 -/clients/ -/cookbooks/ -/data_bags/ -/environments/ -/nodes/ -/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 - - 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 /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 /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 /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 /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 /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 - - 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 - - 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 /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 /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 - - 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 - - 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 deleted file mode 100644 index 874b33901f..0000000000 --- a/spec/integration/knife/chef_repo_path_spec.rb +++ /dev/null @@ -1,888 +0,0 @@ -# -# Author:: John Keiser (<jkeiser@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 '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 - include IntegrationSupport - include KnifeSupport - - # TODO alternate repo_path / *_path - 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', {} - end - end - - 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/ -/clients/client3.json -/cookbooks/ -/cookbooks/cookbook3/ -/cookbooks/cookbook3/metadata.rb -/data_bags/ -/data_bags/bag3/ -/data_bags/bag3/item3.json -/environments/ -/environments/env3.json -/nodes/ -/nodes/node3.json -/roles/ -/roles/role3.json -/users/ -/users/user3.json -EOM - end - - 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| - 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') - end - - 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 -/cookbooks/ -/cookbooks/cookbook3/ -/cookbooks/cookbook3/metadata.rb -/data_bags/ -/data_bags/bag3/ -/data_bags/bag3/item3.json -/environments/ -/environments/env3.json -/nodes/ -/nodes/node3.json -/roles/ -/roles/role3.json -/users/ -/users/user3.json -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") - 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") - 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 -clients/ -clients/client2.json -cookbooks/ -cookbooks/cookbook2/ -cookbooks/cookbook2/metadata.rb -data_bags/ -data_bags/bag2/ -data_bags/bag2/item2.json -environments/ -environments/env2.json -nodes/ -nodes/node2.json -roles/ -roles/role2.json -users/ -users/user2.json -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 -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" - end - end - end - - 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| - 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 -clients/ -clients/client2.json -cookbooks/ -cookbooks/cookbook2/ -cookbooks/cookbook2/metadata.rb -data_bags/ -data_bags/bag2/ -data_bags/bag2/item2.json -environments/ -environments/env2.json -nodes/ -nodes/node2.json -roles/ -roles/role2.json -users/ -users/user2.json -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") - 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") - 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 -bag2/ -bag2/item2.json -EOM - end - end - end - - 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| - Chef::Config.delete("#{object_name}_path".to_sym) - end - 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") - 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") - 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 -clients/ -clients/client3.json -cookbooks/ -cookbooks/cookbook3/ -cookbooks/cookbook3/metadata.rb -data_bags/ -data_bags/bag3/ -data_bags/bag3/item3.json -environments/ -environments/env3.json -nodes/ -nodes/node3.json -roles/ -roles/role3.json -users/ -users/user3.json -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 -bag3/ -bag3/item3.json -EOM - end - end - end - - 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| - 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") - ] - end - 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 - before do - 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 -/clients/blah.json: -{ - -} -EOM - end - end - - 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', '' - end - 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/ -/cookbooks/cookbook1/metadata.rb -/cookbooks/cookbook2/ -/cookbooks/cookbook2/metadata.rb -EOM - end - end - - 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', '' - 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") -/cookbooks/blah/ -/cookbooks/blah/metadata.rb -/cookbooks/cookbook1/ -/cookbooks/cookbook1/metadata.rb -/cookbooks/cookbook2/ -/cookbooks/cookbook2/metadata.rb -EOM - end - end - - 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', '' - 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") -/cookbooks/blah/ -/cookbooks/blah/metadata.json -/cookbooks/cookbook1/ -/cookbooks/cookbook1/metadata.rb -/cookbooks/cookbook2/ -/cookbooks/cookbook2/metadata.rb -EOM - end - end - - 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', '' - end - 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/ -/data_bags/bag2/item2.json -/data_bags/blah/ -/data_bags/blah/item.json -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 - before do - 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") -/data_bags/bag/ -/data_bags/bag/item.json -/data_bags/bag2/ -/data_bags/bag2/item2.json -/data_bags/blah/ -/data_bags/blah/item1.json -EOM - end - end - - 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', {} - end - it 'knife show /environments/blah.json succeeds' do - knife('show --local /environments/blah.json').should_succeed <<EOM -/environments/blah.json: -{ - -} -EOM - end - end - - 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', {} - end - it 'knife show /nodes/blah.json succeeds' do - knife('show --local /nodes/blah.json').should_succeed <<EOM -/nodes/blah.json: -{ - -} -EOM - end - end - - 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', {} - end - it 'knife show /roles/blah.json succeeds' do - knife('show --local /roles/blah.json').should_succeed <<EOM -/roles/blah.json: -{ - -} -EOM - end - end - - 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', {} - end - it 'knife show /users/blah.json succeeds' do - knife('show --local /users/blah.json').should_succeed <<EOM -/users/blah.json: -{ - -} -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") - 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 -bag/ -bag/item.json -bag2/ -bag2/item2.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 -clients/ -clients/client1.json -clients/client2.json -cookbooks/ -cookbooks/cookbook1/ -cookbooks/cookbook1/metadata.rb -cookbooks/cookbook2/ -cookbooks/cookbook2/metadata.rb -data_bags/ -data_bags/bag/ -data_bags/bag/item.json -data_bags/bag2/ -data_bags/bag2/item2.json -environments/ -environments/env1.json -environments/env2.json -nodes/ -nodes/node1.json -nodes/node2.json -roles/ -roles/role1.json -roles/role2.json -users/ -users/user1.json -users/user2.json -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 -bag/ -bag/item.json -bag2/ -bag2/item2.json -EOM - end - end - end - - 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| - 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') - ] - 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 -clients/ -clients/client1.json -clients/client3.json -cookbooks/ -cookbooks/cookbook1/ -cookbooks/cookbook1/metadata.rb -cookbooks/cookbook3/ -cookbooks/cookbook3/metadata.rb -data_bags/ -data_bags/bag/ -data_bags/bag/item.json -data_bags/bag3/ -data_bags/bag3/item3.json -environments/ -environments/env1.json -environments/env3.json -nodes/ -nodes/node1.json -nodes/node3.json -roles/ -roles/role1.json -roles/role3.json -users/ -users/user1.json -users/user3.json -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 -bag/ -bag/item.json -bag3/ -bag3/item3.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 -clients/ -clients/client1.json -clients/client3.json -cookbooks/ -cookbooks/cookbook1/ -cookbooks/cookbook1/metadata.rb -cookbooks/cookbook3/ -cookbooks/cookbook3/metadata.rb -data_bags/ -data_bags/bag/ -data_bags/bag/item.json -data_bags/bag3/ -data_bags/bag3/item3.json -environments/ -environments/env1.json -environments/env3.json -nodes/ -nodes/node1.json -nodes/node3.json -roles/ -roles/role1.json -roles/role3.json -users/ -users/user1.json -users/user3.json -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 -bag/ -bag/item.json -bag3/ -bag3/item3.json -EOM - end - end - end - - 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| - 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') - 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") - 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") - 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 -clients/ -clients/client3.json -cookbooks/ -cookbooks/cookbook3/ -cookbooks/cookbook3/metadata.rb -data_bags/ -data_bags/bag3/ -data_bags/bag3/item3.json -environments/ -environments/env3.json -nodes/ -nodes/node3.json -roles/ -roles/role3.json -users/ -users/user3.json -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 -bag3/ -bag3/item3.json -EOM - end - end - end - - 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| - 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') - ] - 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 -clients/ -clients/client1.json -clients/client3.json -cookbooks/ -cookbooks/cookbook1/ -cookbooks/cookbook1/metadata.rb -cookbooks/cookbook3/ -cookbooks/cookbook3/metadata.rb -data_bags/ -data_bags/bag/ -data_bags/bag/item.json -data_bags/bag3/ -data_bags/bag3/item3.json -environments/ -environments/env1.json -environments/env3.json -nodes/ -nodes/node1.json -nodes/node3.json -roles/ -roles/role1.json -roles/role3.json -users/ -users/user1.json -users/user3.json -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 -bag/ -bag/item.json -bag3/ -bag3/item3.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 -clients/ -clients/client1.json -clients/client3.json -cookbooks/ -cookbooks/cookbook1/ -cookbooks/cookbook1/metadata.rb -cookbooks/cookbook3/ -cookbooks/cookbook3/metadata.rb -data_bags/ -data_bags/bag/ -data_bags/bag/item.json -data_bags/bag3/ -data_bags/bag3/item3.json -environments/ -environments/env1.json -environments/env3.json -nodes/ -nodes/node1.json -nodes/node3.json -roles/ -roles/role1.json -roles/role3.json -users/ -users/user1.json -users/user3.json -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 -bag/ -bag/item.json -bag3/ -bag3/item3.json -EOM - end - end - end - - 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| - 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') - 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") - 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 -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 -clients/ -clients/client3.json -cookbooks/ -cookbooks/cookbook3/ -cookbooks/cookbook3/metadata.rb -data_bags/ -data_bags/bag/ -data_bags/bag/item.json -environments/ -environments/env3.json -nodes/ -nodes/node3.json -roles/ -roles/role3.json -users/ -users/user3.json -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") - end - end - end - - 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| - 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') - end - - 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 -/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 -bag/ -bag/item.json -EOM - end - end - end - end - - 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) - end - 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 '' - 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") - end - end - 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 deleted file mode 100644 index 34afd228f3..0000000000 --- a/spec/integration/knife/chef_repository_file_system_spec.rb +++ /dev/null @@ -1,292 +0,0 @@ -# -# Author:: John Keiser (<jkeiser@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 'support/shared/integration/integration_helper' -require 'chef/knife/list' -require 'chef/knife/show' - -describe 'General chef_repo file system checks', :workstation do - include IntegrationSupport - include KnifeSupport - - 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" - directory "environments" - directory "data_bags/bag1" - end - - it "knife list --local -Rfp / returns them" do - knife('list --local -Rfp /').should_succeed <<EOM -/data_bags/ -/data_bags/bag1/ -/environments/ -/roles/ -EOM - end - end - - when_the_repository "has an empty data_bags directory" do - before { directory "data_bags" } - - it "knife list --local / returns it" do - knife('list --local /').should_succeed "/data_bags\n" - end - end - - when_the_repository "has an empty cookbook directory" do - 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") -/cookbooks/ -EOM - end - end - - when_the_repository "has only empty cookbook subdirectories" do - 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") -/cookbooks/ -EOM - end - end - - when_the_repository "has empty and non-empty cookbook subdirectories" do - before do - 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 -/cookbooks/ -/cookbooks/cookbook1/ -/cookbooks/cookbook1/templates/ -/cookbooks/cookbook1/templates/default/ -/cookbooks/cookbook1/templates/default/x.txt -EOM - end - end - - when_the_repository "has only empty cookbook sub-sub-directories" do - 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") -/cookbooks/ -EOM - end - end - - 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' - end - - it "knife list --local -Rfp / does not return the empty ones" do - knife('list --local -Rfp /').should_succeed <<EOM -/cookbooks/ -/cookbooks/cookbook1/ -/cookbooks/cookbook1/templates/ -/cookbooks/cookbook1/templates/default/ -/cookbooks/cookbook1/templates/default/x.txt -EOM - end - end - - when_the_repository "has an extra schmenvironments directory" do - before do - directory "schmenvironments" do - file "_default.json", {} - end - end - - it "knife list --local -Rfp / should NOT return it" do - knife('list --local -Rfp /').should_succeed "" - end - end - - when_the_repository "has extra subdirectories and files under data bag items, roles, and environments" do - before do - directory "data_bags/bag1" do - file "item1.json", {} - file "item2.xml", "" - file "another_subdir/item.json", {} - end - directory "roles" do - file "role1.json", {} - file "role2.xml", "" - file "subdir/role.json", {} - end - directory "environments" do - file "environment1.json", {} - file "environment2.xml", "" - file "subdir/environment.json", {} - end - end - - it "knife list --local -Rfp / should NOT return them" do - knife('list --local -Rfp /').should_succeed <<EOM -/data_bags/ -/data_bags/bag1/ -/data_bags/bag1/item1.json -/environments/ -/environments/environment1.json -/roles/ -/roles/role1.json -EOM - end - end - - 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', {} - end - 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', {} - end - 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', {} - end - 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', {} - end - 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 -/cookbooks/ -/cookbooks/cookbook1/ -/cookbooks/cookbook1/a.rb -/cookbooks/cookbook1/attributes/ -/cookbooks/cookbook1/attributes/a.rb -/cookbooks/cookbook1/definitions/ -/cookbooks/cookbook1/definitions/a.rb -/cookbooks/cookbook1/files/ -/cookbooks/cookbook1/files/a.rb -/cookbooks/cookbook1/files/b.json -/cookbooks/cookbook1/files/c/ -/cookbooks/cookbook1/files/c/d.rb -/cookbooks/cookbook1/files/c/e.json -/cookbooks/cookbook1/libraries/ -/cookbooks/cookbook1/libraries/a.rb -/cookbooks/cookbook1/providers/ -/cookbooks/cookbook1/providers/a.rb -/cookbooks/cookbook1/providers/c/ -/cookbooks/cookbook1/providers/c/d.rb -/cookbooks/cookbook1/recipes/ -/cookbooks/cookbook1/recipes/a.rb -/cookbooks/cookbook1/resources/ -/cookbooks/cookbook1/resources/a.rb -/cookbooks/cookbook1/resources/c/ -/cookbooks/cookbook1/resources/c/d.rb -/cookbooks/cookbook1/templates/ -/cookbooks/cookbook1/templates/a.rb -/cookbooks/cookbook1/templates/b.json -/cookbooks/cookbook1/templates/c/ -/cookbooks/cookbook1/templates/c/d.rb -/cookbooks/cookbook1/templates/c/e.json -EOM - end - 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 -/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 -/data_bags/ -EOM - end - end - end - - when_the_repository 'has a cookbook starting with .' do - before do - 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" - end - end - - 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', {} - end - 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 deleted file mode 100644 index 34bf391f88..0000000000 --- a/spec/integration/knife/chefignore_spec.rb +++ /dev/null @@ -1,300 +0,0 @@ -# -# Author:: John Keiser (<jkeiser@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 'support/shared/integration/integration_helper' -require 'chef/knife/list' -require 'chef/knife/show' - -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', {} - 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 - end - - 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 -/cookbooks/ -/cookbooks/cookbook1/ -/cookbooks/cookbook1/chefignore -/data_bags/ -/data_bags/bag1/ -/data_bags/bag1/x.json -/environments/ -/environments/x.json -/roles/ -/roles/x.json -EOM - end - end - end - - 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" - 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") -/cookbooks/ -EOM - end - end - - 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', {} - end - - 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 -/cookbooks/ -/cookbooks/cookbook1/ -/cookbooks/cookbook1/y.json -/cookbooks/cookbook2/ -/cookbooks/cookbook2/y.json -EOM - end - end - - context "and has a chefignore with wildcards" do - before do - 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 -/cookbooks/ -/cookbooks/cookbook1/ -/cookbooks/cookbook1/y.json -/cookbooks/cookbook2/ -/cookbooks/cookbook2/y.json -EOM - end - end - - 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" - end - - it 'matching directories get ignored' do - knife('list --local -Rfp /').should_succeed <<EOM -/cookbooks/ -/cookbooks/cookbook1/ -/cookbooks/cookbook1/x.json -/cookbooks/cookbook1/y.json -/cookbooks/cookbook2/ -/cookbooks/cookbook2/recipes/ -/cookbooks/cookbook2/recipes/y.rb -/cookbooks/cookbook2/x.json -/cookbooks/cookbook2/y.json -EOM - end - end - - context "and has a chefignore with subdirectories" do - before do - 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 -/cookbooks/ -/cookbooks/cookbook1/ -/cookbooks/cookbook1/recipes/ -/cookbooks/cookbook1/recipes/y.rb -/cookbooks/cookbook1/x.json -/cookbooks/cookbook1/y.json -/cookbooks/cookbook2/ -/cookbooks/cookbook2/x.json -/cookbooks/cookbook2/y.json -EOM - end - end - - 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" - end - - it 'ignores the subdirectory entirely' do - knife('list --local -Rfp /').should_succeed <<EOM -/cookbooks/ -/cookbooks/cookbook1/ -/cookbooks/cookbook1/x.json -/cookbooks/cookbook1/y.json -/cookbooks/cookbook2/ -/cookbooks/cookbook2/x.json -/cookbooks/cookbook2/y.json -EOM - end - end - - context "and has an empty chefignore" do - before do - file 'cookbooks/chefignore', "\n" - end - - it 'nothing is ignored' do - knife('list --local -Rfp /').should_succeed <<EOM -/cookbooks/ -/cookbooks/cookbook1/ -/cookbooks/cookbook1/x.json -/cookbooks/cookbook1/y.json -/cookbooks/cookbook2/ -/cookbooks/cookbook2/x.json -/cookbooks/cookbook2/y.json -EOM - end - end - - context "and has a chefignore with comments and empty lines" do - before do - 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 -/cookbooks/ -/cookbooks/cookbook1/ -/cookbooks/cookbook1/y.json -/cookbooks/cookbook2/ -/cookbooks/cookbook2/y.json -EOM - end - end - end - - 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') - ] - end - - before do - 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" - end - it "chefignores apply only to the directories they are in" do - knife('list --local -Rfp /').should_succeed <<EOM -/cookbooks/ -/cookbooks/mycookbook/ -/cookbooks/mycookbook/x.json -/cookbooks/yourcookbook/ -/cookbooks/yourcookbook/metadata.rb -EOM - end - - 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', '' - 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") -/cookbooks/ -/cookbooks/mycookbook/ -/cookbooks/mycookbook/x.json -/cookbooks/yourcookbook/ -/cookbooks/yourcookbook/onlyincookbooks1.rb -/cookbooks/yourcookbook/x.json -EOM - end - end - end - end - - when_the_repository 'has a cookbook named chefignore' do - before do - file 'cookbooks/chefignore/metadata.rb', {} - end - 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 - before do - 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') - ] - end - 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/ -/cookbooks/chefignore/metadata.rb -EOM - end - end -end diff --git a/spec/integration/knife/common_options_spec.rb b/spec/integration/knife/common_options_spec.rb deleted file mode 100644 index dfc1e024f9..0000000000 --- a/spec/integration/knife/common_options_spec.rb +++ /dev/null @@ -1,155 +0,0 @@ -# -# Author:: John Keiser (<jkeiser@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 'support/shared/integration/integration_helper' -require 'chef/knife/raw' - -describe 'knife common options', :workstation do - include IntegrationSupport - include KnifeSupport - - when_the_repository "has a node" do - before { file 'nodes/x.json', {} } - - 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"/ ) - end - - 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"/ ) - Chef::Config.chef_server_url.should == 'http://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' } - - 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 - before do - file 'mykey.pem', <<EOM ------BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEApubutqtYYQ5UiA9QhWP7UvSmsfHsAoPKEVVPdVW/e8Svwpyf -0Xef6OFWVmBE+W442ZjLOe2y6p2nSnaq4y7dg99NFz6X+16mcKiCbj0RCiGqCvCk -NftHhTgO9/RFvCbmKZ1RKNob1YzLrFpxBHaSh9po+DGWhApcd+I+op+ZzvDgXhNn -0nauZu3rZmApI/r7EEAOjFedAXs7VPNXhhtZAiLSAVIrwU3ZajtSzgXOxbNzgj5O -AAAMmThK+71qPdffAdO4J198H6/MY04qgtFo7vumzCq0UCaGZfmeI1UNE4+xQWwP -HJ3pDAP61C6Ebx2snI2kAd9QMx9Y78nIedRHPwIDAQABAoIBAHssRtPM1GacWsom -8zfeN6ZbI4KDlbetZz0vhnqDk9NVrpijWlcOP5dwZXVNitnB/HaqCqFvyPDY9JNB -zI/pEFW4QH59FVDP42mVEt0keCTP/1wfiDDGh1vLqVBYl/ZphscDcNgDTzNkuxMx -k+LFVxKnn3w7rGc59lALSkpeGvbbIDjp3LUMlUeCF8CIFyYZh9ZvXe4OCxYdyjxb -i8tnMLKvJ4Psbh5jMapsu3rHQkfPdqzztQUz8vs0NYwP5vWge46FUyk+WNm/IhbJ -G3YM22nwUS8Eu2bmTtADSJolATbCSkOwQ1D+Fybz/4obfYeGaCdOqB05ttubhenV -ShsAb7ECgYEA20ecRVxw2S7qA7sqJ4NuYOg9TpfGooptYNA1IP971eB6SaGAelEL -awYkGNuu2URmm5ElZpwJFFTDLGA7t2zB2xI1FeySPPIVPvJGSiZoFQOVlIg9WQzK -7jTtFQ/tOMrF+bigEUJh5bP1/7HzqSpuOsPjEUb2aoCTp+tpiRGL7TUCgYEAwtns -g3ysrSEcTzpSv7fQRJRk1lkBhatgNd0oc+ikzf74DaVLhBg1jvSThDhiDCdB59mr -Jh41cnR1XqE8jmdQbCDRiFrI1Pq6TPaDZFcovDVE1gue9x86v3FOH2ukPG4d2/Xy -HevXjThtpMMsWFi0JYXuzXuV5HOvLZiP8sN3lSMCgYANpdxdGM7RRbE9ADY0dWK2 -V14ReTLcxP7fyrWz0xLzEeCqmomzkz3BsIUoouu0DCTSw+rvAwExqcDoDylIVlWO -fAifz7SeZHbcDxo+3TsXK7zwnLYsx7YNs2+aIv6hzUUbMNmNmXMcZ+IEwx+mRMTN -lYmZdrA5mr0V83oDFPt/jQKBgC74RVE03pMlZiObFZNtheDiPKSG9Bz6wMh7NWMr -c37MtZLkg52mEFMTlfPLe6ceV37CM8WOhqe+dwSGrYhOU06dYqUR7VOZ1Qr0aZvo -fsNPu/Y0+u7rMkgv0fs1AXQnvz7kvKaF0YITVirfeXMafuKEtJoH7owRbur42cpV -YCAtAoGAP1rHOc+w0RUcBK3sY7aErrih0OPh9U5bvJsrw1C0FIZhCEoDVA+fNIQL -syHLXYFNy0OxMtH/bBAXBGNHd9gf5uOnqh0pYcbe/uRAxumC7Rl0cL509eURiA2T -+vFmf54y9YdnLXaqv+FhJT6B6V7WX7IpU9BMqJY1cJYXHuHG2KA= ------END RSA PRIVATE KEY----- -EOM - end - - 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"/ ) - end - - 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"/ ) - Chef::Config.chef_server_url.should == 'http://localhost:9999' - end - - context 'when the default port (8889) is already bound' do - before :each do - begin - @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. - end - end - after :each do - @server.stop if @server - end - - 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 - before :each do - begin - @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. - end - end - after :each do - @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"/ ) - 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"/ ) - 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"/ ) - Chef::Config.chef_server_url.should == 'http://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 deleted file mode 100644 index e59c8912bd..0000000000 --- a/spec/integration/knife/cookbook_api_ipv6_spec.rb +++ /dev/null @@ -1,112 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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 'support/shared/integration/integration_helper' -require 'chef/mixin/shell_out' - -describe "Knife cookbook API integration with IPv6", :workstation do - include IntegrationSupport - include Chef::Mixin::ShellOut - - when_the_chef_server "is bound to IPv6" do - let(:chef_zero_opts) { {:host => "::1"} } - - let(:client_key) do - <<-END_VALIDATION_PEM ------BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEApubutqtYYQ5UiA9QhWP7UvSmsfHsAoPKEVVPdVW/e8Svwpyf -0Xef6OFWVmBE+W442ZjLOe2y6p2nSnaq4y7dg99NFz6X+16mcKiCbj0RCiGqCvCk -NftHhTgO9/RFvCbmKZ1RKNob1YzLrFpxBHaSh9po+DGWhApcd+I+op+ZzvDgXhNn -0nauZu3rZmApI/r7EEAOjFedAXs7VPNXhhtZAiLSAVIrwU3ZajtSzgXOxbNzgj5O -AAAMmThK+71qPdffAdO4J198H6/MY04qgtFo7vumzCq0UCaGZfmeI1UNE4+xQWwP -HJ3pDAP61C6Ebx2snI2kAd9QMx9Y78nIedRHPwIDAQABAoIBAHssRtPM1GacWsom -8zfeN6ZbI4KDlbetZz0vhnqDk9NVrpijWlcOP5dwZXVNitnB/HaqCqFvyPDY9JNB -zI/pEFW4QH59FVDP42mVEt0keCTP/1wfiDDGh1vLqVBYl/ZphscDcNgDTzNkuxMx -k+LFVxKnn3w7rGc59lALSkpeGvbbIDjp3LUMlUeCF8CIFyYZh9ZvXe4OCxYdyjxb -i8tnMLKvJ4Psbh5jMapsu3rHQkfPdqzztQUz8vs0NYwP5vWge46FUyk+WNm/IhbJ -G3YM22nwUS8Eu2bmTtADSJolATbCSkOwQ1D+Fybz/4obfYeGaCdOqB05ttubhenV -ShsAb7ECgYEA20ecRVxw2S7qA7sqJ4NuYOg9TpfGooptYNA1IP971eB6SaGAelEL -awYkGNuu2URmm5ElZpwJFFTDLGA7t2zB2xI1FeySPPIVPvJGSiZoFQOVlIg9WQzK -7jTtFQ/tOMrF+bigEUJh5bP1/7HzqSpuOsPjEUb2aoCTp+tpiRGL7TUCgYEAwtns -g3ysrSEcTzpSv7fQRJRk1lkBhatgNd0oc+ikzf74DaVLhBg1jvSThDhiDCdB59mr -Jh41cnR1XqE8jmdQbCDRiFrI1Pq6TPaDZFcovDVE1gue9x86v3FOH2ukPG4d2/Xy -HevXjThtpMMsWFi0JYXuzXuV5HOvLZiP8sN3lSMCgYANpdxdGM7RRbE9ADY0dWK2 -V14ReTLcxP7fyrWz0xLzEeCqmomzkz3BsIUoouu0DCTSw+rvAwExqcDoDylIVlWO -fAifz7SeZHbcDxo+3TsXK7zwnLYsx7YNs2+aIv6hzUUbMNmNmXMcZ+IEwx+mRMTN -lYmZdrA5mr0V83oDFPt/jQKBgC74RVE03pMlZiObFZNtheDiPKSG9Bz6wMh7NWMr -c37MtZLkg52mEFMTlfPLe6ceV37CM8WOhqe+dwSGrYhOU06dYqUR7VOZ1Qr0aZvo -fsNPu/Y0+u7rMkgv0fs1AXQnvz7kvKaF0YITVirfeXMafuKEtJoH7owRbur42cpV -YCAtAoGAP1rHOc+w0RUcBK3sY7aErrih0OPh9U5bvJsrw1C0FIZhCEoDVA+fNIQL -syHLXYFNy0OxMtH/bBAXBGNHd9gf5uOnqh0pYcbe/uRAxumC7Rl0cL509eURiA2T -+vFmf54y9YdnLXaqv+FhJT6B6V7WX7IpU9BMqJY1cJYXHuHG2KA= ------END RSA PRIVATE KEY----- -END_VALIDATION_PEM - end - - let(:cache_path) do - Dir.mktmpdir - end - - let(:chef_dir) { File.join(File.dirname(__FILE__), "..", "..", "..", "bin") } - let(:knife) { "ruby '#{chef_dir}/knife'" } - - let(:knife_config_flag) { "-c '#{path_to("config/knife.rb")}'" } - - # Some Solaris test platforms are too old for IPv6. These tests should not - # otherwise be platform dependent, so exclude solaris - context "and the chef_server_url contains an IPv6 literal", :not_supported_on_solaris do - - # This provides helper functions we need such as #path_to() - when_the_repository "has the cookbook to be uploaded" do - - let(:knife_rb_content) do - <<-END_CLIENT_RB -chef_server_url "http://[::1]:8900" -syntax_check_cache_path '#{cache_path}' -client_key '#{path_to('config/knifeuser.pem')}' -node_name 'whoisthisis' -cookbook_path '#{CHEF_SPEC_DATA}/cookbooks' -END_CLIENT_RB - end - - before do - file 'config/knife.rb', knife_rb_content - file 'config/knifeuser.pem', client_key - end - - it "successfully uploads a cookbook" do - shell_out!("#{knife} cookbook upload apache2 #{knife_config_flag}", :cwd => chef_dir) - versions_list_json = Chef::HTTP::Simple.new("http://[::1]:8900").get("/cookbooks/apache2", "accept" => "application/json") - versions_list = Chef::JSONCompat.from_json(versions_list_json) - versions_list["apache2"]["versions"].should_not be_empty - end - - context "and the cookbook has been uploaded to the server" do - before do - shell_out!("#{knife} cookbook upload apache2 #{knife_config_flag}", :cwd => chef_dir) - end - - it "downloads the cookbook" do - shell_out!("knife cookbook download apache2 #{knife_config_flag} -d #{cache_path}", :cwd => chef_dir) - Dir["#{cache_path}/*"].map {|entry| File.basename(entry)}.should include("apache2-0.0.1") - end - end - - end - end - end -end diff --git a/spec/integration/knife/delete_spec.rb b/spec/integration/knife/delete_spec.rb deleted file mode 100644 index 733a7ef72b..0000000000 --- a/spec/integration/knife/delete_spec.rb +++ /dev/null @@ -1,1003 +0,0 @@ -# -# Author:: John Keiser (<jkeiser@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 'support/shared/integration/integration_helper' -require 'chef/knife/delete' -require 'chef/knife/list' -require 'chef/knife/raw' - -describe 'knife delete', :workstation do - include IntegrationSupport - include KnifeSupport - - let :everything do - <<EOM -/clients -/clients/x.json -/cookbooks -/cookbooks/x -/cookbooks/x/metadata.rb -/data_bags -/data_bags/x -/data_bags/x/y.json -/environments -/environments/_default.json -/environments/x.json -/nodes -/nodes/x.json -/roles -/roles/x.json -/users -/users/x.json -EOM - end - - let :server_everything do - <<EOM -/clients -/clients/chef-validator.json -/clients/chef-webui.json -/clients/x.json -/cookbooks -/cookbooks/x -/cookbooks/x/metadata.rb -/data_bags -/data_bags/x -/data_bags/x/y.json -/environments -/environments/_default.json -/environments/x.json -/nodes -/nodes/x.json -/roles -/roles/x.json -/users -/users/admin.json -/users/x.json -EOM - end - let :server_nothing do - <<EOM -/clients -/clients/chef-validator.json -/clients/chef-webui.json -/cookbooks -/data_bags -/environments -/environments/_default.json -/nodes -/roles -/users -/users/admin.json -EOM - end - - let :nothing do - <<EOM -/clients -/cookbooks -/data_bags -/environments -/nodes -/roles -/users -EOM - end - - 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', '{}' - end - - 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 -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 - 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 -/clients -/clients/chef-validator.json -/clients/chef-webui.json -/clients/x.json -/cookbooks -/data_bags -/data_bags/x -/data_bags/x/y.json -/environments -/environments/_default.json -/environments/x.json -/nodes -/nodes/x.json -/roles -/roles/x.json -/users -/users/admin.json -/users/x.json -EOM - knife('list -Rf --local /').should_succeed <<EOM -/clients -/clients/x.json -/cookbooks -/data_bags -/data_bags/x -/data_bags/x/y.json -/environments -/environments/_default.json -/environments/x.json -/nodes -/nodes/x.json -/roles -/roles/x.json -/users -/users/x.json -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 -/clients -/clients/x.json -/cookbooks -/data_bags -/data_bags/x -/data_bags/x/y.json -/environments -/environments/_default.json -/environments/x.json -/nodes -/nodes/x.json -/roles -/roles/x.json -/users -/users/x.json -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 -/clients -/clients/chef-validator.json -/clients/chef-webui.json -/clients/x.json -/cookbooks -/data_bags -/data_bags/x -/data_bags/x/y.json -/environments -/environments/_default.json -/environments/x.json -/nodes -/nodes/x.json -/roles -/roles/x.json -/users -/users/admin.json -/users/x.json -EOM - 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 - before do - 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 -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 -/clients -/clients/chef-validator.json -/clients/chef-webui.json -/clients/x.json -/cookbooks -/cookbooks/x -/cookbooks/x/metadata.rb -/data_bags -/data_bags/empty -/data_bags/x -/data_bags/x/y.json -/environments -/environments/_default.json -/environments/x.json -/nodes -/nodes/x.json -/roles -/roles/x.json -/users -/users/admin.json -/users/x.json -EOM - knife('list -Rf --local /').should_succeed <<EOM -/clients -/clients/x.json -/cookbooks -/cookbooks/x -/cookbooks/x/metadata.rb -/data_bags -/data_bags/empty -/data_bags/x -/data_bags/x/y.json -/environments -/environments/_default.json -/environments/x.json -/nodes -/nodes/x.json -/roles -/roles/x.json -/users -/users/x.json -EOM - end - end - - 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 - 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 -/clients -/clients/chef-validator.json -/clients/chef-webui.json -/clients/x.json -/cookbooks -/cookbooks/x -/cookbooks/x/metadata.rb -/data_bags -/environments -/environments/_default.json -/environments/x.json -/nodes -/nodes/x.json -/roles -/roles/x.json -/users -/users/admin.json -/users/x.json -EOM - knife('list -Rf --local /').should_succeed <<EOM -/clients -/clients/x.json -/cookbooks -/cookbooks/x -/cookbooks/x/metadata.rb -/data_bags -/environments -/environments/_default.json -/environments/x.json -/nodes -/nodes/x.json -/roles -/roles/x.json -/users -/users/x.json -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 -/clients -/clients/chef-validator.json -/clients/chef-webui.json -/clients/x.json -/cookbooks -/cookbooks/x -/cookbooks/x/metadata.rb -/data_bags -/data_bags/x -/data_bags/x/y.json -/environments -/environments/_default.json -/nodes -/nodes/x.json -/roles -/roles/x.json -/users -/users/admin.json -/users/x.json -EOM - knife('list -Rf --local /').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/_default.json -/nodes -/nodes/x.json -/roles -/roles/x.json -/users -/users/x.json -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 -/clients -/clients/chef-validator.json -/clients/chef-webui.json -/clients/x.json -/cookbooks -/cookbooks/x -/cookbooks/x/metadata.rb -/data_bags -/data_bags/x -/data_bags/x/y.json -/environments -/environments/_default.json -/environments/x.json -/nodes -/nodes/x.json -/roles -/users -/users/admin.json -/users/x.json -EOM - knife('list -Rf --local /').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/_default.json -/environments/x.json -/nodes -/nodes/x.json -/roles -/users -/users/x.json -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 -/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 - - 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 -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 - end - - 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. -ERROR: /clients (local) cannot be deleted. -ERROR: /cookbooks (remote) cannot be deleted. -ERROR: /cookbooks (local) cannot be deleted. -ERROR: /data_bags (remote) cannot be deleted. -ERROR: /data_bags (local) cannot be deleted. -ERROR: /environments (remote) cannot be deleted. -ERROR: /environments (local) cannot be deleted. -ERROR: /nodes (remote) cannot be deleted. -ERROR: /nodes (local) cannot be deleted. -ERROR: /roles (remote) cannot be deleted. -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 - end - end - - 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 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 -/clients -/clients/chef-validator.json -/clients/chef-webui.json -/clients/x.json -/cookbooks -/data_bags -/data_bags/x -/data_bags/x/y.json -/environments -/environments/_default.json -/environments/x.json -/nodes -/nodes/x.json -/roles -/roles/x.json -/users -/users/admin.json -/users/x.json -EOM - 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 - 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 -/clients -/clients/chef-validator.json -/clients/chef-webui.json -/clients/x.json -/cookbooks -/cookbooks/x -/cookbooks/x/metadata.rb -/data_bags -/environments -/environments/_default.json -/environments/x.json -/nodes -/nodes/x.json -/roles -/roles/x.json -/users -/users/admin.json -/users/x.json -EOM - 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 -/clients -/clients/chef-validator.json -/clients/chef-webui.json -/clients/x.json -/cookbooks -/cookbooks/x -/cookbooks/x/metadata.rb -/data_bags -/data_bags/x -/data_bags/x/y.json -/environments -/environments/_default.json -/nodes -/nodes/x.json -/roles -/roles/x.json -/users -/users/admin.json -/users/x.json -EOM - 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 -/clients -/clients/chef-validator.json -/clients/chef-webui.json -/clients/x.json -/cookbooks -/cookbooks/x -/cookbooks/x/metadata.rb -/data_bags -/data_bags/x -/data_bags/x/y.json -/environments -/environments/_default.json -/environments/x.json -/nodes -/nodes/x.json -/roles -/users -/users/admin.json -/users/x.json -EOM - 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 - 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 - end - - 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. -ERROR: /clients (local) cannot be deleted. -ERROR: /cookbooks (remote) cannot be deleted. -ERROR: /cookbooks (local) cannot be deleted. -ERROR: /data_bags (remote) cannot be deleted. -ERROR: /data_bags (local) cannot be deleted. -ERROR: /environments (remote) cannot be deleted. -ERROR: /environments (local) cannot be deleted. -ERROR: /nodes (remote) cannot be deleted. -ERROR: /nodes (local) cannot be deleted. -ERROR: /roles (remote) cannot be deleted. -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 - 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 - 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 -clients -clients/chef-validator.json -clients/chef-webui.json -clients/x.json -cookbooks -cookbooks/x -cookbooks/x/metadata.rb -data_bags -data_bags/x -data_bags/x/y.json -environments -environments/_default.json -environments/x.json -nodes -nodes/x.json -roles -roles/x.json -users -users/admin.json -users/x.json -EOM - knife('list -Rf --local /').should_succeed <<EOM -clients -cookbooks -data_bags -environments -nodes -roles -users -EOM - end - end - end - end - - 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 -/clients -/clients/x.json -/cookbooks -/data_bags -/data_bags/x -/data_bags/x/y.json -/environments -/environments/_default.json -/environments/x.json -/nodes -/nodes/x.json -/roles -/roles/x.json -/users -/users/x.json -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 - 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 -/clients -/clients/x.json -/cookbooks -/cookbooks/x -/cookbooks/x/metadata.rb -/data_bags -/environments -/environments/_default.json -/environments/x.json -/nodes -/nodes/x.json -/roles -/roles/x.json -/users -/users/x.json -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 -/clients -/clients/x.json -/cookbooks -/cookbooks/x -/cookbooks/x/metadata.rb -/data_bags -/data_bags/x -/data_bags/x/y.json -/environments -/environments/_default.json -/nodes -/nodes/x.json -/roles -/roles/x.json -/users -/users/x.json -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 -/clients -/clients/x.json -/cookbooks -/cookbooks/x -/cookbooks/x/metadata.rb -/data_bags -/data_bags/x -/data_bags/x/y.json -/environments -/environments/_default.json -/environments/x.json -/nodes -/nodes/x.json -/roles -/users -/users/x.json -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 -/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 - - 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 -ERROR: / (remote) cannot be deleted. -ERROR: / (local) cannot be deleted. -ERROR: /clients (remote) cannot be deleted. -ERROR: /clients (local) cannot be deleted. -ERROR: /cookbooks (remote) cannot be deleted. -ERROR: /cookbooks (local) cannot be deleted. -ERROR: /data_bags (remote) cannot be deleted. -ERROR: /data_bags (local) cannot be deleted. -ERROR: /environments (remote) cannot be deleted. -ERROR: /environments (local) cannot be deleted. -ERROR: /nodes (remote) cannot be deleted. -ERROR: /nodes (local) cannot be deleted. -ERROR: /roles (remote) cannot be deleted. -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 - 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 - 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 -clients -clients/chef-validator.json -clients/chef-webui.json -cookbooks -data_bags -environments -environments/_default.json -nodes -roles -users -users/admin.json -EOM - knife('list -Rf --local /').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/_default.json -environments/x.json -nodes -nodes/x.json -roles -roles/x.json -users -users/x.json -EOM - end - end - end - end - - 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' - end - - 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' } - 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 '' - end - end - - 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' } - 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 '' - 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' } } - - 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' } } - - 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 - before do - 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/ ) - 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', {} - end - end - - before :each do - 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" - 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/) - 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/) - 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" - 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 deleted file mode 100644 index 8b4d71906b..0000000000 --- a/spec/integration/knife/deps_spec.rb +++ /dev/null @@ -1,712 +0,0 @@ -# -# Author:: John Keiser (<jkeiser@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 'support/shared/integration/integration_helper' -require 'support/shared/context/config' -require 'chef/knife/deps' - -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" - end - end - - 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 -/roles/minor.json -/cookbooks/quiche -/cookbooks/soup -/roles/starring.json -EOM - end - end - - 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 -/roles/minor.json -/cookbooks/quiche -/cookbooks/soup -/roles/starring.json -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" - end - end - when_the_repository 'has a node with an environment' do - before do - 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" - end - end - 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 -/roles/minor.json -/cookbooks/quiche -/cookbooks/soup -/nodes/mort.json -EOM - end - end - 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', '' - end - 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 - before do - file 'cookbooks/kettle/metadata.rb', 'name "kettle"' - file 'cookbooks/quiche/metadata.rb', 'name "quiche" -depends "kettle"' - 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" - 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" - 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" - end - end - 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]' ] } - end - - it 'knife deps reports all dependencies' do - knife('deps /nodes/mort.json').should_succeed <<EOM -/environments/desert.json -/roles/minor.json -/cookbooks/quiche -/cookbooks/soup -/roles/starring.json -/nodes/mort.json -EOM - end - 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 -/cookbooks/quiche -/cookbooks/soup -/roles/starring.json -/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 -/roles/minor.json -/nodes/bart.json -/environments/desert.json -/cookbooks/quiche -/cookbooks/soup -/roles/starring.json -/nodes/mort.json -EOM - end - 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 - /environments/desert.json - /roles/starring.json - /roles/minor.json - /cookbooks/quiche - /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 -/nodes/bart.json - /roles/minor.json -/nodes/mort.json - /environments/desert.json - /roles/starring.json -EOM - end - end - - context 'circular dependencies' do - when_the_repository 'has cookbooks with circular dependencies' do - before do - file 'cookbooks/foo/metadata.rb', 'name "foo" -depends "bar"' - file 'cookbooks/bar/metadata.rb', 'name "bar" -depends "baz"' - file 'cookbooks/baz/metadata.rb', 'name "baz" -depends "foo"' - 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 - 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 - end - end - 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]' ] } - end - 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 - stdout.should == "/roles/foo.json\n /roles/bar.json\n /roles/baz.json\n /roles/foo.json\n/roles/self.json\n /roles/self.json\n" - stderr.should == "WARNING: No knife configuration file found\n" - end - end - 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( - :exit_code => 2, - :stdout => "/blah\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( - :exit_code => 2, - :stdout => "/roles/x.json\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( - :exit_code => 2, - :stdout => "/nodes/x.json\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( - :exit_code => 2, - :stdout => "/environments/x.json\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( - :exit_code => 2, - :stdout => "/cookbooks/x\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( - :exit_code => 2, - :stdout => "/data_bags/bag/item\n", - :stderr => "ERROR: /data_bags/bag/item: No such file or directory\n" - ) - end - end - when_the_repository 'is missing a dependent cookbook' do - before do - 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( - :exit_code => 2, - :stdout => "/cookbooks/quiche\n/roles/starring.json\n", - :stderr => "ERROR: /cookbooks/quiche: No such file or directory\n" - ) - end - end - when_the_repository 'is missing a dependent environment' do - before do - 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( - :exit_code => 2, - :stdout => "/environments/desert.json\n/nodes/mort.json\n", - :stderr => "ERROR: /environments/desert.json: No such file or directory\n" - ) - end - end - when_the_repository 'is missing a dependent role' do - before do - 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( - :exit_code => 2, - :stdout => "/roles/minor.json\n/roles/starring.json\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") - end - 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" - ) - 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") - 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( - "/cookbooks/blah/metadata.rb\n" - ) - end - end - end - end - - 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" - end - end - - 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' => '' } } - end - it 'knife deps reports all dependencies' do - knife('deps --remote /roles/starring.json').should_succeed <<EOM -/roles/minor.json -/cookbooks/quiche -/cookbooks/soup -/roles/starring.json -EOM - end - end - - 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' => '' } } - end - it 'knife deps reports all dependencies' do - knife('deps --remote /roles/starring.json').should_succeed <<EOM -/roles/minor.json -/cookbooks/quiche -/cookbooks/soup -/roles/starring.json -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" - end - end - when_the_chef_server 'has a node with an environment' do - before do - 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" - end - end - 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]) } - end - it 'knife deps reports just the node' do - knife('deps --remote /nodes/mort.json').should_succeed <<EOM -/roles/minor.json -/cookbooks/quiche -/cookbooks/soup -/nodes/mort.json -EOM - end - end - 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' => '' } } - end - 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 - 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' => '' } } - end - 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" - 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" - end - end - 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]' ] } - end - - it 'knife deps reports all dependencies' do - knife('deps --remote /nodes/mort.json').should_succeed <<EOM -/environments/desert.json -/roles/minor.json -/cookbooks/quiche -/cookbooks/soup -/roles/starring.json -/nodes/mort.json -EOM - end - 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 -/cookbooks/quiche -/cookbooks/soup -/roles/starring.json -/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 -/roles/minor.json -/nodes/bart.json -/environments/desert.json -/cookbooks/quiche -/cookbooks/soup -/roles/starring.json -/nodes/mort.json -EOM - end - 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 - /environments/desert.json - /roles/starring.json - /roles/minor.json - /cookbooks/quiche - /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 -/nodes/bart.json - /roles/minor.json -/nodes/mort.json - /environments/desert.json - /roles/starring.json -EOM - end - end - - 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" -depends "bar"' } - cookbook 'bar', '1.0.0', { 'metadata.rb' => 'name "bar" -depends "baz"' } - cookbook 'baz', '1.0.0', { 'metadata.rb' => 'name "baz" -depends "foo"' } - 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 -/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 -/cookbooks/foo - /cookbooks/bar - /cookbooks/baz - /cookbooks/foo -/cookbooks/self - /cookbooks/self -EOM - end - end - 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]' ] } - end - 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 - stdout.should == "/roles/foo.json\n /roles/bar.json\n /roles/baz.json\n /roles/foo.json\n/roles/self.json\n /roles/self.json\n" - stderr.should == "WARNING: No knife configuration file found\n" - end - end - 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( - :exit_code => 2, - :stdout => "/blah\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( - :exit_code => 2, - :stdout => "/roles/x.json\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( - :exit_code => 2, - :stdout => "/nodes/x.json\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( - :exit_code => 2, - :stdout => "/environments/x.json\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( - :exit_code => 2, - :stdout => "/cookbooks/x\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( - :exit_code => 2, - :stdout => "/data_bags/bag/item\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 - before do - 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( - :exit_code => 2, - :stdout => "/cookbooks/quiche\n/roles/starring.json\n", - :stderr => "ERROR: /cookbooks/quiche: No such file or directory\n" - ) - end - end - when_the_chef_server 'is missing a dependent environment' do - before do - 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( - :exit_code => 2, - :stdout => "/environments/desert.json\n/nodes/mort.json\n", - :stderr => "ERROR: /environments/desert.json: No such file or directory\n" - ) - end - end - when_the_chef_server 'is missing a dependent role' do - before do - 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( - :exit_code => 2, - :stdout => "/roles/minor.json\n/roles/starring.json\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") - end - 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") - end - end - when_the_chef_server 'has a cookbook' do - before do - 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( - "/cookbooks/blah/metadata.rb\n" - ) - end - end - end - end - - 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 deleted file mode 100644 index c12ebbcf8f..0000000000 --- a/spec/integration/knife/diff_spec.rb +++ /dev/null @@ -1,602 +0,0 @@ -# -# Author:: John Keiser (<jkeiser@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 'support/shared/integration/integration_helper' -require 'chef/knife/diff' - -describe 'knife diff', :workstation do - include IntegrationSupport - include KnifeSupport - - 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', '{}' - end - - 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 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 -D\t/cookbooks/x -D\t/data_bags/x -D\t/environments/_default.json -D\t/environments/x.json -D\t/nodes/x.json -D\t/roles/x.json -D\t/users/admin.json -D\t/users/x.json -EOM - end - end - - 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 } - end - - 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" - 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" - end - - context 'except the role file' do - before do - 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 -M\t/roles/x.json -EOM - 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 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 -A\t/data_bags/x/z.json -A\t/data_bags/y -A\t/environments/y.json -A\t/nodes/y.json -A\t/roles/y.json -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 -A\tx/z.json -A\ty -EOM - end - it 'knife diff * reports different data bags' do - knife('diff --name-status *').should_succeed <<EOM -A\tx/z.json -A\ty -EOM - end - end - end - end - - 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 -D\t/environments -D\t/nodes -D\t/roles -D\t/users -EOM - end - end - end - - 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', '' - end - - 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' => '' } - end - - 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 -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 - before do - 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 '' - end - end - - 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' => '' } - end - - 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 -EOM - end - end - - 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' => '' } - end - - 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 -EOM - end - end - end - - context 'json diff tests' do - when_the_repository 'has an empty environment file' do - before do - 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 '' - 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', :pending => (RUBY_VERSION < "1.9") do - knife('diff /environments/x.json').should_succeed(/ - { -- "name": "x", -- "description": "hi" -\+ "name": "x" - } -/) - end - end - end - - when_the_repository 'has an environment file with a value in it' do - before do - file 'environments/x.json', { 'description' => 'hi' } - end - - when_the_chef_server 'has an environment with the same value' do - before do - environment 'x', { 'description' => 'hi' } - end - 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 do - environment 'x', {} - end - - it 'knife diff reports the difference', :pending => (RUBY_VERSION < "1.9") do - knife('diff /environments/x.json').should_succeed(/ - { -- "name": "x" -\+ "name": "x", -\+ "description": "hi" - } -/) - end - end - when_the_chef_server 'has an environment with a different value' do - before do - environment 'x', { 'description' => 'lo' } - end - it 'knife diff reports the difference', :pending => (RUBY_VERSION < "1.9") do - knife('diff /environments/x.json').should_succeed(/ - { - "name": "x", -- "description": "lo" -\+ "description": "hi" - } -/) - end - end - 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 - 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) - end - end - end - end # without versioned cookbooks - - 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', '{}' - end - - 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 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 -D\t/cookbooks/x-1.0.0 -D\t/data_bags/x -D\t/environments/_default.json -D\t/environments/x.json -D\t/nodes/x.json -D\t/roles/x.json -D\t/users/admin.json -D\t/users/x.json -EOM - end - end - - 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 } - end - - 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" - 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" - end - - context 'except the role file' do - before do - 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 -M\t/roles/x.json -EOM - end - end - - 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', {} - end - - 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 -A\t/cookbooks/y-1.0.0 -A\t/data_bags/x/z.json -A\t/data_bags/y -A\t/environments/y.json -A\t/nodes/y.json -A\t/roles/y.json -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 -A\tx/z.json -A\ty -EOM - end - it 'knife diff * reports different data bags' do - knife('diff --name-status *').should_succeed <<EOM -A\tx/z.json -A\ty -EOM - end - end - end - end - - 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 -D\t/environments -D\t/nodes -D\t/roles -D\t/users -EOM - end - end - end - - 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', '' - end - - 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' => '' } - end - - 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 '' - end - end - - 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' => '' } - end - 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 - before do - 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 -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 - before do - 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 -D\t/cookbooks/x-0.9.9 -A\t/cookbooks/x-1.0.0 -EOM - end - 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 '' - 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', :pending => (RUBY_VERSION < "1.9") do - knife('diff /environments/x.json').should_succeed(/ - { -- "name": "x", -- "description": "hi" -\+ "name": "x" - } -/) - end - end - end - - when_the_repository 'has an environment file with a value in it' do - before do - file 'environments/x.json', { 'description' => 'hi' } - end - - when_the_chef_server 'has an environment with the same value' do - before do - environment 'x', { 'description' => 'hi' } - end - 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', :pending => (RUBY_VERSION < "1.9") do - knife('diff /environments/x.json').should_succeed(/ - { -- "name": "x" -\+ "name": "x", -\+ "description": "hi" - } -/) - end - end - when_the_chef_server 'has an environment with a different value' do - before do - environment 'x', { 'description' => 'lo' } - end - it 'knife diff reports the difference', :pending => (RUBY_VERSION < "1.9") do - knife('diff /environments/x.json').should_succeed(/ - { - "name": "x", -- "description": "lo" -\+ "description": "hi" - } -/) - end - end - 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 - 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) - end - end - end - end # without versioned cookbooks -end diff --git a/spec/integration/knife/download_spec.rb b/spec/integration/knife/download_spec.rb deleted file mode 100644 index 0c2b907f1e..0000000000 --- a/spec/integration/knife/download_spec.rb +++ /dev/null @@ -1,1170 +0,0 @@ -# -# Author:: John Keiser (<jkeiser@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 'support/shared/integration/integration_helper' -require 'chef/knife/download' -require 'chef/knife/diff' - -describe 'knife download', :workstation do - include IntegrationSupport - include KnifeSupport - - 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', {} - end - - 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 download downloads everything' do - knife('download /').should_succeed <<EOM -Created /clients/chef-validator.json -Created /clients/chef-webui.json -Created /clients/x.json -Created /cookbooks/x -Created /cookbooks/x/metadata.rb -Created /data_bags/x -Created /data_bags/x/y.json -Created /environments/_default.json -Created /environments/x.json -Created /nodes/x.json -Created /roles/x.json -Created /users/admin.json -Created /users/x.json -EOM - knife('diff --name-status /').should_succeed '' - end - end - - 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 } - end - - 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 '' - end - - context 'except the role file' do - before do - file 'roles/x.json', <<EOM -{ - "chef_type": "role", - "default_attributes": { - }, - "description": "blarghle", - "env_run_lists": { - }, - "json_class": "Chef::Role", - "name": "x", - "override_attributes": { - }, - "run_list": [ - - ] -} -EOM - end - - 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" - end - end - - context 'except the role file is textually different, but not ACTUALLY different' do - before do - file 'roles/x.json', <<EOM -{ - "chef_type": "role", - "default_attributes": { - }, - "env_run_lists": { - }, - "json_class": "Chef::Role", - "name": "x", - "description": "", - "override_attributes": { - }, - "run_list": [ - - ] -} -EOM - end - - 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 - 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 } - end - - 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 -A\t/data_bags/x/z.json -A\t/data_bags/y -A\t/environments/y.json -A\t/nodes/y.json -A\t/roles/y.json -A\t/users/y.json -EOM - end - - 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) -Deleted extra entry /data_bags/x/z.json (purge is on) -Deleted extra entry /data_bags/y (purge is on) -Deleted extra entry /environments/y.json (purge is on) -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 '' - end - end - end - - 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 -Created /clients/x.json -Created /cookbooks -Created /cookbooks/x -Created /cookbooks/x/metadata.rb -Created /data_bags -Created /data_bags/x -Created /data_bags/x/y.json -Created /environments -Created /environments/_default.json -Created /environments/x.json -Created /nodes -Created /nodes/x.json -Created /roles -Created /roles/x.json -Created /users -Created /users/admin.json -Created /users/x.json -EOM - knife('diff --name-status /').should_succeed '' - end - - 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 -Created /clients/x.json -Created /cookbooks -Created /cookbooks/x -Created /cookbooks/x/metadata.rb -Created /data_bags -Created /data_bags/x -Created /data_bags/x/y.json -Created /environments -Created /environments/_default.json -Created /environments/x.json -Created /nodes -Created /nodes/x.json -Created /roles -Created /roles/x.json -Created /users -Created /users/admin.json -Created /users/x.json -EOM - knife('diff --name-status /').should_succeed '' - end - - context 'when current directory is top level' do - before do - 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/ - 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 - before do - 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 -Created /data_bags -Created /data_bags/x -Created /data_bags/x/y.json -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 -Created /data_bags -Created /data_bags/x -Created /data_bags/x/y.json -Created /data_bags/x/z.json -EOM - end - end - end - - when_the_repository 'has three data bag items' do - before do - file 'data_bags/x/deleted.json', <<EOM -{ - "id": "deleted" -} -EOM - file 'data_bags/x/modified.json', <<EOM -{ - "id": "modified" -} -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 - before do - 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 -Updated /data_bags/x/modified.json -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 -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 -Created /data_bags/x/added.json -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 -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 -Deleted extra entry /data_bags/x/deleted.json (purge is on) -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 -Created /data_bags/x/added.json -Updated /data_bags/x/modified.json -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 -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 '' - end - context 'when cwd is the /data_bags directory' do - before do - 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/ - end - 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 '' - end - 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 '' - end - end - end - end - - 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', '' - end - - 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' } - 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 -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 -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 -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 -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 -Updated /cookbooks/x/metadata.rb -Created /cookbooks/x/y.rb -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 -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 '' - end - end - end - - 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' - end - - 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' } - end - - 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 '' - end - end - - 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' } - end - - 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 '' - end - end - - 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' } - end - - 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 '' - end - end - - 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' } - end - - 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 '' - end - end - end - - when_the_chef_server 'has an environment' do - before do - environment 'x', {} - end - when_the_repository 'has an environment with bad JSON' do - before do - file 'environments/x.json', '{' - end - 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 '' - end - end - - when_the_repository 'has the same environment with the wrong name in the file' do - before do - 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 '' - end - end - - when_the_repository 'has the same environment with no name in the file' do - before do - 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 '' - end - end - end - end # without versioned cookbooks - - 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', {} - end - - 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 download downloads everything' do - knife('download /').should_succeed <<EOM -Created /clients/chef-validator.json -Created /clients/chef-webui.json -Created /clients/x.json -Created /cookbooks/x-1.0.0 -Created /cookbooks/x-1.0.0/metadata.rb -Created /data_bags/x -Created /data_bags/x/y.json -Created /environments/_default.json -Created /environments/x.json -Created /nodes/x.json -Created /roles/x.json -Created /users/admin.json -Created /users/x.json -EOM - knife('diff --name-status /').should_succeed '' - end - end - - 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 } - end - - 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 '' - end - - context 'except the role file' do - before do - 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 '' - end - end - - context 'except the role file is textually different, but not ACTUALLY different' do - before do - file 'roles/x.json', <<EOM -{ - "chef_type": "role" , - "default_attributes": { - }, - "env_run_lists": { - }, - "json_class": "Chef::Role", - "name": "x", - "description": "", - "override_attributes": { - }, - "run_list": [ - - ] -} -EOM - end - - 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 - 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 } - end - - 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 -A\t/cookbooks/y-1.0.0 -A\t/data_bags/x/z.json -A\t/data_bags/y -A\t/environments/y.json -A\t/nodes/y.json -A\t/roles/y.json -A\t/users/y.json -EOM - end - - 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) -Deleted extra entry /cookbooks/y-1.0.0 (purge is on) -Deleted extra entry /data_bags/x/z.json (purge is on) -Deleted extra entry /data_bags/y (purge is on) -Deleted extra entry /environments/y.json (purge is on) -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 '' - end - end - end - - 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 -Created /clients/x.json -Created /cookbooks -Created /cookbooks/x-1.0.0 -Created /cookbooks/x-1.0.0/metadata.rb -Created /data_bags -Created /data_bags/x -Created /data_bags/x/y.json -Created /environments -Created /environments/_default.json -Created /environments/x.json -Created /nodes -Created /nodes/x.json -Created /roles -Created /roles/x.json -Created /users -Created /users/admin.json -Created /users/x.json -EOM - knife('diff --name-status /').should_succeed '' - end - - context 'when current directory is top level' do - before do - 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/ - 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 - before do - 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 -Created /data_bags -Created /data_bags/x -Created /data_bags/x/y.json -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 - before do - file 'data_bags/x/deleted.json', <<EOM -{ - "id": "deleted" -} -EOM - file 'data_bags/x/modified.json', <<EOM -{ - "id": "modified" -} -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 - before do - 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 -Updated /data_bags/x/modified.json -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 -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 -Created /data_bags/x/added.json -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 -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 -Deleted extra entry /data_bags/x/deleted.json (purge is on) -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 -Created /data_bags/x/added.json -Updated /data_bags/x/modified.json -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 -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 '' - end - context 'when cwd is the /data_bags directory' do - before do - 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/ - end - 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 '' - end - 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 '' - end - end - end - end - - 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', '' - end - - 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' } - 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 -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 -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 -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 -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 -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 -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 -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 '' - end - end - end - - 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' - end - - 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' } - end - - 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 '' - end - end - - 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' } - end - - 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 '' - end - end - - 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' } - end - - 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 '' - end - end - - 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' } - end - - 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 '' - end - end - end - - when_the_chef_server 'has an environment' do - before do - environment 'x', {} - end - - when_the_repository 'has the same environment with the wrong name in the file' do - before do - 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 '' - end - end - - when_the_repository 'has the same environment with no name in the file' do - before do - 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 '' - end - end - end - end # with versioned cookbooks - - when_the_chef_server 'has a cookbook' do - before do - cookbook 'x', '1.0.0' - end - - when_the_repository 'is empty' do - it 'knife download /cookbooks/x signs all requests', :ruby_gte_19_only do - - # Check that BasicClient.request() always gets called with X-OPS-USERID - original_new = Chef::HTTP::BasicClient.method(:new) - Chef::HTTP::BasicClient.should_receive(:new) do |args| - new_result = original_new.call(*args) - original_request = new_result.method(:request) - new_result.should_receive(:request) do |method, url, body, headers, &response_handler| - headers['X-OPS-USERID'].should_not be_nil - original_request.call(method, url, body, headers, &response_handler) - end.at_least(:once) - new_result - end.at_least(:once) - - knife('download /cookbooks/x').should_succeed <<EOM -Created /cookbooks -Created /cookbooks/x -Created /cookbooks/x/metadata.rb -EOM - 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', {} - end - end - - before :each do - 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 -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/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/roles.json -Created /acls/containers/sandboxes.json -Created /acls/containers/x.json -Created /acls/cookbooks -Created /acls/data_bags -Created /acls/environments -Created /acls/environments/_default.json -Created /acls/groups -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/roles -Created /acls/organization.json -Created /clients -Created /clients/foo-validator.json -Created /containers -Created /containers/clients.json -Created /containers/containers.json -Created /containers/cookbooks.json -Created /containers/data.json -Created /containers/environments.json -Created /containers/groups.json -Created /containers/nodes.json -Created /containers/roles.json -Created /containers/sandboxes.json -Created /containers/x.json -Created /cookbooks -Created /data_bags -Created /environments -Created /environments/_default.json -Created /groups -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 /roles -EOM - knife('diff --name-status /').should_succeed '' - end - end - end -end diff --git a/spec/integration/knife/list_spec.rb b/spec/integration/knife/list_spec.rb deleted file mode 100644 index 3d8b83001d..0000000000 --- a/spec/integration/knife/list_spec.rb +++ /dev/null @@ -1,865 +0,0 @@ -# -# Author:: John Keiser (<jkeiser@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 'support/shared/integration/integration_helper' -require 'support/shared/context/config' -require 'chef/knife/list' - -describe 'knife list', :workstation do - include IntegrationSupport - include KnifeSupport - - include_context "default config options" - - when_the_chef_server "is empty" do - it "knife list / returns all top level directories" do - knife('list /').should_succeed <<EOM -/clients -/cookbooks -/data_bags -/environments -/nodes -/roles -/users -EOM - end - - it "knife list -R / returns everything" do - knife('list -R /').should_succeed <<EOM -/: -clients -cookbooks -data_bags -environments -nodes -roles -users - -/clients: -chef-validator.json -chef-webui.json - -/cookbooks: - -/data_bags: - -/environments: -_default.json - -/nodes: - -/roles: - -/users: -admin.json -EOM - end - end - - 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', {} - end - - it "knife list / returns all top level directories" do - knife('list /').should_succeed <<EOM -/clients -/cookbooks -/data_bags -/environments -/nodes -/roles -/users -EOM - end - - it "knife list -R / returns everything" do - knife('list -R /').should_succeed <<EOM -/: -clients -cookbooks -data_bags -environments -nodes -roles -users - -/clients: -chef-validator.json -chef-webui.json -client1.json -client2.json - -/cookbooks: -cookbook1 -cookbook2 - -/cookbooks/cookbook1: -metadata.rb - -/cookbooks/cookbook2: -metadata.rb -recipes - -/cookbooks/cookbook2/recipes: -default.rb - -/data_bags: -bag1 -bag2 - -/data_bags/bag1: -item1.json -item2.json - -/data_bags/bag2: -item1.json -item2.json - -/environments: -_default.json -environment1.json -environment2.json - -/nodes: -node1.json -node2.json - -/roles: -role1.json -role2.json - -/users: -admin.json -user1.json -user2.json -EOM - end - - it "knife list -R --flat / returns everything" do - knife('list -R --flat /').should_succeed <<EOM -/clients -/clients/chef-validator.json -/clients/chef-webui.json -/clients/client1.json -/clients/client2.json -/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 -/nodes -/nodes/node1.json -/nodes/node2.json -/roles -/roles/role1.json -/roles/role2.json -/users -/users/admin.json -/users/user1.json -/users/user2.json -EOM - end - - it "knife list -Rfp / returns everything" do - knife('list -Rfp /').should_succeed <<EOM -/clients/ -/clients/chef-validator.json -/clients/chef-webui.json -/clients/client1.json -/clients/client2.json -/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 -/nodes/ -/nodes/node1.json -/nodes/node2.json -/roles/ -/roles/role1.json -/roles/role2.json -/users/ -/users/admin.json -/users/user1.json -/users/user2.json -EOM - end - - it "knife list /cookbooks returns the list of cookbooks" do - 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" - end - - it "knife list /**.rb returns all ruby files" do - knife('list /**.rb').should_succeed <<EOM -/cookbooks/cookbook1/metadata.rb -/cookbooks/cookbook2/metadata.rb -/cookbooks/cookbook2/recipes/default.rb -EOM - end - - it "knife list /cookbooks/**.rb returns all ruby files" do - knife('list /cookbooks/**.rb').should_succeed <<EOM -/cookbooks/cookbook1/metadata.rb -/cookbooks/cookbook2/metadata.rb -/cookbooks/cookbook2/recipes/default.rb -EOM - end - - it "knife list /**.json returns all json files" do - knife('list /**.json').should_succeed <<EOM -/clients/chef-validator.json -/clients/chef-webui.json -/clients/client1.json -/clients/client2.json -/data_bags/bag1/item1.json -/data_bags/bag1/item2.json -/data_bags/bag2/item1.json -/data_bags/bag2/item2.json -/environments/_default.json -/environments/environment1.json -/environments/environment2.json -/nodes/node1.json -/nodes/node2.json -/roles/role1.json -/roles/role2.json -/users/admin.json -/users/user1.json -/users/user2.json -EOM - end - - it "knife list /data**.json returns all data bag json files" do - knife('list /data**.json').should_succeed <<EOM -/data_bags/bag1/item1.json -/data_bags/bag1/item2.json -/data_bags/bag2/item1.json -/data_bags/bag2/item2.json -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" - 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" - 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" - 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" - 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 '.' } - - it "knife list -Rfp returns everything" do - knife('list -Rfp').should_succeed <<EOM -clients/ -clients/chef-validator.json -clients/chef-webui.json -clients/client1.json -clients/client2.json -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 -nodes/ -nodes/node1.json -nodes/node2.json -roles/ -roles/role1.json -roles/role2.json -users/ -users/admin.json -users/user1.json -users/user2.json -EOM - end - end - end - - 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 -/clients/ -/clients/chef-validator.json -/clients/chef-webui.json -/clients/client1.json -/clients/client2.json -./ -cookbook1/ -cookbook1/metadata.rb -cookbook2/ -cookbook2/metadata.rb -cookbook2/recipes/ -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 -/nodes/ -/nodes/node1.json -/nodes/node2.json -/roles/ -/roles/role1.json -/roles/role2.json -/users/ -/users/admin.json -/users/user1.json -/users/user2.json -EOM - end - - it "knife list -Rfp .. returns everything" do - knife('list -Rfp ..').should_succeed <<EOM -/clients/ -/clients/chef-validator.json -/clients/chef-webui.json -/clients/client1.json -/clients/client2.json -./ -cookbook1/ -cookbook1/metadata.rb -cookbook2/ -cookbook2/metadata.rb -cookbook2/recipes/ -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 -/nodes/ -/nodes/node1.json -/nodes/node2.json -/roles/ -/roles/role1.json -/roles/role2.json -/users/ -/users/admin.json -/users/user1.json -/users/user2.json -EOM - end - - it "knife list -Rfp returns cookbooks" do - knife('list -Rfp').should_succeed <<EOM -cookbook1/ -cookbook1/metadata.rb -cookbook2/ -cookbook2/metadata.rb -cookbook2/recipes/ -cookbook2/recipes/default.rb -EOM - end - end - end - - 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' } - - it "knife list -Rfp returns cookbooks" do - knife('list -Rfp').should_succeed <<EOM -metadata.rb -recipes/ -recipes/default.rb -EOM - end - end - end - - when_the_repository 'has a cookbooks directory and a symlinked cookbooks directory', :pending => (Chef::Platform.windows?) do - before do - directory 'cookbooks' - symlink 'symlinked', 'cookbooks' - end - - context 'when cwd is in cookbooks/' do - before { cwd 'cookbooks' } - - it "knife list -Rfp returns cookbooks" do - knife('list -Rfp').should_succeed <<EOM -cookbook1/ -cookbook1/metadata.rb -cookbook2/ -cookbook2/metadata.rb -cookbook2/recipes/ -cookbook2/recipes/default.rb -EOM - end - end - - context 'when cwd is in symlinked/' do - before { cwd 'symlinked' } - - it "knife list -Rfp returns cookbooks" do - knife('list -Rfp').should_succeed <<EOM -cookbook1/ -cookbook1/metadata.rb -cookbook2/ -cookbook2/metadata.rb -cookbook2/recipes/ -cookbook2/recipes/default.rb -EOM - end - end - end - - when_the_repository 'has a real_cookbooks directory and a cookbooks symlink to it', :pending => (Chef::Platform.windows?) do - before do - directory 'real_cookbooks' - symlink 'cookbooks', 'real_cookbooks' - end - - 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 -cookbook1/ -cookbook1/metadata.rb -cookbook2/ -cookbook2/metadata.rb -cookbook2/recipes/ -cookbook2/recipes/default.rb -EOM - end - end - - context 'when cwd is in cookbooks/' do - before { cwd 'cookbooks' } - - it "knife list -Rfp returns cookbooks" do - knife('list -Rfp').should_succeed <<EOM -cookbook1/ -cookbook1/metadata.rb -cookbook2/ -cookbook2/metadata.rb -cookbook2/recipes/ -cookbook2/recipes/default.rb -EOM - end - end - end - end - end - - context "--local" do - when_the_repository "is empty" do - it "knife list --local / returns nothing" do - 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" - end - end - - when_the_repository "has a bunch of stuff" do - before do - file 'clients/client1.json', {} - file 'clients/client2.json', {} - - 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', '' - end - - directory 'data_bags' do - directory 'bag1' do - file 'item1.json', {} - file 'item2.json', {} - end - 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', {} - end - - it "knife list -Rfp / returns everything" do - knife('list -Rp --local --flat /').should_succeed <<EOM -/clients/ -/clients/client1.json -/clients/client2.json -/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/environment1.json -/environments/environment2.json -/nodes/ -/nodes/node1.json -/nodes/node2.json -/roles/ -/roles/role1.json -/roles/role2.json -/users/ -/users/user1.json -/users/user2.json -EOM - end - - 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" - 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" - 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" - end - 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 - - context 'and is empty' do - it "knife list / returns all top level directories" do - knife('list /').should_succeed <<EOM -/acls -/clients -/containers -/cookbooks -/data_bags -/environments -/groups -/invitations.json -/members.json -/nodes -/org.json -/roles -EOM - end - - it "knife list -R / returns everything" do - knife('list -R /').should_succeed <<EOM -/: -acls -clients -containers -cookbooks -data_bags -environments -groups -invitations.json -members.json -nodes -org.json -roles - -/acls: -clients -containers -cookbooks -data_bags -environments -groups -nodes -organization.json -roles - -/acls/clients: -foo-validator.json - -/acls/containers: -clients.json -containers.json -cookbooks.json -data.json -environments.json -groups.json -nodes.json -roles.json -sandboxes.json - -/acls/cookbooks: - -/acls/data_bags: - -/acls/environments: -_default.json - -/acls/groups: -admins.json -billing-admins.json -clients.json -users.json - -/acls/nodes: - -/acls/roles: - -/clients: -foo-validator.json - -/containers: -clients.json -containers.json -cookbooks.json -data.json -environments.json -groups.json -nodes.json -roles.json -sandboxes.json - -/cookbooks: - -/data_bags: - -/environments: -_default.json - -/groups: -admins.json -billing-admins.json -clients.json -users.json - -/nodes: - -/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 -/: -acls -clients -containers -cookbooks -data_bags -environments -groups -invitations.json -members.json -nodes -org.json -roles - -/acls: -clients -containers -cookbooks -data_bags -environments -groups -nodes -organization.json -roles - -/acls/clients: -foo-validator.json - -/acls/containers: -clients.json -containers.json -cookbooks.json -data.json -environments.json -groups.json -nodes.json -roles.json -sandboxes.json - -/acls/cookbooks: - -/acls/data_bags: - -/acls/environments: -_default.json - -/acls/groups: -admins.json -billing-admins.json -clients.json -users.json - -/acls/nodes: - -/acls/roles: - -/clients: -foo-validator.json - -/containers: -clients.json -containers.json -cookbooks.json -data.json -environments.json -groups.json -nodes.json -roles.json -sandboxes.json - -/cookbooks: - -/data_bags: - -/environments: -_default.json - -/groups: -admins.json -billing-admins.json -clients.json -users.json - -/nodes: - -/roles: -EOM - end - end -end diff --git a/spec/integration/knife/raw_spec.rb b/spec/integration/knife/raw_spec.rb deleted file mode 100644 index 2b49d2ebb2..0000000000 --- a/spec/integration/knife/raw_spec.rb +++ /dev/null @@ -1,242 +0,0 @@ -# -# Author:: John Keiser (<jkeiser@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 'support/shared/integration/integration_helper' -require 'support/shared/context/config' -require 'chef/knife/raw' -require 'chef/knife/show' - -describe 'knife raw', :workstation do - include IntegrationSupport - include KnifeSupport - include AppServerSupport - - include_context "default config options" - - 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', '{}' - end - - it 'knife raw /nodes/x returns the node', :pending => (RUBY_VERSION < "1.9") do - knife('raw /nodes/x').should_succeed <<EOM -{ - "name": "x", - "json_class": "Chef::Node", - "chef_type": "node", - "chef_environment": "_default", - "override": { - - }, - "normal": { - - }, - "default": { - - }, - "automatic": { - - }, - "run_list": [ - - ] -} -EOM - end - - 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', :pending => (RUBY_VERSION < "1.9") do - knife('raw -m DELETE /roles/x').should_succeed <<EOM -{ - "name": "x", - "description": "", - "json_class": "Chef::Role", - "chef_type": "role", - "default_attributes": { - - }, - "override_attributes": { - - }, - "run_list": [ - - ], - "env_run_lists": { - - } -} -EOM - 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', :pending => (RUBY_VERSION < "1.9") do - Tempfile.open('raw_put_input') do |file| - file.write <<EOM -{ - "name": "x", - "description": "eek", - "json_class": "Chef::Role", - "chef_type": "role", - "default_attributes": { - - }, - "override_attributes": { - - }, - "run_list": [ - - ], - "env_run_lists": { - - } -} -EOM - file.close - - knife("raw -m PUT -i #{file.path} /roles/x").should_succeed <<EOM -{ - "name": "x", - "description": "eek", - "json_class": "Chef::Role", - "chef_type": "role", - "default_attributes": { - - }, - "override_attributes": { - - }, - "run_list": [ - - ], - "env_run_lists": { - - } -} -EOM - knife('show /roles/x.json').should_succeed <<EOM -/roles/x.json: -{ - "name": "x", - "description": "eek" -} -EOM - end - end - - it 'knife raw -m POST -i blah.txt /roles succeeds', :pending => (RUBY_VERSION < "1.9") do - Tempfile.open('raw_put_input') do |file| - file.write <<EOM -{ - "name": "y", - "description": "eek", - "json_class": "Chef::Role", - "chef_type": "role", - "default_attributes": { - }, - "override_attributes": { - }, - "run_list": [ - - ], - "env_run_lists": { - } -} -EOM - file.close - - knife("raw -m POST -i #{file.path} /roles").should_succeed <<EOM -{ - "uri": "#{Chef::Config.chef_server_url}/roles/y" -} -EOM - knife('show /roles/y.json').should_succeed <<EOM -/roles/y.json: -{ - "name": "y", - "description": "eek" -} -EOM - end - end - - 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" }'] ] - end - @raw_server, @raw_server_thread = start_app_server(app, 9018) - end - - after :each do - @raw_server.shutdown if @raw_server - @raw_server_thread.kill if @raw_server_thread - end - - it 'knife raw /blah returns the prettified json', :pending => (RUBY_VERSION < "1.9") do - knife('raw /blah').should_succeed <<EOM -{ - "x": "y", - "a": "b" -} -EOM - end - - 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 - before :each do - Chef::Config.chef_server_url = "http://localhost:9018" - app = lambda do |env| - [200, {'Content-Type' => 'text' }, ['{ "x": "y", "a": "b" }'] ] - end - @raw_server, @raw_server_thread = start_app_server(app, 9018) - end - - after :each do - @raw_server.shutdown if @raw_server - @raw_server_thread.kill if @raw_server_thread - end - - 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) -{ "x": "y", "a": "b" } -EOM - end - end - end -end diff --git a/spec/integration/knife/redirection_spec.rb b/spec/integration/knife/redirection_spec.rb deleted file mode 100644 index 77bda99453..0000000000 --- a/spec/integration/knife/redirection_spec.rb +++ /dev/null @@ -1,52 +0,0 @@ -# -# Author:: John Keiser (<jkeiser@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 'support/shared/integration/integration_helper' -require 'support/shared/context/config' -require 'chef/knife/list' - -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', {} } - - 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'] ] - end - @redirector_server, @redirector_server_thread = start_app_server(app, 9018) - end - - after :each do - @redirector_server.shutdown if @redirector_server - @redirector_thread.kill if @redirector_thread - end - - it 'knife list /roles returns the role' do - knife('list /roles').should_succeed "/roles/x.json\n" - end - end - end -end diff --git a/spec/integration/knife/serve_spec.rb b/spec/integration/knife/serve_spec.rb deleted file mode 100644 index 3c859b794e..0000000000 --- a/spec/integration/knife/serve_spec.rb +++ /dev/null @@ -1,57 +0,0 @@ -# -# Author:: John Keiser (<jkeiser@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 'support/shared/integration/integration_helper' -require 'chef/knife/serve' -require 'chef/server_api' - -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' } } - - it 'knife serve serves up /nodes/x' do - exception = nil - t = Thread.new do - begin - knife('serve --chef-zero-port=8889') - rescue - exception = $! - end - end - begin - Chef::Config.log_level = :debug - Chef::Config.chef_server_url = 'http://localhost:8889' - Chef::Config.node_name = nil - Chef::Config.client_key = nil - api = Chef::ServerAPI.new - api.get('nodes/x')['name'].should == 'x' - rescue - if exception - raise exception - else - raise - end - ensure - t.kill - end - end - end -end diff --git a/spec/integration/knife/show_spec.rb b/spec/integration/knife/show_spec.rb deleted file mode 100644 index bc7f1cf6d3..0000000000 --- a/spec/integration/knife/show_spec.rb +++ /dev/null @@ -1,167 +0,0 @@ -# -# Author:: John Keiser (<jkeiser@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 'support/shared/integration/integration_helper' -require 'support/shared/context/config' -require 'chef/knife/show' - -describe 'knife show', :workstation do - include IntegrationSupport - include KnifeSupport - - include_context "default config options" - - 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', '{}' - end - - 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' } - end - - 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 -/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 -/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 -/data_bags/x/y.json: -{ - "foo": "bar" -} -EOM - end - it 'knife show /environments/x.json shows the remote version', :pending => (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 -/environments/x.json: -{ - "foo": "bar" -} -EOM - end - it 'knife show /roles/x.json shows the remote version', :pending => (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 -/roles/x.json: -{ - "foo": "bar" -} -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" - 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" - 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" - 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" - end - end - end - - 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' - } - end - it 'knife show shows the attributes in a predetermined order', :pending => (RUBY_VERSION < "1.9") do - knife('show /environments/x.json').should_succeed <<EOM -/environments/x.json: -{ - "name": "x", - "description": "woo", - "cookbook_versions": { - "blah": "= 1.0.0" - }, - "default_attributes": { - "foo": "bar" - }, - "override_attributes": { - "x": "y" - } -} -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 -/environments/x.json: -{ -EOM - end - end -end diff --git a/spec/integration/knife/upload_spec.rb b/spec/integration/knife/upload_spec.rb deleted file mode 100644 index 1db2f613b3..0000000000 --- a/spec/integration/knife/upload_spec.rb +++ /dev/null @@ -1,1372 +0,0 @@ -# -# Author:: John Keiser (<jkeiser@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 'support/shared/integration/integration_helper' -require 'chef/knife/upload' -require 'chef/knife/diff' -require 'chef/knife/raw' - -describe 'knife upload', :workstation do - include IntegrationSupport - include KnifeSupport - - 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', {} - end - - 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 -D\t/clients/chef-validator.json -D\t/clients/chef-webui.json -D\t/clients/x.json -D\t/cookbooks/x -D\t/data_bags/x -D\t/environments/_default.json -D\t/environments/x.json -D\t/nodes/x.json -D\t/roles/x.json -D\t/users/admin.json -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") -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) -Deleted extra entry /cookbooks/x (purge is on) -Deleted extra entry /data_bags/x (purge is on) -Deleted extra entry /environments/x.json (purge is on) -Deleted extra entry /nodes/x.json (purge is on) -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 -D\t/environments/_default.json -EOM - end - end - - 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 } - end - - 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 '' - end - - context 'except the role file' do - before do - 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 '' - 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" - end - end - - context 'except the role file is textually different, but not ACTUALLY different' do - before do - file 'roles/x.json', <<EOM -{ - "chef_type": "role", - "default_attributes": { - }, - "env_run_lists": { - }, - "json_class": "Chef::Role", - "name": "x", - "description": "", - "override_attributes": { - }, - "run_list": [ - - ] -} -EOM - end - - 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 - 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 -Created /data_bags/x/z.json -Created /data_bags/y -Created /data_bags/y/zz.json -Created /environments/y.json -Created /nodes/y.json -Created /roles/y.json -Created /users/y.json -EOM - knife('diff --name-status /').should_succeed '' - end - - 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 -Created /data_bags/x/z.json -Created /data_bags/y -Created /data_bags/y/zz.json -Created /environments/y.json -Created /nodes/y.json -Created /roles/y.json -Created /users/y.json -EOM - 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 -D\t/clients -D\t/cookbooks -D\t/data_bags -D\t/environments -D\t/nodes -D\t/roles -D\t/users -EOM - end - - 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. -ERROR: /environments cannot be deleted. -ERROR: /nodes cannot be deleted. -ERROR: /roles cannot be deleted. -ERROR: /users cannot be deleted. -EOM - knife('diff --name-status /').should_succeed <<EOM -D\t/clients -D\t/cookbooks -D\t/data_bags -D\t/environments -D\t/nodes -D\t/roles -D\t/users -EOM - end - - context 'when current directory is top level' do - before do - 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/ - end - end - end - end - - 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' } - 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 -Created /data_bags/x -Created /data_bags/x/y.json -EOM - knife('diff --name-status /data_bags').should_succeed <<EOM -EOM - JSON.parse(knife('raw /data/x/y').stdout, :create_additions => false).keys.sort.should == [ '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 -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 - - before do - 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 -Created /data_bags/x -Created /data_bags/x/y.json -EOM - knife('diff --name-status /data_bags').should_succeed '' - result = JSON.parse(knife('raw /data/x/y').stdout, :create_additions => false) - result.keys.sort.should == [ 'chef_type', 'data_bag', 'id' ] - result['chef_type'].should == 'aaa' - result['data_bag'].should == '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 - before do - 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 -Created /data_bags/x -Created /data_bags/x/y.json -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 - - before do - data_bag 'x', { 'deleted' => {}, 'modified' => {}, 'unmodified' => {} } - end - - 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', {} - end - - 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 -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 -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 -Created /data_bags/x/added.json -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 -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 -Deleted extra entry /data_bags/x/deleted.json (purge is on) -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 -Created /data_bags/x/added.json -Updated /data_bags/x/modified.json -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 -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 '' - end - context 'when cwd is the /data_bags directory' do - - before do - 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/ - end - - 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 '' - end - 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 '' - end - end - end - end - - # 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 - - before do - cookbook 'x', '1.0.0', { 'z.rb' => '' } - end - - 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' - 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" - 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 -Updated /cookbooks/x -EOM - 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 -Updated /cookbooks/x -EOM - knife('diff --name-status /cookbooks').should_succeed '' - end - end - when_the_repository 'has a missing file for the cookbook' do - - before do - 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 -Updated /cookbooks/x -EOM - knife('diff --name-status /cookbooks').should_succeed '' - end - end - 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', '' - end - - 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 '' - end - end - - when_the_repository 'has a different file in the cookbook' do - before do - 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 -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" - end - end - end - - when_the_chef_server 'has a frozen cookbook' do - before do - cookbook 'frozencook', '1.0.0', {}, :frozen => true - end - - 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") - 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" - end - 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 - before do - 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 - before do - 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 -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 -Updated /cookbooks/x -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 -EOM - end - end - - 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' } - end - - 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 '' - end - end - - 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' } - end - - 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 -Updated /cookbooks/x -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 -EOM - end - end - - 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' } - end - - 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 '' - end - end - end - - when_the_chef_server 'has an environment' do - before do - environment 'x', {} - end - - when_the_repository 'has an environment with bad JSON' do - before do - file 'environments/x.json', '{' - end - - it 'knife upload tries and fails' do - error1 = <<-EOH -WARN: Parse error reading #{path_to('environments/x.json')} as JSON: parse error: premature EOF - { - (right here) ------^ - -ERROR: /environments/x.json failed to write: Parse error reading JSON: parse error: premature EOF - { - (right here) ------^ -EOH - - warn = <<-EOH -WARN: Parse error reading #{path_to('environments/x.json')} as JSON: parse error: premature EOF - { - (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) - end - end - - when_the_repository 'has the same environment with the wrong name in the file' do - before do - 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" - end - end - - when_the_repository 'has the same environment with no name in the file' do - before do - 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 '' - end - end - end - - when_the_chef_server 'is empty' do - - when_the_repository 'has an environment with the wrong name in the file' do - before do - 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" - end - end - - when_the_repository 'has an environment with no name in the file' do - - before do - 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 '' - end - end - - when_the_repository 'has a data bag with no id in the file' do - before do - 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 '' - end - end - end - end # without versioned cookbooks - - 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', {} - end - - 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 -D\t/clients/chef-validator.json -D\t/clients/chef-webui.json -D\t/clients/x.json -D\t/cookbooks/x-1.0.0 -D\t/data_bags/x -D\t/environments/_default.json -D\t/environments/x.json -D\t/nodes/x.json -D\t/roles/x.json -D\t/users/admin.json -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") -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) -Deleted extra entry /cookbooks/x-1.0.0 (purge is on) -Deleted extra entry /data_bags/x (purge is on) -Deleted extra entry /environments/x.json (purge is on) -Deleted extra entry /nodes/x.json (purge is on) -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 -D\t/environments/_default.json -EOM - end - end - - 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 } - end - - 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 '' - end - - context 'except the role file' do - before do - 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 '' - end - end - - context 'except the role file is textually different, but not ACTUALLY different' do - - before do - file 'roles/x.json', <<EOM -{ - "chef_type": "role", - "default_attributes": { - }, - "env_run_lists": { - }, - "json_class": "Chef::Role", - "name": "x", - "description": "", - "override_attributes": { - }, - "run_list": [ - - ] -} -EOM - end - - 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 - 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 } - end - - 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 -Created /cookbooks/y-1.0.0 -Created /data_bags/x/z.json -Created /data_bags/y -Created /data_bags/y/zz.json -Created /environments/y.json -Created /nodes/y.json -Created /roles/y.json -Created /users/y.json -EOM - 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 -D\t/clients -D\t/cookbooks -D\t/data_bags -D\t/environments -D\t/nodes -D\t/roles -D\t/users -EOM - end - - 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. -ERROR: /environments cannot be deleted. -ERROR: /nodes cannot be deleted. -ERROR: /roles cannot be deleted. -ERROR: /users cannot be deleted. -EOM - knife('diff --name-status /').should_succeed <<EOM -D\t/clients -D\t/cookbooks -D\t/data_bags -D\t/environments -D\t/nodes -D\t/roles -D\t/users -EOM - end - - context 'when current directory is top level' do - before do - 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/ - 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 - before do - 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 -Created /data_bags/x -Created /data_bags/x/y.json -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 - before do - data_bag 'x', { 'deleted' => {}, 'modified' => {}, 'unmodified' => {} } - end - 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', {} - end - - 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 -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 -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 -Created /data_bags/x/added.json -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 -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 -Deleted extra entry /data_bags/x/deleted.json (purge is on) -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 -Created /data_bags/x/added.json -Updated /data_bags/x/modified.json -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 -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 '' - end - context 'when cwd is the /data_bags directory' do - before do - 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/ - end - 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 '' - end - 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 '' - end - end - end - end - - # 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 - before do - cookbook 'x', '1.0.0', { 'z.rb' => '' } - end - - 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' - 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" - 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 -Updated /cookbooks/x-1.0.0 -EOM - 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 -Updated /cookbooks/x-1.0.0 -EOM - knife('diff --name-status /cookbooks').should_succeed '' - end - end - - 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") - end - - 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 '' - end - end - - 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', '' - end - - 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 '' - end - end - end - - 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' - end - - 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' } - end - - 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 -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 '' - end - end - - 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' } - end - 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 '' - end - end - - 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' } - end - - 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 -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 '' - end - end - - 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' } - end - - 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 '' - end - end - end - - when_the_chef_server 'has an environment' do - before do - environment 'x', {} - end - - when_the_repository 'has the same environment with the wrong name in the file' do - before do - 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" - end - end - - when_the_repository 'has the same environment with no name in the file' do - before do - 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 '' - end - end - end - - when_the_chef_server 'is empty' do - - when_the_repository 'has an environment with the wrong name in the file' do - before do - 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" - end - end - - when_the_repository 'has an environment with no name in the file' do - before do - 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 '' - end - end - - when_the_repository 'has a data bag with no id in the file' do - before do - 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 '' - end - end - end - end # with versioned cookbooks - - when_the_chef_server 'has a user' do - before do - user 'x', {} - end - - 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' } - end - 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'} - end - - before :each do - 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', {} - - when_the_repository 'has 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 -Updated /acls/groups/blah.json -Created /clients/x.json -Created /containers/x.json -Created /cookbooks/x -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 -Updated /org.json -Created /roles/x.json -EOM - api.get('association_requests').map { |a| a['username'] }.should == [ 'foo' ] - api.get('users').map { |a| a['user']['username'] }.should == [ 'bar' ] - end - end - - when_the_repository 'has an org.json that does not change full_name' do - before do - 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 '' - api.get('/')['full_name'].should == 'Something' - end - end - - when_the_repository 'has an org.json that changes full_name' do - before do - 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" - api.get('/')['full_name'].should == 'Something Else' - end - end - - 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 - before do - 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" - api.get('association_requests').map { |a| a['username'] }.should == [ 'foo', 'foobar' ] - api.get('users').map { |a| a['user']['username'] }.should == [ 'bar' ] - end - end - - when_the_repository 'wants to make foo, bar and foobar members' do - before do - 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" - api.get('association_requests').map { |a| a['username'] }.should == [ ] - api.get('users').map { |a| a['user']['username'] }.should == [ 'bar', 'foo', 'foobar' ] - end - end - - when_the_repository 'wants to invite foo and have bar as a member' do - before do - file 'invitations.json', [ 'foo' ] - file 'members.json', [ 'bar' ] - end - - it 'knife upload / does nothing' do - knife('upload /').should_succeed '' - api.get('association_requests').map { |a| a['username'] }.should == [ 'foo' ] - api.get('users').map { |a| a['user']['username'] }.should == [ 'bar' ] - end - end - end - - context 'and has invited bar and foo' do - org_invite 'bar', 'foo' - - when_the_repository 'wants to invite foo and bar (different order)' do - before do - file 'invitations.json', [ 'foo', 'bar' ] - end - - it 'knife upload / does nothing' do - knife('upload /').should_succeed '' - api.get('association_requests').map { |a| a['username'] }.should == [ 'bar', 'foo' ] - api.get('users').map { |a| a['user']['username'] }.should == [ ] - end - end - end - - 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 - before do - file 'members.json', [ 'foo', 'bar' ] - end - - it 'knife upload / does nothing' do - knife('upload /').should_succeed '' - api.get('association_requests').map { |a| a['username'] }.should == [ ] - api.get('users').map { |a| a['user']['username'] }.should == [ 'bar', 'foo' ] - end - end - end - end - end -end diff --git a/spec/integration/recipes/lwrp_inline_resources_spec.rb b/spec/integration/recipes/lwrp_inline_resources_spec.rb deleted file mode 100644 index a0c13da6f7..0000000000 --- a/spec/integration/recipes/lwrp_inline_resources_spec.rb +++ /dev/null @@ -1,78 +0,0 @@ -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") } - - # 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'" } - - when_the_repository "has a cookbook with a nested LWRP" do - before 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/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 - - 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 'x::default'", :cwd => chef_dir) - actual = result.stdout.lines.map { |l| l.chomp }.join("\n") - expected = <<EOM - * x_my_machine[me] action create - * x_do_nothing[a] action create (up to date) - * x_do_nothing[b] action create (up to date) - (up to date) - * x_my_machine[you] action create - * x_do_nothing[a] action create (up to date) - * x_do_nothing[b] action create (up to date) - (up to date) -EOM - expected = expected.lines.map { |l| l.chomp }.join("\n") - actual.should include(expected) - result.error! - end - end -end diff --git a/spec/integration/solo/solo_spec.rb b/spec/integration/solo/solo_spec.rb deleted file mode 100644 index 793789b754..0000000000 --- a/spec/integration/solo/solo_spec.rb +++ /dev/null @@ -1,142 +0,0 @@ -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 - include Chef::Mixin::ShellOut - - let(:chef_dir) { File.join(File.dirname(__FILE__), "..", "..", "..") } - - let(:cookbook_x_100_metadata_rb) { cb_metadata("x", "1.0.0") } - - let(:cookbook_ancient_100_metadata_rb) { cb_metadata("ancient", "1.0.0") } - - 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"' - end - - it "should complete with success" do - file 'config/solo.rb', <<EOM -cookbook_path "#{path_to('cookbooks')}" -file_cache_path "#{path_to('config/cache')}" -EOM - result = shell_out("ruby bin/chef-solo -c \"#{path_to('config/solo.rb')}\" -o 'x::default' -l debug", :cwd => chef_dir) - result.error! - result.stdout.should include("ITWORKS") - end - - it "should evaluate its node.json file" do - file 'config/solo.rb', <<EOM -cookbook_path "#{path_to('cookbooks')}" -file_cache_path "#{path_to('config/cache')}" -EOM - - file 'config/node.json',<<-E -{"run_list":["x::default"]} -E - - result = shell_out("ruby bin/chef-solo -c \"#{path_to('config/solo.rb')}\" -j '#{path_to('config/node.json')}' -l debug", :cwd => chef_dir) - result.error! - result.stdout.should include("ITWORKS") - end - - end - - 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/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 -cookbook_path "#{path_to('cookbooks')}" -file_cache_path "#{path_to('config/cache')}" -EOM - result = shell_out("ruby bin/chef-solo -c \"#{path_to('config/solo.rb')}\" -o 'x::default' -l debug", :cwd => chef_dir) - result.exitstatus.should == 0 # For CHEF-5120 this becomes 1 - result.stdout.should include("WARN: MissingCookbookDependency") - 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 -ruby_block "sleeping" do - block do - sleep 5 - end -end -EOM - end - - # Ruby 1.8.7 doesn't have Process.spawn :( - it "while running solo concurrently", :ruby_gte_19_only => true do - file 'config/solo.rb', <<EOM -cookbook_path "#{path_to('cookbooks')}" -file_cache_path "#{path_to('config/cache')}" -EOM - # We have a timeout protection here so that if due to some bug - # run_lock gets stuck we can discover it. - lambda { - Timeout.timeout(120) do - chef_dir = File.join(File.dirname(__FILE__), "..", "..", "..") - - # Instantiate the first chef-solo run - s1 = Process.spawn("ruby bin/chef-solo -c \"#{path_to('config/solo.rb')}\" -o 'x::default' \ --l debug -L #{path_to('logs/runs.log')}", :chdir => chef_dir) - - # Give it some time to progress - sleep 1 - - # Instantiate the second chef-solo run - s2 = Process.spawn("ruby bin/chef-solo -c \"#{path_to('config/solo.rb')}\" -o 'x::default' \ --l debug -L #{path_to('logs/runs.log')}", :chdir => chef_dir) - - Process.waitpid(s1) - Process.waitpid(s2) - end - }.should_not raise_error - - # 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')) - - # both of the runs should succeed - run_log.lines.reject {|l| !l.include? "INFO: Chef Run complete in"}.length.should == 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.length.should == 2 - pids = pid_lines.map {|l| l.split(" ").last} - run_log.should include("Chef client #{pids[0]} is running, will wait for it to finish and then run.") - - # second run should start after first run ends - starts = [ ] - ends = [ ] - run_log.lines.each_with_index do |line, index| - if line.include? "Chef-client pid:" - starts << index - elsif line.include? "INFO: Chef Run complete in" - ends << index - end - end - starts[1].should > ends[0] - end - - end -end diff --git a/spec/stress/win32/file_spec.rb b/spec/stress/win32/file_spec.rb deleted file mode 100644 index caeab352f7..0000000000 --- a/spec/stress/win32/file_spec.rb +++ /dev/null @@ -1,37 +0,0 @@ -# -# Author:: Seth Chisamore (<schisamo@opscode.com>) -# Copyright:: Copyright (c) 2011 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/file' if windows? - -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 - - it "should not leak significant memory" do - test = lambda { Chef::ReservedNames::Win32::File.symlink?(@path) } - test.should_not leak_memory(:warmup => 50000, :iterations => 50000) - end - - it "should not leak handles" do - test = lambda { Chef::ReservedNames::Win32::File.symlink?(@path) } - test.should_not leak_handles(:warmup => 50, :iterations => 100) - end - -end diff --git a/spec/stress/win32/memory_spec.rb b/spec/stress/win32/memory_spec.rb deleted file mode 100644 index ed3ad306d0..0000000000 --- a/spec/stress/win32/memory_spec.rb +++ /dev/null @@ -1,22 +0,0 @@ -# -# Author:: Seth Chisamore (<schisamo@opscode.com>) -# Copyright:: Copyright (c) 2011 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::ReservedNames::Win32::Memory', :windows_only do -end diff --git a/spec/stress/win32/security_spec.rb b/spec/stress/win32/security_spec.rb deleted file mode 100644 index e506b71be1..0000000000 --- a/spec/stress/win32/security_spec.rb +++ /dev/null @@ -1,69 +0,0 @@ -# -# Author:: Seth Chisamore (<schisamo@opscode.com>) -# Copyright:: Copyright (c) 2011 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' - -if windows? - require 'chef/win32/security' - require 'tmpdir' - require 'fileutils' -end - -describe 'Chef::ReservedNames::Win32::Security', :windows_only do - - def monkeyfoo - File.join(CHEF_SPEC_DATA, "monkeyfoo").gsub("/", "\\") - end - - before :all do - @test_tempdir = File.join(Dir::tmpdir, "cheftests", "chef_win32_security") - FileUtils.mkdir_p(@test_tempdir) - @monkeyfoo = File.join(@test_tempdir, "monkeyfoo.txt") - end - - before :each do - File.delete(@monkeyfoo) if File.exist?(@monkeyfoo) - # Make a file. - File.open(@monkeyfoo, "w") do |file| - file.write("hi") - end - end - - after :all do - FileUtils.rm_rf(@test_tempdir) - end - - it "should not leak when retrieving and reading the ACE from a file", :volatile do - lambda { - sids = Chef::ReservedNames::Win32::Security::SecurableObject.new(@monkeyfoo).security_descriptor.dacl.select { |ace| ace.sid } - GC.start - }.should_not leak_memory(:warmup => 50, :iterations => 100) - end - - it "should not leak when creating a new ACL and setting it on a file", :volatile do - securable_object = Security::SecurableObject.new(@monkeyfoo) - lambda { - 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) - ]) - GC.start - }.should_not leak_memory(:warmup => 50, :iterations => 100) - end - -end diff --git a/spec/unit/api_client/registration_spec.rb b/spec/unit/api_client/registration_spec.rb deleted file mode 100644 index d752429676..0000000000 --- a/spec/unit/api_client/registration_spec.rb +++ /dev/null @@ -1,252 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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 'tempfile' - -require 'chef/api_client/registration' - -describe Chef::ApiClient::Registration do - - let(:key_location) do - make_tmpname("client-registration-key") - end - - let(:client_name) { "silent-bob" } - - 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 } - end - - let(:http_mock) { double("Chef::REST mock") } - - let(:expected_post_data) do - { :name => client_name, :admin => false, :public_key => generated_public_key.to_pem } - end - - let(:expected_put_data) do - { :name => client_name, :admin => false, :public_key => generated_public_key.to_pem } - end - - let(:server_v10_response) do - {"uri" => "https://chef.local/clients/#{client_name}", - "private_key" => "--begin rsa key etc--"} - end - - # Server v11 includes `json_class` on all replies - let(:server_v11_response) do - response = Chef::ApiClient.new - response.name(client_name) - response.private_key("--begin rsa key etc--") - response - end - - 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) { 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 - } - 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} - end - - before do - Chef::Config[:validation_client_name] = "test-validator" - Chef::Config[:validation_key] = File.expand_path('ssl/private_key.pem', CHEF_SPEC_DATA) - OpenSSL::PKey::RSA.stub(:generate).with(2048).and_return(generated_private_key) - end - - after do - File.unlink(key_location) if File.exist?(key_location) - end - - it "has an HTTP client configured with validator credentials" do - registration.http_api.should be_a_kind_of(Chef::REST) - registration.http_api.client_name.should == "test-validator" - registration.http_api.signing_key.should == private_key_data - end - - describe "when creating/updating the client on the server" do - before do - registration.stub(:http_api).and_return(http_mock) - end - - it "posts a locally generated public key to the server to create a client" do - http_mock.should_receive(:post). - with("clients", expected_post_data). - and_return(create_with_pkey_response) - registration.create_or_update.should == create_with_pkey_response - registration.private_key.should == generated_private_key_pem - end - - it "puts a locally generated public key to the server to update a client" do - http_mock.should_receive(:post). - with("clients", expected_post_data). - and_raise(exception_409) - http_mock.should_receive(:put). - with("clients/#{client_name}", expected_put_data). - and_return(update_with_pkey_response) - registration.create_or_update.should == update_with_pkey_response - registration.private_key.should == generated_private_key_pem - end - - it "writes the generated private key to disk" do - http_mock.should_receive(:post). - with("clients", expected_post_data). - and_return(create_with_pkey_response) - registration.run - IO.read(key_location).should == generated_private_key_pem - end - - context "and the client already exists on a Chef 11 server" do - it "requests a new key from the server and saves it" do - http_mock.should_receive(:post).and_raise(exception_409) - http_mock.should_receive(:put). - with("clients/#{client_name}", expected_put_data). - and_return(update_with_pkey_response) - registration.create_or_update.should == update_with_pkey_response - registration.private_key.should == generated_private_key_pem - end - end - - context "when local key generation is disabled" do - - let(:expected_post_data) do - { :name => client_name, :admin => false } - end - - let(:expected_put_data) do - { :name => client_name, :admin => false, :private_key => true } - end - - before do - Chef::Config[:local_key_generation] = false - OpenSSL::PKey::RSA.should_not_receive(:generate) - end - - it "creates a new ApiClient on the server using the validator identity" do - http_mock.should_receive(:post). - with("clients", expected_post_data). - and_return(server_v10_response) - registration.create_or_update.should == server_v10_response - registration.private_key.should == "--begin rsa key etc--" - end - - context "and the client already exists on a Chef 11 server" do - it "requests a new key from the server and saves it" do - http_mock.should_receive(:post).and_raise(exception_409) - http_mock.should_receive(:put). - with("clients/#{client_name}", expected_put_data). - and_return(server_v11_response) - registration.create_or_update.should == server_v11_response - registration.private_key.should == "--begin rsa key etc--" - end - end - - context "and the client already exists on a Chef 10 server" do - it "requests a new key from the server and saves it" do - http_mock.should_receive(:post).with("clients", expected_post_data). - and_raise(exception_409) - http_mock.should_receive(:put). - with("clients/#{client_name}", expected_put_data). - and_return(server_v10_response) - registration.create_or_update.should == server_v10_response - registration.private_key.should == "--begin rsa key etc--" - end - end - end - end - - describe "when writing the private key to disk" do - before do - registration.stub(:private_key).and_return('--begin rsa key etc--') - end - - # Permission read via File.stat is busted on windows, though creating the - # file with 0600 has the desired effect of giving access rights to the - # owner only. A platform-specific functional test would be helpful. - it "creates the file with 0600 permissions", :unix_only do - File.should_not exist(key_location) - registration.write_key - File.should exist(key_location) - stat = File.stat(key_location) - (stat.mode & 07777).should == 0600 - end - - it "writes the private key content to the file" do - registration.write_key - IO.read(key_location).should == "--begin rsa key etc--" - end - end - - describe "when registering a client" do - - before do - registration.stub(:http_api).and_return(http_mock) - end - - it "creates the client on the server and writes the key" do - http_mock.should_receive(:post).ordered.and_return(server_v10_response) - registration.run - IO.read(key_location).should == generated_private_key_pem - end - - it "retries up to 5 times" do - response_500 = Net::HTTPInternalServerError.new("1.1", "500", "Internal Server Error") - exception_500 = Net::HTTPFatalError.new("500 Internal Server Error", response_500) - - http_mock.should_receive(:post).ordered.and_raise(exception_500) # 1 - http_mock.should_receive(:post).ordered.and_raise(exception_500) # 2 - http_mock.should_receive(:post).ordered.and_raise(exception_500) # 3 - http_mock.should_receive(:post).ordered.and_raise(exception_500) # 4 - http_mock.should_receive(:post).ordered.and_raise(exception_500) # 5 - - http_mock.should_receive(:post).ordered.and_return(server_v10_response) - registration.run - IO.read(key_location).should == generated_private_key_pem - end - - it "gives up retrying after the max attempts" do - response_500 = Net::HTTPInternalServerError.new("1.1", "500", "Internal Server Error") - exception_500 = Net::HTTPFatalError.new("500 Internal Server Error", response_500) - - http_mock.should_receive(:post).exactly(6).times.and_raise(exception_500) - - lambda {registration.run}.should raise_error(Net::HTTPFatalError) - end - - end - -end diff --git a/spec/unit/api_client_spec.rb b/spec/unit/api_client_spec.rb deleted file mode 100644 index 76fc4afb5c..0000000000 --- a/spec/unit/api_client_spec.rb +++ /dev/null @@ -1,306 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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/api_client' -require 'tempfile' - -describe Chef::ApiClient do - before(:each) do - @client = Chef::ApiClient.new - end - - it "has a name attribute" do - @client.name("ops_master") - @client.name.should == "ops_master" - end - - it "does not allow spaces in the name" do - lambda { @client.name "ops master" }.should raise_error(ArgumentError) - end - - it "only allows string values for the name" do - lambda { @client.name Hash.new }.should raise_error(ArgumentError) - end - - it "has an admin flag attribute" do - @client.admin(true) - @client.admin.should be_true - end - - it "defaults to non-admin" do - @client.admin.should be_false - end - - it "allows only boolean values for the admin flag" do - lambda { @client.admin(false) }.should_not raise_error - lambda { @client.admin(Hash.new) }.should raise_error(ArgumentError) - end - - it "has a 'validator' flag attribute" do - @client.validator(true) - @client.validator.should be_true - end - - it "defaults to non-validator" do - @client.validator.should be_false - end - - it "allows only boolean values for the 'validator' flag" do - lambda { @client.validator(false) }.should_not raise_error - lambda { @client.validator(Hash.new) }.should raise_error(ArgumentError) - end - - it "has a public key attribute" do - @client.public_key("super public") - @client.public_key.should == "super public" - end - - it "accepts only String values for the public key" do - lambda { @client.public_key "" }.should_not raise_error - lambda { @client.public_key Hash.new }.should raise_error(ArgumentError) - end - - - it "has a private key attribute" do - @client.private_key("super private") - @client.private_key.should == "super private" - end - - it "accepts only String values for the private key" do - lambda { @client.private_key "" }.should_not raise_error - lambda { @client.private_key Hash.new }.should 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 - @json.should match(/^\{.+\}$/) - end - - it "includes the name value" do - @json.should include(%q{"name":"black"}) - end - - it "includes the public key value" do - @json.should include(%{"public_key":"crowes"}) - end - - it "includes the 'admin' flag" do - @json.should include(%q{"admin":false}) - end - - it "includes the 'validator' flag" do - @json.should include(%q{"validator":false}) - end - - it "includes the private key when present" do - @client.private_key("monkeypants") - @client.to_json.should include(%q{"private_key":"monkeypants"}) - end - - it "does not include the private key if not present" do - @json.should_not include("private_key") - end - end - - describe "when deserializing from JSON" do - before(:each) do - client = { - "name" => "black", - "public_key" => "crowes", - "private_key" => "monkeypants", - "admin" => true, - "validator" => true, - "json_class" => "Chef::ApiClient" - } - @client = Chef::JSONCompat.from_json(client.to_json) - end - - it "should deserialize to a Chef::ApiClient object" do - @client.should be_a_kind_of(Chef::ApiClient) - end - - it "preserves the name" do - @client.name.should == "black" - end - - it "preserves the public key" do - @client.public_key.should == "crowes" - end - - it "preserves the admin status" do - @client.admin.should be_true - end - - it "preserves the 'validator' status" do - @client.validator.should be_true - end - - it "includes the private key if present" do - @client.private_key.should == "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, - "validator" => true, - "json_class" => "Chef::ApiClient" - } - @http_client = double("Chef::REST mock") - Chef::REST.stub(:new).and_return(@http_client) - @http_client.should_receive(:get).with("clients/black").and_return(client) - @client = Chef::ApiClient.load(client['name']) - end - - it "should deserialize to a Chef::ApiClient object" do - @client.should be_a_kind_of(Chef::ApiClient) - end - - it "preserves the name" do - @client.name.should == "black" - end - - it "preserves the public key" do - @client.public_key.should == "crowes" - end - - it "preserves the admin status" do - @client.admin.should be_a_kind_of(TrueClass) - end - - it "preserves the 'validator' status" do - @client.validator.should be_a_kind_of(TrueClass) - end - - it "includes the private key if present" do - @client.private_key.should == "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 - - it "has an HTTP client configured with default credentials" do - @client.http_api.should be_a_kind_of(Chef::REST) - @client.http_api.client_name.should == "silent-bob" - @client.http_api.signing_key.to_s.should == private_key_data - end - end - - - describe "when requesting a new key" do - before do - @http_client = double("Chef::REST mock") - Chef::REST.stub(: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) - - @http_client.should_receive(:get).with("clients/lost-my-key").and_raise(@a_404_exception) - end - - it "raises a 404 error" do - lambda { Chef::ApiClient.reregister("lost-my-key") }.should raise_error(Net::HTTPServerException) - end - end - - context "and the client exists" do - before do - @api_client_without_key = Chef::ApiClient.new - @api_client_without_key.name("lost-my-key") - @http_client.should_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 - @api_client_with_key.name("lost-my-key") - @api_client_with_key.private_key("the new private key") - @http_client.should_receive(:put). - with("clients/lost-my-key", :name => "lost-my-key", :admin => false, :validator => false, :private_key => true). - and_return(@api_client_with_key) - end - - it "returns an ApiClient with a private key" do - response = Chef::ApiClient.reregister("lost-my-key") - # no sane == method for ApiClient :'( - response.should == @api_client_without_key - response.private_key.should == "the new private key" - response.name.should == "lost-my-key" - response.admin.should be_false - end - end - - 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"} - @http_client.should_receive(:put). - with("clients/lost-my-key", :name => "lost-my-key", :admin => false, :validator => false, :private_key => true). - and_return(@api_client_with_key) - end - - it "returns an ApiClient with a private key" do - response = Chef::ApiClient.reregister("lost-my-key") - # no sane == method for ApiClient :'( - response.should == @api_client_without_key - response.private_key.should == "the new private key" - response.name.should == "lost-my-key" - response.admin.should be_false - response.validator.should be_false - end - end - - end - end -end - - diff --git a/spec/unit/application/agent_spec.rb b/spec/unit/application/agent_spec.rb deleted file mode 100644 index e69de29bb2..0000000000 --- a/spec/unit/application/agent_spec.rb +++ /dev/null diff --git a/spec/unit/application/apply.rb b/spec/unit/application/apply.rb deleted file mode 100644 index 62a53c2a31..0000000000 --- a/spec/unit/application/apply.rb +++ /dev/null @@ -1,86 +0,0 @@ -# -# Author:: Bryan W. Berry (<bryan.berry@gmail.com>) -# Copyright:: Copyright (c) 2012 Bryan W. Berry -# 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::Application::Apply do - - before do - @app = Chef::Application::Apply.new - @app.stub(:configure_logging).and_return(true) - @recipe_text = "package 'nyancat'" - Chef::Config[:solo] = true - end - - describe "configuring the application" do - it "should set solo mode to true" do - @app.reconfigure - Chef::Config[:solo].should be_true - end - end - describe "read_recipe_file" do - before do - @recipe_file_name = "foo.rb" - @recipe_path = File.expand_path("foo.rb") - @recipe_file = double("Tempfile (mock)", :read => @recipe_text) - @app.stub(:open).with(@recipe_path).and_return(@recipe_file) - File.stub(:exist?).with("foo.rb").and_return(true) - Chef::Application.stub(:fatal!).and_return(true) - end - it "should read text properly" do - @app.read_recipe_file(@recipe_file_name)[0].should == @recipe_text - end - it "should return a file_handle" do - @app.read_recipe_file(@recipe_file_name)[1].should be_instance_of(RSpec::Mocks::Mock) - end - describe "when recipe doesn't exist" do - before do - File.stub(:exist?).with(@recipe_file_name).and_return(false) - end - it "should raise a fatal" do - Chef::Application.should_receive(:fatal!) - @app.read_recipe_file(@recipe_file_name) - end - end - end - describe "temp_recipe_file" do - before do - @app.instance_variable_set(:@recipe_text, @recipe_text) - @app.temp_recipe_file - @recipe_fh = @app.instance_variable_get(:@recipe_fh) - end - it "should open a tempfile" do - @recipe_fh.path.should match(/.*recipe-temporary-file.*/) - end - it "should write recipe text to the tempfile" do - @recipe_fh.read.should == @recipe_text - end - it "should save the filename for later use" do - @recipe_fh.path.should == @app.instance_variable_get(:@recipe_filename) - end - end - describe "recipe_file_arg" do - before do - ARGV.clear - end - it "should exit and log message" do - Chef::Log.should_receive(:debug).with(/^No recipe file provided/) - lambda { @app.run }.should raise_error(SystemExit) { |e| e.status.should == 1 } - end - - end -end diff --git a/spec/unit/application/client_spec.rb b/spec/unit/application/client_spec.rb deleted file mode 100644 index ee91e67256..0000000000 --- a/spec/unit/application/client_spec.rb +++ /dev/null @@ -1,297 +0,0 @@ -# -# Author:: AJ Christensen (<aj@junglist.gen.nz>) -# 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' - -describe Chef::Application::Client, "reconfigure" do - before do - Kernel.stub(:trap).and_return(:ok) - - @original_argv = ARGV.dup - ARGV.clear - - @app = Chef::Application::Client.new - @app.stub(:trap) - @app.stub(:configure_opt_parser).and_return(true) - @app.stub(:configure_chef).and_return(true) - @app.stub(:configure_logging).and_return(true) - @app.cli_arguments = [] - Chef::Config[:interval] = 10 - - Chef::Config[:once] = false - end - - after do - ARGV.replace(@original_argv) - end - - describe "when configured to not fork the client process" do - before do - Chef::Config[:client_fork] = false - Chef::Config[:daemonize] = false - Chef::Config[:interval] = nil - Chef::Config[:splay] = nil - end - - context "when interval is given" do - before do - Chef::Config[:interval] = 600 - end - - it "should terminate with message" do - Chef::Application.should_receive(:fatal!).with( -"Unforked chef-client interval runs are disabled in Chef 12. -Configuration settings: - interval = 600 seconds -Enable chef-client interval runs by setting `:client_fork = true` in your config file or adding `--fork` to your command line options." - ) - @app.reconfigure - end - end - - context "when configured to run once" do - before do - Chef::Config[:once] = true - Chef::Config[:interval] = 1000 - end - - it "should reconfigure chef-client" do - @app.reconfigure - Chef::Config[:interval].should be_nil - end - end - end - - describe "when in daemonized mode and no interval has been set" do - before do - Chef::Config[:daemonize] = true - Chef::Config[:interval] = nil - end - - it "should set the interval to 1800" do - @app.reconfigure - Chef::Config.interval.should == 1800 - end - end - - describe "when configured to run once" do - before do - Chef::Config[:once] = true - Chef::Config[:daemonize] = false - Chef::Config[:splay] = 60 - Chef::Config[:interval] = 1800 - end - - it "ignores the splay" do - @app.reconfigure - Chef::Config.splay.should be_nil - end - - it "forces the interval to nil" do - @app.reconfigure - Chef::Config.interval.should be_nil - end - - end - - describe "when the json_attribs configuration option is 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" } - - before do - Chef::Config[:json_attribs] = json_source - Chef::ConfigFetcher.should_receive(:new).with(json_source). - and_return(config_fetcher) - end - - it "reads the JSON attributes from the specified source" do - @app.reconfigure - @app.chef_client_json.should == json_attribs - end - end -end - -describe Chef::Application::Client, "setup_application" do - before do - @app = Chef::Application::Client.new - # this is all stuff the reconfigure method needs - @app.stub(:configure_opt_parser).and_return(true) - @app.stub(:configure_chef).and_return(true) - @app.stub(:configure_logging).and_return(true) - end - - it "should change privileges" do - Chef::Daemon.should_receive(:change_privilege).and_return(true) - @app.setup_application - end - after do - Chef::Config[:solo] = false - end -end - -describe Chef::Application::Client, "configure_chef" do - before do - @original_argv = ARGV.dup - ARGV.clear - @app = Chef::Application::Client.new - @app.configure_chef - end - - after do - ARGV.replace(@original_argv) - end - - it "should set the colored output to false by default on windows and true otherwise" do - if windows? - Chef::Config[:color].should be_false - else - Chef::Config[:color].should be_true - end - end -end - -describe Chef::Application::Client, "run_application", :unix_only do - before(:each) do - Chef::Config[:specific_recipes] = [] # normally gets set in @app.reconfigure - - @app = Chef::Application::Client.new - @app.setup_signal_handlers - # Default logger doesn't work correctly when logging from a trap handler. - @app.configure_logging - - @pipe = IO.pipe - @client = Chef::Client.new - Chef::Client.stub(:new).and_return(@client) - @client.stub(:run) do - @pipe[1].puts 'started' - sleep 1 - @pipe[1].puts 'finished' - end - end - - context "when sent SIGTERM", :volatile_on_solaris do - context "when converging in forked process" do - before do - Chef::Config[:daemonize] = true - Chef::Daemon.stub(:daemonize).and_return(true) - end - - it "should exit hard with exitstatus 3" do - pid = fork do - @app.run_application - end - Process.kill("TERM", pid) - _pid, result = Process.waitpid2(pid) - result.exitstatus.should == 3 - end - - it "should allow child to finish converging" do - pid = fork do - @app.run_application - end - @pipe[0].gets.should == "started\n" - Process.kill("TERM", pid) - Process.wait - sleep 1 # Make sure we give the converging child process enough time to finish - IO.select([@pipe[0]], nil, nil, 0).should_not be_nil - @pipe[0].gets.should == "finished\n" - end - end - - context "when running unforked" do - before(:each) do - Chef::Config[:client_fork] = false - Chef::Config[:daemonize] = false - end - - it "should exit gracefully when sent during converge" do - pid = fork do - @app.run_application - end - @pipe[0].gets.should == "started\n" - Process.kill("TERM", pid) - _pid, result = Process.waitpid2(pid) - result.exitstatus.should == 0 - IO.select([@pipe[0]], nil, nil, 0).should_not be_nil - @pipe[0].gets.should == "finished\n" - end - - it "should exit hard when sent before converge" do - pid = fork do - sleep 3 - @app.run_application - end - Process.kill("TERM", pid) - _pid, result = Process.waitpid2(pid) - result.exitstatus.should == 3 - end - end - end - - describe "when splay is set" do - before do - Chef::Config[:splay] = 10 - Chef::Config[:interval] = 10 - - run_count = 0 - - # uncomment to debug failures... - # Chef::Log.init($stderr) - # Chef::Log.level = :debug - - @app.stub(:run_chef_client) do - - run_count += 1 - if run_count > 3 - exit 0 - end - - # If everything is fine, sending USR1 to self should prevent - # app to go into splay sleep forever. - Process.kill("USR1", Process.pid) - # On Ruby < 2.1, we need to give the signal handlers a little - # more time, otherwise the test will fail because interleavings. - sleep 1 - end - - number_of_sleep_calls = 0 - - # This is a very complicated way of writing - # @app.should_receive(:sleep).once. - # We have to do it this way because the main loop of - # Chef::Application::Client swallows most exceptions, and we need to be - # able to expose our expectation failures to the parent process in the test. - @app.stub(:interval_sleep) do |arg| - number_of_sleep_calls += 1 - if number_of_sleep_calls > 1 - exit 127 - end - end - end - - it "shouldn't sleep when sent USR1" do - @app.stub(:interval_sleep).with(0).and_call_original - pid = fork do - @app.run_application - end - _pid, result = Process.waitpid2(pid) - result.exitstatus.should == 0 - end - end -end diff --git a/spec/unit/application/knife_spec.rb b/spec/unit/application/knife_spec.rb deleted file mode 100644 index 0933d7e178..0000000000 --- a/spec/unit/application/knife_spec.rb +++ /dev/null @@ -1,173 +0,0 @@ -# -# Author:: AJ Christensen (<aj@junglist.gen.nz>) -# 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_SPEC_DATA}/knife_subcommand/test_yourself" - -describe Chef::Application::Knife do - include SpecHelpers::Knife - - before(:all) do - class NoopKnifeCommand < Chef::Knife - option :opt_with_default, - :short => "-D VALUE", - :long => "-optwithdefault VALUE", - :default => "default-value" - - def run - end - end - end - - before(:each) do - # Prevent code from getting loaded on every test invocation. - Chef::Knife.stub(:load_commands) - - @knife = Chef::Application::Knife.new - @knife.stub(:puts) - @knife.stub(:trap) - Chef::Knife.stub(:list_commands) - end - - it "should exit 1 and print the options if no arguments are given at all" do - with_argv([]) do - lambda { @knife.run }.should raise_error(SystemExit) { |e| e.status.should == 1 } - end - end - - it "should exit 2 if run without a sub command" do - with_argv("--user", "adam") do - Chef::Log.should_receive(:error).with(/you need to pass a sub\-command/i) - lambda { @knife.run }.should raise_error(SystemExit) { |e| e.status.should == 2 } - end - end - - it "should run a sub command with the applications command line option prototype" do - with_argv(*%w{noop knife command with some args}) do - knife = double(Chef::Knife) - Chef::Knife.should_receive(:run).with(ARGV, @knife.options).and_return(knife) - @knife.should_receive(:exit).with(0) - @knife.run - end - end - - it "should set the colored output to false by default on windows and true otherwise" do - with_argv(*%w{noop knife command}) do - @knife.should_receive(:exit).with(0) - @knife.run - end - if windows? - Chef::Config[:color].should be_false - else - Chef::Config[:color].should be_true - 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' - Dir.stub(:pwd).and_return(CHEF_SPEC_DATA) - with_argv(*%W{noop knife command -k #{relative_path}}) do - @knife.should_receive(:exit).with(0) - @knife.run - end - Chef::Config[:client_key].should == File.join(CHEF_SPEC_DATA, relative_path) - end - - it "expands a ~/home/path to the correct full path" do - home_path = '~/.chef/client.pem' - with_argv(*%W{noop knife command -k #{home_path}}) do - @knife.should_receive(:exit).with(0) - @knife.run - end - Chef::Config[:client_key].should == 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 - with_argv(*%W{noop knife command -k #{full_path}}) do - @knife.should_receive(:exit).with(0) - @knife.run - end - Chef::Config[:client_key].should == full_path - end - - end - - describe "with environment configuration" do - before do - Chef::Config[:environment] = nil - end - - it "should default to no environment" do - with_argv(*%w{noop knife command}) do - @knife.should_receive(:exit).with(0) - @knife.run - end - Chef::Config[:environment].should == nil - end - - it "should load the environment from the config file" do - config_file = File.join(CHEF_SPEC_DATA,"environment-config.rb") - with_argv(*%W{noop knife command -c #{config_file}}) do - @knife.should_receive(:exit).with(0) - @knife.run - end - Chef::Config[:environment].should == 'production' - end - - it "should load the environment from the CLI options" do - with_argv(*%W{noop knife command -E development}) do - @knife.should_receive(:exit).with(0) - @knife.run - end - Chef::Config[:environment].should == 'development' - end - - it "should override the config file environment with the CLI environment" do - config_file = File.join(CHEF_SPEC_DATA,"environment-config.rb") - with_argv(*%W{noop knife command -c #{config_file} -E override}) do - @knife.should_receive(:exit).with(0) - @knife.run - end - Chef::Config[:environment].should == '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") - with_argv(*%W{noop knife command -E override -c #{config_file}}) do - @knife.should_receive(:exit).with(0) - @knife.run - end - Chef::Config[:environment].should == 'override' - end - - it "should run a sub command with the applications command line option prototype" do - with_argv(*%w{noop knife command with some args}) do - knife = double(Chef::Knife) - Chef::Knife.should_receive(:run).with(ARGV, @knife.options).and_return(knife) - @knife.should_receive(:exit).with(0) - @knife.run - end - end - - end -end diff --git a/spec/unit/application/server_spec.rb b/spec/unit/application/server_spec.rb deleted file mode 100644 index e69de29bb2..0000000000 --- a/spec/unit/application/server_spec.rb +++ /dev/null diff --git a/spec/unit/application/solo_spec.rb b/spec/unit/application/solo_spec.rb deleted file mode 100644 index e29fcc9367..0000000000 --- a/spec/unit/application/solo_spec.rb +++ /dev/null @@ -1,169 +0,0 @@ -# -# Author:: AJ Christensen (<aj@junglist.gen.nz>) -# 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' - -describe Chef::Application::Solo do - before do - Kernel.stub(:trap).and_return(:ok) - @app = Chef::Application::Solo.new - @app.stub(:configure_opt_parser).and_return(true) - @app.stub(:configure_chef).and_return(true) - @app.stub(:configure_logging).and_return(true) - @app.stub(:trap) - Chef::Config[:recipe_url] = false - Chef::Config[:json_attribs] = false - Chef::Config[:solo] = true - end - - describe "configuring the application" do - it "should set solo mode to true" do - @app.reconfigure - Chef::Config[:solo].should be_true - end - - describe "when configured to not fork the client process" do - before do - Chef::Config[:client_fork] = false - Chef::Config[:daemonize] = false - Chef::Config[:interval] = nil - Chef::Config[:splay] = nil - end - - context "when interval is given" do - before do - Chef::Config[:interval] = 600 - end - - it "should terminate with message" do - Chef::Application.should_receive(:fatal!).with( -"Unforked chef-client interval runs are disabled in Chef 12. -Configuration settings: - interval = 600 seconds -Enable chef-client interval runs by setting `:client_fork = true` in your config file or adding `--fork` to your command line options." - ) - @app.reconfigure - end - end - end - - describe "when in daemonized mode and no interval has been set" do - before do - Chef::Config[:daemonize] = true - end - - it "should set the interval to 1800" do - Chef::Config[:interval] = nil - @app.reconfigure - Chef::Config[:interval].should == 1800 - end - end - - describe "when the json_attribs configuration option is 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" } - - before do - Chef::Config[:json_attribs] = json_source - Chef::ConfigFetcher.should_receive(:new).with(json_source). - and_return(config_fetcher) - end - - it "reads the JSON attributes from the specified source" do - @app.reconfigure - @app.chef_client_json.should == json_attribs - end - end - - describe "when the recipe_url configuration option is specified" do - before do - Chef::Config[:cookbook_path] = "#{Dir.tmpdir}/chef-solo/cookbooks" - Chef::Config[:recipe_url] = "http://junglist.gen.nz/recipes.tgz" - FileUtils.stub(:mkdir_p).and_return(true) - @tarfile = StringIO.new("remote_tarball_content") - @app.stub(:open).with("http://junglist.gen.nz/recipes.tgz").and_yield(@tarfile) - - @target_file = StringIO.new - File.stub(:open).with("#{Dir.tmpdir}/chef-solo/recipes.tgz", "wb").and_yield(@target_file) - - Chef::Mixin::Command.stub(:run_command).and_return(true) - end - - it "should create the recipes path based on the parent of the cookbook path" do - FileUtils.should_receive(:mkdir_p).with("#{Dir.tmpdir}/chef-solo").and_return(true) - @app.reconfigure - end - - it "should download the recipes" do - @app.should_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 - @target_file.string.should == "remote_tarball_content" - end - - it "should untar the target file to the parent of the cookbook path" do - Chef::Mixin::Command.should_receive(:run_command).with({:command => "tar zxvf #{Dir.tmpdir}/chef-solo/recipes.tgz -C #{Dir.tmpdir}/chef-solo"}).and_return(true) - @app.reconfigure - end - 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" } - - before do - Chef::Config[:json_attribs] = json_source - Chef::Config[:recipe_url] = "http://icanhas.cheezburger.com/lolcats" - Chef::Config[:cookbook_path] = "#{Dir.tmpdir}/chef-solo/cookbooks" - FileUtils.stub(:mkdir_p).and_return(true) - Chef::Mixin::Command.stub(:run_command).and_return(true) - end - - it "should fetch the recipe_url first" do - @app.should_receive(:fetch_recipe_tarball).ordered - Chef::ConfigFetcher.should_receive(:new).ordered.and_return(config_fetcher) - @app.reconfigure - end - end - - describe "after the application has been configured" do - before do - Chef::Config[:solo] = true - - Chef::Daemon.stub(:change_privilege) - @chef_client = double("Chef::Client") - Chef::Client.stub(:new).and_return(@chef_client) - @app = Chef::Application::Solo.new - # this is all stuff the reconfigure method needs - @app.stub(:configure_opt_parser).and_return(true) - @app.stub(:configure_chef).and_return(true) - @app.stub(:configure_logging).and_return(true) - end - - it "should change privileges" do - Chef::Daemon.should_receive(:change_privilege).and_return(true) - @app.setup_application - end - end - -end diff --git a/spec/unit/application_spec.rb b/spec/unit/application_spec.rb deleted file mode 100644 index b7b69c6993..0000000000 --- a/spec/unit/application_spec.rb +++ /dev/null @@ -1,509 +0,0 @@ -# -# Author:: AJ Christensen (<aj@junglist.gen.nz>) -# Author:: Mark Mzyk (mmzyk@opscode.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' - -describe Chef::Application do - before do - @original_argv = ARGV.dup - ARGV.clear - Chef::Log.logger = Logger.new(StringIO.new) - @app = Chef::Application.new - @app.stub(:trap) - Dir.stub(:chdir).and_return(0) - @app.stub(:reconfigure) - Chef::Log.init(STDERR) - end - - after do - ARGV.replace(@original_argv) - end - - describe "reconfigure" do - before do - @app = Chef::Application.new - @app.stub(:configure_chef).and_return(true) - @app.stub(:configure_logging).and_return(true) - @app.stub(:configure_proxy_environment_variables).and_return(true) - end - - it "should configure chef" do - @app.should_receive(:configure_chef).and_return(true) - @app.reconfigure - end - - it "should configure logging" do - @app.should_receive(:configure_logging).and_return(true) - @app.reconfigure - end - - it "should configure environment variables" do - @app.should_receive(:configure_proxy_environment_variables).and_return(true) - @app.reconfigure - end - end - - describe Chef::Application do - before do - @app = Chef::Application.new - end - - describe "run" do - before do - @app.stub(:setup_application).and_return(true) - @app.stub(:run_application).and_return(true) - @app.stub(:configure_chef).and_return(true) - @app.stub(:configure_logging).and_return(true) - end - - it "should reconfigure the application before running" do - @app.should_receive(:reconfigure).and_return(true) - @app.run - end - - it "should setup the application before running it" do - @app.should_receive(:setup_application).and_return(true) - @app.run - end - - it "should run the actual application" do - @app.should_receive(:run_application).and_return(true) - @app.run - end - end - end - - describe "configure_chef" do - before do - # Silence warnings when no config file exists - Chef::Log.stub(:warn) - - @app = Chef::Application.new - #Chef::Config.stub(:merge!).and_return(true) - @app.stub(:parse_options).and_return(true) - end - - it "should parse the commandline options" do - @app.should_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) - p.stub(:realpath).and_return(config_location) - p - end - - 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 - Pathname.stub(:new).with(config_location).and_return(config_location_pathname) - File.should_receive(:read). - with(config_location). - and_return(config_content) - end - - it "should configure chef::config from a file" do - Chef::Config.should_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 - Chef::Config.rspec_ran.should == "true" - end - - end - - describe "when there is no config_file defined" do - before do - @app.config[:config_file] = nil - end - - it "should emit a warning" do - Chef::Config.should_not_receive(:from_file).with("/etc/chef/default.rb") - Chef::Log.should_receive(:warn).with("No config file found or specified on command line, using command line options.") - @app.configure_chef - end - end - - 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 - Chef::Config.should_receive(:merge!) - @app.configure_chef - end - end - end - - describe "when configuring the logger" do - before do - @app = Chef::Application.new - Chef::Log.stub(:init) - end - - it "should initialise the chef logger" do - Chef::Log.stub(:level=) - @monologger = double("Monologger") - MonoLogger.should_receive(:new).with(Chef::Config[:log_location]).and_return(@monologger) - Chef::Log.should_receive(:init).with(@monologger) - @app.configure_logging - end - - it "should raise fatals if log location is invalid" do - Chef::Config[:log_location] = "/tmp/non-existing-dir/logfile" - Chef::Log.should_receive(:fatal).at_least(:once) - Process.should_receive(:exit) - @app.configure_logging - end - - shared_examples_for "log_level_is_auto" do - context "when STDOUT is to a tty" do - before do - STDOUT.stub(:tty?).and_return(true) - end - - it "configures the log level to :warn" do - @app.configure_logging - Chef::Log.level.should == :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 - Chef::Log.level.should == :info - end - end - end - - context "when STDOUT is not to a tty" do - before do - STDOUT.stub(:tty?).and_return(false) - end - - it "configures the log level to :info" do - @app.configure_logging - Chef::Log.level.should == :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 - Chef::Log.level.should == :warn - end - 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 - end - - it_behaves_like "log_level_is_auto" - end - end - - describe "when configuring environment variables" do - def configure_proxy_environment_variables_stubs - @app.stub(:configure_http_proxy).and_return(true) - @app.stub(:configure_https_proxy).and_return(true) - @app.stub(:configure_ftp_proxy).and_return(true) - @app.stub(:configure_no_proxy).and_return(true) - end - - shared_examples_for "setting ENV['http_proxy']" do - before do - Chef::Config[:http_proxy] = http_proxy - end - - it "should set ENV['http_proxy']" do - @app.configure_proxy_environment_variables - @env['http_proxy'].should == "#{scheme}://#{address}:#{port}" - end - - it "should set ENV['HTTP_PROXY']" do - @app.configure_proxy_environment_variables - @env['HTTP_PROXY'].should == "#{scheme}://#{address}:#{port}" - 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 - @env['http_proxy'].should == "#{scheme}://username@#{address}:#{port}" - @env['HTTP_PROXY'].should == "#{scheme}://username@#{address}:#{port}" - end - - context "when :http_proxy_user contains '@' and/or ':'" do - before do - Chef::Config[:http_proxy_user] = "my:usern@me" - end - - it "should set ENV['http_proxy'] with the escaped username" do - @app.configure_proxy_environment_variables - @env['http_proxy'].should == "#{scheme}://my%3Ausern%40me@#{address}:#{port}" - @env['HTTP_PROXY'].should == "#{scheme}://my%3Ausern%40me@#{address}:#{port}" - end - end - - describe "when Chef::Config[:http_proxy_pass] is set" do - before do - Chef::Config[:http_proxy_pass] = "password" - end - - it "should set ENV['http_proxy'] with the password" do - @app.configure_proxy_environment_variables - @env['http_proxy'].should == "#{scheme}://username:password@#{address}:#{port}" - @env['HTTP_PROXY'].should == "#{scheme}://username:password@#{address}:#{port}" - end - - context "when :http_proxy_pass contains '@' and/or ':'" do - before do - Chef::Config[:http_proxy_pass] = ":P@ssword101" - end - - it "should set ENV['http_proxy'] with the escaped password" do - @app.configure_proxy_environment_variables - @env['http_proxy'].should == "#{scheme}://username:%3AP%40ssword101@#{address}:#{port}" - @env['HTTP_PROXY'].should == "#{scheme}://username:%3AP%40ssword101@#{address}:#{port}" - 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 - @env['http_proxy'].should == "#{scheme}://#{address}:#{port}" - @env['HTTP_PROXY'].should == "#{scheme}://#{address}:#{port}" - end - end - end - - describe "when configuring ENV['http_proxy']" do - before do - @env = {} - @app.stub(:env).and_return(@env) - - @app.stub(:configure_https_proxy).and_return(true) - @app.stub(:configure_ftp_proxy).and_return(true) - @app.stub(:configure_no_proxy).and_return(true) - end - - describe "when Chef::Config[:http_proxy] is not set" do - before do - Chef::Config[:http_proxy] = nil - end - - it "should not set ENV['http_proxy']" do - @app.configure_proxy_environment_variables - @env.should == {} - 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 - @env['http_proxy'].should == Chef::Config[:http_proxy] - end - end - - 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 - end - end - - describe "class method: fatal!" do - before do - STDERR.stub(:puts).with("FATAL: blah").and_return(true) - Chef::Log.stub(:fatal).and_return(true) - Process.stub(:exit).and_return(true) - end - - it "should log an error message to the logger" do - Chef::Log.should_receive(:fatal).with("blah").and_return(true) - Chef::Application.fatal! "blah" - end - - describe "when an exit code is supplied" do - it "should exit with the given exit code" do - Process.should_receive(:exit).with(-100).and_return(true) - Chef::Application.fatal! "blah", -100 - end - end - - describe "when an exit code is not supplied" do - it "should exit with the default exit code" do - Process.should_receive(:exit).with(-1).and_return(true) - Chef::Application.fatal! "blah" - end - end - - end - - describe "setup_application" do - before do - @app = Chef::Application.new - end - - it "should raise an error" do - lambda { @app.setup_application }.should raise_error(Chef::Exceptions::Application) - end - end - - describe "run_application" do - before do - @app = Chef::Application.new - end - - it "should raise an error" do - lambda { @app.run_application }.should raise_error(Chef::Exceptions::Application) - end - end - - context "when the config file is not available" do - it "should warn for bad config file path" do - @app.config[:config_file] = "/tmp/non-existing-dir/file" - config_file_regexp = Regexp.new @app.config[:config_file] - Chef::Log.should_receive(:warn).at_least(:once).with(config_file_regexp).and_return(true) - Chef::Log.stub(:warn).and_return(true) - @app.configure_chef - end - end - - describe "configuration errors" do - before do - Process.should_receive(:exit) - end - - def raises_informative_fatals_on_configure_chef - config_file_regexp = Regexp.new @app.config[:config_file] - Chef::Log.should_receive(:fatal). - with(/Configuration error/) - Chef::Log.should_receive(:fatal). - with(config_file_regexp). - at_least(1).times - @app.configure_chef - end - - describe "when config file exists but contains errors" do - def create_config_file(text) - @config_file = Tempfile.new("rspec-chef-config") - @config_file.write(text) - @config_file.close - @app.config[:config_file] = @config_file.path - end - - after(:each) do - @config_file.unlink - end - - it "should raise informative fatals for badly written config" do - create_config_file("text that should break the config parsing") - raises_informative_fatals_on_configure_chef - end - end - end -end diff --git a/spec/unit/chef_fs/config_spec.rb b/spec/unit/chef_fs/config_spec.rb deleted file mode 100644 index 031da6c4b5..0000000000 --- a/spec/unit/chef_fs/config_spec.rb +++ /dev/null @@ -1,58 +0,0 @@ -# -# Author:: Jess Mink (<jmink@getchef.com>) -# Copyright:: Copyright (c) 2014 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 '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/' - - ui = double("ui") - expect(ui).to receive(:warn) - - Chef::ChefFS::Config.new(base_config, Dir.pwd, {}, ui) - end - - 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/' - - ui = double("ui") - expect(ui).to receive(:warn).exactly(0).times - - Chef::ChefFS::Config.new(base_config, Dir.pwd, {}, ui) - end - - 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/' - - ui = double("ui") - expect(ui).to receive(:warn).exactly(0).times - - Chef::ChefFS::Config.new(base_config, Dir.pwd, {}, ui) - end - end -end diff --git a/spec/unit/chef_fs/diff_spec.rb b/spec/unit/chef_fs/diff_spec.rb deleted file mode 100644 index 2133d05139..0000000000 --- a/spec/unit/chef_fs/diff_spec.rb +++ /dev/null @@ -1,328 +0,0 @@ -# -# Author:: John Keiser (<jkeiser@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/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') -end - -describe 'diff', :uses_diff => true do - include FileSystemSupport - - context 'with two filesystems with all types of difference' do - let(:a) { - memory_fs('a', { - :both_dirs => { - :sub_both_dirs => { :subsub => nil }, - :sub_both_files => nil, - :sub_both_files_different => "a\n", - :sub_both_dirs_empty => {}, - :sub_dirs_empty_in_a_filled_in_b => {}, - :sub_dirs_empty_in_b_filled_in_a => { :subsub => nil }, - :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 - }, - :both_files => nil, - :both_files_different => "a\n", - :both_dirs_empty => {}, - :dirs_empty_in_a_filled_in_b => {}, - :dirs_empty_in_b_filled_in_a => { :subsub => nil }, - :dirs_in_a_cannot_be_in_b => {}, - :file_in_a_cannot_be_in_b => nil, - :a_only_dir => { :subsub => nil }, - :a_only_file => nil, - :dir_in_a_file_in_b => {}, - :file_in_a_dir_in_b => nil - }, /cannot_be_in_a/) - } - let(:b) { - memory_fs('b', { - :both_dirs => { - :sub_both_dirs => { :subsub => nil }, - :sub_both_files => nil, - :sub_both_files_different => "b\n", - :sub_both_dirs_empty => {}, - :sub_dirs_empty_in_a_filled_in_b => { :subsub => nil }, - :sub_dirs_empty_in_b_filled_in_a => {}, - :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 => {} - }, - :both_files => nil, - :both_files_different => "b\n", - :both_dirs_empty => {}, - :dirs_empty_in_a_filled_in_b => { :subsub => nil }, - :dirs_empty_in_b_filled_in_a => {}, - :dirs_in_b_cannot_be_in_a => {}, - :file_in_b_cannot_be_in_a => nil, - :b_only_dir => { :subsub => nil }, - :b_only_file => nil, - :dir_in_a_file_in_b => nil, - :file_in_a_dir_in_b => {} - }, /cannot_be_in_b/) - } - it 'Chef::ChefFS::CommandLine.diff_print(/)' do - results = [] - Chef::ChefFS::CommandLine.diff_print(pattern('/'), a, b, nil, nil) do |diff| - results << remove_os_differences(diff) - end - results.should =~ [ - 'diff --knife a/both_dirs/sub_both_files_different b/both_dirs/sub_both_files_different ---- a/both_dirs/sub_both_files_different DATE -+++ b/both_dirs/sub_both_files_different DATE -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 -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 -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 -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 -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 ---- 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 -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 -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 -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 -new file ---- /dev/null DATE -+++ b/b_only_file DATE -CONTEXT_LINE_NUMBERS -+b_only_file -' ] - end - it 'Chef::ChefFS::CommandLine.diff_print(/both_dirs)' do - results = [] - Chef::ChefFS::CommandLine.diff_print(pattern('/both_dirs'), a, b, nil, nil) do |diff| - results << remove_os_differences(diff) - end - results.should =~ [ - 'diff --knife a/both_dirs/sub_both_files_different b/both_dirs/sub_both_files_different ---- a/both_dirs/sub_both_files_different DATE -+++ b/both_dirs/sub_both_files_different DATE -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 -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 -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 -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 -new file ---- /dev/null DATE -+++ b/both_dirs/sub_b_only_file DATE -CONTEXT_LINE_NUMBERS -+sub_b_only_file -' ] - end - it 'Chef::ChefFS::CommandLine.diff_print(/) with depth 1' do - results = [] - Chef::ChefFS::CommandLine.diff_print(pattern('/'), a, b, 1, nil) do |diff| - results << remove_os_differences(diff) - end - results.should =~ [ -'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 -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 -new file ---- /dev/null DATE -+++ b/b_only_file DATE -CONTEXT_LINE_NUMBERS -+b_only_file -' ] - end - it 'Chef::ChefFS::CommandLine.diff_print(/*_*) with depth 0' do - results = [] - Chef::ChefFS::CommandLine.diff_print(pattern('/*_*'), a, b, 0, nil) do |diff| - results << remove_os_differences(diff) - end - results.should =~ [ -'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 -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 -new file ---- /dev/null DATE -+++ b/b_only_file DATE -CONTEXT_LINE_NUMBERS -+b_only_file -' ] - end - 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| - results << remove_os_differences(diff) - end - results.should =~ [ - "b/both_dirs/sub_both_files_different\n", - "b/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub\n", - "b/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub\n", - "b/both_dirs/sub_a_only_dir\n", - "b/both_dirs/sub_a_only_file\n", - "b/both_dirs/sub_b_only_dir\n", - "b/both_dirs/sub_b_only_file\n", - "b/both_dirs/sub_dir_in_a_file_in_b\n", - "b/both_dirs/sub_file_in_a_dir_in_b\n", - "b/both_files_different\n", - "b/dirs_empty_in_b_filled_in_a/subsub\n", - "b/dirs_empty_in_a_filled_in_b/subsub\n", - "b/a_only_dir\n", - "b/a_only_file\n", - "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" - ] - end - 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| - results << remove_os_differences(diff) - end - results.should =~ [ - "M\tb/both_dirs/sub_both_files_different\n", - "D\tb/both_dirs/sub_dirs_empty_in_b_filled_in_a/subsub\n", - "A\tb/both_dirs/sub_dirs_empty_in_a_filled_in_b/subsub\n", - "D\tb/both_dirs/sub_a_only_dir\n", - "D\tb/both_dirs/sub_a_only_file\n", - "A\tb/both_dirs/sub_b_only_dir\n", - "A\tb/both_dirs/sub_b_only_file\n", - "T\tb/both_dirs/sub_dir_in_a_file_in_b\n", - "T\tb/both_dirs/sub_file_in_a_dir_in_b\n", - "M\tb/both_files_different\n", - "D\tb/dirs_empty_in_b_filled_in_a/subsub\n", - "A\tb/dirs_empty_in_a_filled_in_b/subsub\n", - "D\tb/a_only_dir\n", - "D\tb/a_only_file\n", - "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" - ] - end - end -end diff --git a/spec/unit/chef_fs/file_pattern_spec.rb b/spec/unit/chef_fs/file_pattern_spec.rb deleted file mode 100644 index bac393a054..0000000000 --- a/spec/unit/chef_fs/file_pattern_spec.rb +++ /dev/null @@ -1,526 +0,0 @@ -# -# Author:: John Keiser (<jkeiser@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/chef_fs/file_pattern' - -describe Chef::ChefFS::FilePattern do - def p(str) - Chef::ChefFS::FilePattern.new(str) - end - - # Different kinds of patterns - context 'with empty pattern ""' do - let(:pattern) { Chef::ChefFS::FilePattern.new('') } - it 'match?' do - pattern.match?('').should be_true - pattern.match?('/').should be_false - pattern.match?('a').should be_false - pattern.match?('a/b').should be_false - end - it 'exact_path' do - pattern.exact_path.should == '' - end - it 'could_match_children?' do - pattern.could_match_children?('').should be_false - pattern.could_match_children?('a/b').should be_false - end - end - - context 'with root pattern "/"' do - let(:pattern) { Chef::ChefFS::FilePattern.new('/') } - it 'match?' do - pattern.match?('/').should be_true - pattern.match?('').should be_false - pattern.match?('a').should be_false - pattern.match?('/a').should be_false - end - it 'exact_path' do - pattern.exact_path.should == '/' - end - it 'could_match_children?' do - pattern.could_match_children?('').should be_false - pattern.could_match_children?('/').should be_false - pattern.could_match_children?('a').should be_false - pattern.could_match_children?('a/b').should be_false - pattern.could_match_children?('/a').should be_false - end - end - - context 'with simple pattern "abc"' do - let(:pattern) { Chef::ChefFS::FilePattern.new('abc') } - it 'match?' do - pattern.match?('abc').should be_true - pattern.match?('a').should be_false - pattern.match?('abcd').should be_false - pattern.match?('/abc').should be_false - pattern.match?('').should be_false - pattern.match?('/').should be_false - end - it 'exact_path' do - pattern.exact_path.should == 'abc' - end - it 'could_match_children?' do - pattern.could_match_children?('').should be_false - pattern.could_match_children?('abc').should be_false - pattern.could_match_children?('/abc').should be_false - end - end - - context 'with simple pattern "/abc"' do - let(:pattern) { Chef::ChefFS::FilePattern.new('/abc') } - it 'match?' do - pattern.match?('/abc').should be_true - pattern.match?('abc').should be_false - pattern.match?('a').should be_false - pattern.match?('abcd').should be_false - pattern.match?('').should be_false - pattern.match?('/').should be_false - end - it 'exact_path' do - pattern.exact_path.should == '/abc' - end - it 'could_match_children?' do - pattern.could_match_children?('abc').should be_false - pattern.could_match_children?('/abc').should be_false - pattern.could_match_children?('/').should be_true - pattern.could_match_children?('').should be_false - end - it 'exact_child_name_under' do - pattern.exact_child_name_under('/').should == 'abc' - end - end - - context 'with simple pattern "abc/def/ghi"' do - let(:pattern) { Chef::ChefFS::FilePattern.new('abc/def/ghi') } - it 'match?' do - pattern.match?('abc/def/ghi').should be_true - pattern.match?('/abc/def/ghi').should be_false - pattern.match?('abc').should be_false - pattern.match?('abc/def').should be_false - end - it 'exact_path' do - pattern.exact_path.should == 'abc/def/ghi' - end - it 'could_match_children?' do - pattern.could_match_children?('abc').should be_true - pattern.could_match_children?('xyz').should be_false - pattern.could_match_children?('/abc').should be_false - pattern.could_match_children?('abc/def').should be_true - pattern.could_match_children?('abc/xyz').should be_false - pattern.could_match_children?('abc/def/ghi').should be_false - end - it 'exact_child_name_under' do - pattern.exact_child_name_under('abc').should == 'def' - pattern.exact_child_name_under('abc/def').should == 'ghi' - end - end - - context 'with simple pattern "/abc/def/ghi"' do - let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/def/ghi') } - it 'match?' do - pattern.match?('/abc/def/ghi').should be_true - pattern.match?('abc/def/ghi').should be_false - pattern.match?('/abc').should be_false - pattern.match?('/abc/def').should be_false - end - it 'exact_path' do - pattern.exact_path.should == '/abc/def/ghi' - end - it 'could_match_children?' do - pattern.could_match_children?('/abc').should be_true - pattern.could_match_children?('/xyz').should be_false - pattern.could_match_children?('abc').should be_false - pattern.could_match_children?('/abc/def').should be_true - pattern.could_match_children?('/abc/xyz').should be_false - pattern.could_match_children?('/abc/def/ghi').should be_false - end - it 'exact_child_name_under' do - pattern.exact_child_name_under('/').should == 'abc' - pattern.exact_child_name_under('/abc').should == 'def' - pattern.exact_child_name_under('/abc/def').should == 'ghi' - end - end - - context 'with simple pattern "a\*\b"', :pending => (Chef::Platform.windows?) do - let(:pattern) { Chef::ChefFS::FilePattern.new('a\*\b') } - it 'match?' do - pattern.match?('a*b').should be_true - pattern.match?('ab').should be_false - pattern.match?('acb').should be_false - pattern.match?('ab').should be_false - end - it 'exact_path' do - pattern.exact_path.should == 'a*b' - end - it 'could_match_children?' do - pattern.could_match_children?('a/*b').should be_false - end - end - - context 'with star pattern "/abc/*/ghi"' do - let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/*/ghi') } - it 'match?' do - pattern.match?('/abc/def/ghi').should be_true - pattern.match?('/abc/ghi').should be_false - end - it 'exact_path' do - pattern.exact_path.should be_nil - end - it 'could_match_children?' do - pattern.could_match_children?('/abc').should be_true - pattern.could_match_children?('/xyz').should be_false - pattern.could_match_children?('abc').should be_false - pattern.could_match_children?('/abc/def').should be_true - pattern.could_match_children?('/abc/xyz').should be_true - pattern.could_match_children?('/abc/def/ghi').should be_false - end - it 'exact_child_name_under' do - pattern.exact_child_name_under('/').should == 'abc' - pattern.exact_child_name_under('/abc').should == nil - pattern.exact_child_name_under('/abc/def').should == '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 - pattern.match?('/abc/def/ghi').should be_true - pattern.match?('/abc/dxf/ghi').should be_true - pattern.match?('/abc/df/ghi').should be_true - pattern.match?('/abc/dxyzf/ghi').should be_true - pattern.match?('/abc/d/ghi').should be_false - pattern.match?('/abc/f/ghi').should be_false - pattern.match?('/abc/ghi').should be_false - pattern.match?('/abc/xyz/ghi').should be_false - end - it 'exact_path' do - pattern.exact_path.should be_nil - end - it 'could_match_children?' do - pattern.could_match_children?('/abc').should be_true - pattern.could_match_children?('/xyz').should be_false - pattern.could_match_children?('abc').should be_false - pattern.could_match_children?('/abc/def').should be_true - pattern.could_match_children?('/abc/xyz').should be_false - pattern.could_match_children?('/abc/dxyzf').should be_true - pattern.could_match_children?('/abc/df').should be_true - pattern.could_match_children?('/abc/d').should be_false - pattern.could_match_children?('/abc/f').should be_false - pattern.could_match_children?('/abc/def/ghi').should be_false - end - it 'exact_child_name_under' do - pattern.exact_child_name_under('/').should == 'abc' - pattern.exact_child_name_under('/abc').should == nil - pattern.exact_child_name_under('/abc/def').should == '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 - pattern.match?('/abc/deef/ghi').should be_true - pattern.match?('/abc/deeef/ghi').should be_false - pattern.match?('/abc/def/ghi').should be_false - pattern.match?('/abc/df/ghi').should be_false - pattern.match?('/abc/d/ghi').should be_false - pattern.match?('/abc/f/ghi').should be_false - pattern.match?('/abc/ghi').should be_false - end - it 'exact_path' do - pattern.exact_path.should be_nil - end - it 'could_match_children?' do - pattern.could_match_children?('/abc').should be_true - pattern.could_match_children?('/xyz').should be_false - pattern.could_match_children?('abc').should be_false - pattern.could_match_children?('/abc/deef').should be_true - pattern.could_match_children?('/abc/deeef').should be_false - pattern.could_match_children?('/abc/def').should be_false - pattern.could_match_children?('/abc/df').should be_false - pattern.could_match_children?('/abc/d').should be_false - pattern.could_match_children?('/abc/f').should be_false - pattern.could_match_children?('/abc/deef/ghi').should be_false - end - it 'exact_child_name_under' do - pattern.exact_child_name_under('/').should == 'abc' - pattern.exact_child_name_under('/abc').should == nil - pattern.exact_child_name_under('/abc/deef').should == '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 - pattern.match?('/abc/de1f/ghi').should be_true - pattern.match?('/abc/deef/ghi').should be_false - pattern.match?('/abc/d11f/ghi').should be_false - pattern.match?('/abc/de11f/ghi').should be_false - pattern.match?('/abc/dee1f/ghi').should be_false - pattern.match?('/abc/df/ghi').should be_false - pattern.match?('/abc/d/ghi').should be_false - pattern.match?('/abc/f/ghi').should be_false - pattern.match?('/abc/ghi').should be_false - end - it 'exact_path' do - pattern.exact_path.should be_nil - end - it 'could_match_children?' do - pattern.could_match_children?('/abc').should be_true - pattern.could_match_children?('/xyz').should be_false - pattern.could_match_children?('abc').should be_false - pattern.could_match_children?('/abc/de1f').should be_true - pattern.could_match_children?('/abc/deef').should be_false - pattern.could_match_children?('/abc/d11f').should be_false - pattern.could_match_children?('/abc/de11f').should be_false - pattern.could_match_children?('/abc/dee1f').should be_false - pattern.could_match_children?('/abc/def').should be_false - pattern.could_match_children?('/abc/df').should be_false - pattern.could_match_children?('/abc/d').should be_false - pattern.could_match_children?('/abc/f').should be_false - pattern.could_match_children?('/abc/de1f/ghi').should be_false - end - it 'exact_child_name_under' do - pattern.exact_child_name_under('/').should == 'abc' - pattern.exact_child_name_under('/abc').should == nil - pattern.exact_child_name_under('/abc/de1f').should == 'ghi' - end - end - - context 'with star pattern "/abc/**/ghi"' do - let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/**/ghi') } - it 'match?' do - pattern.match?('/abc/def/ghi').should be_true - pattern.match?('/abc/d/e/f/ghi').should be_true - pattern.match?('/abc/ghi').should be_false - pattern.match?('/abcdef/d/ghi').should be_false - pattern.match?('/abc/d/defghi').should be_false - pattern.match?('/xyz').should be_false - end - it 'exact_path' do - pattern.exact_path.should be_nil - end - it 'could_match_children?' do - pattern.could_match_children?('/abc').should be_true - pattern.could_match_children?('/abc/d').should be_true - pattern.could_match_children?('/abc/d/e').should be_true - pattern.could_match_children?('/abc/d/e/f').should be_true - pattern.could_match_children?('/abc/def/ghi').should be_true - pattern.could_match_children?('abc').should be_false - pattern.could_match_children?('/xyz').should be_false - end - it 'exact_child_name_under' do - pattern.exact_child_name_under('/').should == 'abc' - pattern.exact_child_name_under('/abc').should == nil - pattern.exact_child_name_under('/abc/def').should == nil - end - end - - context 'with star pattern "/abc**/ghi"' do - let(:pattern) { Chef::ChefFS::FilePattern.new('/abc**/ghi') } - it 'match?' do - pattern.match?('/abc/def/ghi').should be_true - pattern.match?('/abc/d/e/f/ghi').should be_true - pattern.match?('/abc/ghi').should be_true - pattern.match?('/abcdef/ghi').should be_true - pattern.match?('/abc/defghi').should be_false - pattern.match?('/xyz').should be_false - end - it 'exact_path' do - pattern.exact_path.should be_nil - end - it 'could_match_children?' do - pattern.could_match_children?('/abc').should be_true - pattern.could_match_children?('/abcdef').should be_true - pattern.could_match_children?('/abc/d/e').should be_true - pattern.could_match_children?('/abc/d/e/f').should be_true - pattern.could_match_children?('/abc/def/ghi').should be_true - pattern.could_match_children?('abc').should be_false - end - it 'could_match_children? /abc** returns false for /xyz' do - pending 'Make could_match_children? more rigorous' do - # At the moment, we return false for this, but in the end it would be nice to return true: - pattern.could_match_children?('/xyz').should be_false - end - end - it 'exact_child_name_under' do - pattern.exact_child_name_under('/').should == nil - pattern.exact_child_name_under('/abc').should == nil - pattern.exact_child_name_under('/abc/def').should == nil - end - end - - context 'with star pattern "/abc/**ghi"' do - let(:pattern) { Chef::ChefFS::FilePattern.new('/abc/**ghi') } - it 'match?' do - pattern.match?('/abc/def/ghi').should be_true - pattern.match?('/abc/def/ghi/ghi').should be_true - pattern.match?('/abc/def/ghi/jkl').should be_false - pattern.match?('/abc/d/e/f/ghi').should be_true - pattern.match?('/abc/ghi').should be_true - pattern.match?('/abcdef/ghi').should be_false - pattern.match?('/abc/defghi').should be_true - pattern.match?('/xyz').should be_false - end - it 'exact_path' do - pattern.exact_path.should be_nil - end - it 'could_match_children?' do - pattern.could_match_children?('/abc').should be_true - pattern.could_match_children?('/abcdef').should be_false - pattern.could_match_children?('/abc/d/e').should be_true - pattern.could_match_children?('/abc/d/e/f').should be_true - pattern.could_match_children?('/abc/def/ghi').should be_true - pattern.could_match_children?('abc').should be_false - pattern.could_match_children?('/xyz').should be_false - end - it 'exact_child_name_under' do - pattern.exact_child_name_under('/').should == 'abc' - pattern.exact_child_name_under('/abc').should == nil - pattern.exact_child_name_under('/abc/def').should == nil - end - end - - context 'with star pattern "a**b**c"' do - let(:pattern) { Chef::ChefFS::FilePattern.new('a**b**c') } - it 'match?' do - pattern.match?('axybzwc').should be_true - pattern.match?('abc').should be_true - pattern.match?('axyzwc').should be_false - pattern.match?('ac').should be_false - pattern.match?('a/x/y/b/z/w/c').should be_true - end - it 'exact_path' do - pattern.exact_path.should be_nil - end - end - - context 'normalization tests' do - it 'handles trailing slashes' do - p('abc/').normalized_pattern.should == 'abc' - p('abc/').exact_path.should == 'abc' - p('abc/').match?('abc').should be_true - p('//').normalized_pattern.should == '/' - p('//').exact_path.should == '/' - p('//').match?('/').should be_true - p('/./').normalized_pattern.should == '/' - p('/./').exact_path.should == '/' - p('/./').match?('/').should be_true - end - it 'handles multiple slashes' do - p('abc//def').normalized_pattern.should == 'abc/def' - p('abc//def').exact_path.should == 'abc/def' - p('abc//def').match?('abc/def').should be_true - p('abc//').normalized_pattern.should == 'abc' - p('abc//').exact_path.should == 'abc' - p('abc//').match?('abc').should be_true - end - it 'handles dot' do - p('abc/./def').normalized_pattern.should == 'abc/def' - p('abc/./def').exact_path.should == 'abc/def' - p('abc/./def').match?('abc/def').should be_true - p('./abc/def').normalized_pattern.should == 'abc/def' - p('./abc/def').exact_path.should == 'abc/def' - p('./abc/def').match?('abc/def').should be_true - p('/.').normalized_pattern.should == '/' - p('/.').exact_path.should == '/' - p('/.').match?('/').should be_true - end - it 'handles dot by itself', :pending => "decide what to do with dot by itself" do - p('.').normalized_pattern.should == '.' - p('.').exact_path.should == '.' - p('.').match?('.').should be_true - p('./').normalized_pattern.should == '.' - p('./').exact_path.should == '.' - p('./').match?('.').should be_true - end - it 'handles dotdot' do - p('abc/../def').normalized_pattern.should == 'def' - p('abc/../def').exact_path.should == 'def' - p('abc/../def').match?('def').should be_true - p('abc/def/../..').normalized_pattern.should == '' - p('abc/def/../..').exact_path.should == '' - p('abc/def/../..').match?('').should be_true - p('/*/../def').normalized_pattern.should == '/def' - p('/*/../def').exact_path.should == '/def' - p('/*/../def').match?('/def').should be_true - p('/*/*/../def').normalized_pattern.should == '/*/def' - p('/*/*/../def').exact_path.should be_nil - p('/*/*/../def').match?('/abc/def').should be_true - p('/abc/def/../..').normalized_pattern.should == '/' - p('/abc/def/../..').exact_path.should == '/' - p('/abc/def/../..').match?('/').should be_true - p('abc/../../def').normalized_pattern.should == '../def' - p('abc/../../def').exact_path.should == '../def' - p('abc/../../def').match?('../def').should be_true - end - it 'handles dotdot with double star' do - p('abc**/def/../ghi').exact_path.should be_nil - p('abc**/def/../ghi').match?('abc/ghi').should be_true - p('abc**/def/../ghi').match?('abc/x/y/z/ghi').should be_true - p('abc**/def/../ghi').match?('ghi').should be_false - end - it 'raises error on dotdot with overlapping double star' do - lambda { Chef::ChefFS::FilePattern.new('abc/**/../def').exact_path }.should raise_error(ArgumentError) - lambda { Chef::ChefFS::FilePattern.new('abc/**/abc/../../def').exact_path }.should raise_error(ArgumentError) - end - it 'handles leading dotdot' do - p('../abc/def').exact_path.should == '../abc/def' - p('../abc/def').match?('../abc/def').should be_true - p('/../abc/def').exact_path.should == '/abc/def' - p('/../abc/def').match?('/abc/def').should be_true - p('..').exact_path.should == '..' - p('..').match?('..').should be_true - p('/..').exact_path.should == '/' - p('/..').match?('/').should be_true - end - end - - - # match? - # - single element matches (empty, fixed, ?, *, characters, escapes) - # - nested matches - # - absolute matches - # - trailing slashes - # - ** - - # exact_path - # - empty - # - single element and nested matches, with escapes - # - absolute and relative - # - ?, *, characters, ** - - # could_match_children? - # - # - # - # - context 'with pattern "abc"' do - end - - context 'with pattern "/abc"' do - end - - context 'with pattern "abc/def/ghi"' do - end - - context 'with pattern "/abc/def/ghi"' do - end - - # Exercise the different methods to their maximum -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 deleted file mode 100644 index 570246c41f..0000000000 --- a/spec/unit/chef_fs/file_system/operation_failed_error_spec.rb +++ /dev/null @@ -1,47 +0,0 @@ -# -# Author:: John Keiser (<jkeiser@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/chef_fs/file_system/operation_failed_error' - -describe Chef::ChefFS::FileSystem::OperationFailedError 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 - allow_message_expectations_on_nil - response_body = '{"error":["Invalid key test in request body"]}' - @response.stub(:code).and_return("400") - @response.stub(:body).and_return(response_body) - exception = Net::HTTPServerException.new("(exception) unauthorized", @response) - proc { - raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, exception), error_message - }.should raise_error(Chef::ChefFS::FileSystem::OperationFailedError, "#{error_message} cause: #{response_body}") - end - end - - context 'does not have a cause attribute' do - it 'does not include error cause' do - proc { - raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self), error_message - }.should raise_error(Chef::ChefFS::FileSystem::OperationFailedError, error_message) - end - end - end -end diff --git a/spec/unit/chef_fs/file_system_spec.rb b/spec/unit/chef_fs/file_system_spec.rb deleted file mode 100644 index 383a2c81ab..0000000000 --- a/spec/unit/chef_fs/file_system_spec.rb +++ /dev/null @@ -1,135 +0,0 @@ -# -# Author:: John Keiser (<jkeiser@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/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 'list' do - it '/' do - list_should_yield_paths(fs, '/', '/') - end - it '/a' do - list_should_yield_paths(fs, '/a', '/a') - end - it '/a/b' do - list_should_yield_paths(fs, '/a/b', '/a/b') - end - it '/*' do - list_should_yield_paths(fs, '/*', '/') - end - end - - context 'resolve_path' do - it '/' do - Chef::ChefFS::FileSystem.resolve_path(fs, '/').path.should == '/' - end - it 'nonexistent /a' do - Chef::ChefFS::FileSystem.resolve_path(fs, '/a').path.should == '/a' - end - it 'nonexistent /a/b' do - Chef::ChefFS::FileSystem.resolve_path(fs, '/a/b').path.should == '/a/b' - end - end - end - - context 'with a populated filesystem' do - let(:fs) { - memory_fs('', { - :a => { - :aa => { - :c => '', - :zz => '' - }, - :ab => { - :c => '', - } - }, - :x => '' - }) - } - context 'list' do - it '/**' do - list_should_yield_paths(fs, '/**', '/', '/a', '/x', '/a/aa', '/a/aa/c', '/a/aa/zz', '/a/ab', '/a/ab/c') - end - it '/' do - list_should_yield_paths(fs, '/', '/') - end - it '/*' do - list_should_yield_paths(fs, '/*', '/', '/a', '/x') - end - 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') - end - 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') - end - it '/**b/c' do - list_should_yield_paths(fs, '/**b/c', '/a/ab/c') - end - it '/a/ab/c' do - no_blocking_calls_allowed - list_should_yield_paths(fs, '/a/ab/c', '/a/ab/c') - end - it 'nonexistent /a/ab/blah' do - no_blocking_calls_allowed - list_should_yield_paths(fs, '/a/ab/blah', '/a/ab/blah') - end - it 'nonexistent /a/ab/blah/bjork' do - no_blocking_calls_allowed - list_should_yield_paths(fs, '/a/ab/blah/bjork', '/a/ab/blah/bjork') - end - end - - context 'resolve_path' do - before(:each) do - no_blocking_calls_allowed - end - it 'resolves /' do - Chef::ChefFS::FileSystem.resolve_path(fs, '/').path.should == '/' - end - it 'resolves /x' do - Chef::ChefFS::FileSystem.resolve_path(fs, '/x').path.should == '/x' - end - it 'resolves /a' do - Chef::ChefFS::FileSystem.resolve_path(fs, '/a').path.should == '/a' - end - it 'resolves /a/aa' do - Chef::ChefFS::FileSystem.resolve_path(fs, '/a/aa').path.should == '/a/aa' - end - it 'resolves /a/aa/zz' do - Chef::ChefFS::FileSystem.resolve_path(fs, '/a/aa/zz').path.should == '/a/aa/zz' - end - it 'resolves nonexistent /y/x/w' do - Chef::ChefFS::FileSystem.resolve_path(fs, '/y/x/w').path.should == '/y/x/w' - end - end - end -end diff --git a/spec/unit/chef_fs/parallelizer.rb b/spec/unit/chef_fs/parallelizer.rb deleted file mode 100644 index a871b60e98..0000000000 --- a/spec/unit/chef_fs/parallelizer.rb +++ /dev/null @@ -1,482 +0,0 @@ -require 'spec_helper' -require 'chef/chef_fs/parallelizer' - -describe Chef::ChefFS::Parallelizer do - before :each do - @start_time = Time.now - end - - def elapsed_time - Time.now - @start_time - end - - after :each do - parallelizer.kill - end - - context 'With a Parallelizer with 5 threads' do - let :parallelizer do - Chef::ChefFS::Parallelizer.new(5) - end - - def parallelize(inputs, options = {}, &block) - parallelizer.parallelize(inputs, { :main_thread_processing => false }.merge(options), &block) - end - - 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| - sleep val - outputs << val - end - elapsed_time.should < 0.6 - outputs.should == [ 0.1, 0.3, 0.5 ] - end - - context "With :ordered => false (unordered output)" do - it "An empty input produces an empty output" do - parallelize([], :ordered => false) do - sleep 10 - end.to_a == [] - elapsed_time.should < 0.1 - end - - it "10 sleep(0.2)s complete within 0.5 seconds" do - parallelize(1.upto(10), :ordered => false) do |i| - sleep 0.2 - 'x' - end.to_a.should == %w(x x x x x x x x x x) - elapsed_time.should < 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| - sleep val - val - end - enum.map do |value| - elapsed_time.should < value+0.1 - value - end.should == [ 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' - end - enum = parallelize(input, :ordered => false) { |x| sleep(x); x } - results = [] - expect { enum.each { |value| results << value } }.to raise_error 'hi' - results.should == [ 0.1, 0.3, 0.5 ] - elapsed_time.should < 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' - sleep 0.1 - raise 'hi' - end - sleep 0.2 - processed += 1 - x - end - results = [] - expect { enum.each { |value| results << value } }.to raise_error 'hi' - results.sort.should == [ 1, 2, 3 ] - elapsed_time.should < 0.3 - processed.should == 3 - end - - 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' - sleep(0.1) - raise 'hi' - end - sleep(x) - processed += 1 - x - end - expect { parallelized.to_a }.to raise_error 'hi' - processed.should == 4 - end - end - - context "With :ordered => true (ordered output)" do - it "An empty input produces an empty output" do - parallelize([]) do - sleep 10 - end.to_a == [] - elapsed_time.should < 0.1 - end - - it "10 sleep(0.2)s complete within 0.5 seconds" do - parallelize(1.upto(10), :ordered => true) do |i| - sleep 0.2 - 'x' - end.to_a.should == %w(x x x x x x x x x x) - elapsed_time.should < 0.5 - end - - it "Output comes in the order of the input" do - enum = parallelize([0.5,0.3,0.1]) do |val| - sleep val - val - end.enum_for(:each_with_index) - enum.next.should == [ 0.5, 0 ] - enum.next.should == [ 0.3, 1 ] - enum.next.should == [ 0.1, 2 ] - elapsed_time.should < 0.6 - 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' - end - results = [] - enum = parallelize(input) { |x| sleep(x); x } - expect { enum.each { |value| results << value } }.to raise_error 'hi' - elapsed_time.should < 0.6 - results.should == [ 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' - sleep(0.1) - raise 'hi' - end - sleep(0.2) - processed += 1 - x - end - results = [] - expect { enum.each { |value| results << value } }.to raise_error 'hi' - results.should == [ 1, 2 ] - elapsed_time.should < 0.3 - processed.should == 3 - end - - 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' - sleep(0.1) - raise 'hi' - end - sleep(x) - processed += 1 - x - end - expect { parallelized.to_a }.to raise_error 'hi' - processed.should == 4 - end - end - - it "When the input is slow, output still proceeds" do - input = TestEnumerable.new do |&block| - block.call(1) - sleep 0.1 - block.call(2) - sleep 0.1 - block.call(3) - sleep 0.1 - end - enum = parallelize(input) { |x| x } - enum.map do |value| - elapsed_time.should < (value+1)*0.1 - value - end.should == [ 1, 2, 3 ] - end - end - - context "With a Parallelizer with 1 thread" do - let :parallelizer do - Chef::ChefFS::Parallelizer.new(1) - end - - context "when the thread is occupied with a job" do - before :each do - parallelizer - 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 - end - while !started - sleep(0.01) - end - end - - after :each do - if RUBY_VERSION.to_f > 1.8 - Thread.kill(@thread) - end - end - - it "parallelize with :main_thread_processing = true does not block" do - parallelizer.parallelize([1]) do |x| - sleep(0.1) - x - end.to_a.should == [ 1 ] - elapsed_time.should < 0.2 - end - - it "parallelize with :main_thread_processing = false waits for the job to finish" do - parallelizer.parallelize([1], :main_thread_processing => false) do |x| - sleep(0.1) - x+1 - end.to_a.should == [ 2 ] - elapsed_time.should > 0.3 - end - - it "resizing the Parallelizer to 0 waits for the job to stop" do - elapsed_time.should < 0.2 - parallelizer.resize(0) - parallelizer.num_threads.should == 0 - elapsed_time.should > 0.25 - @occupying_job_finished.should == [ true ] - end - - it "stopping the Parallelizer waits for the job to finish" do - elapsed_time.should < 0.2 - parallelizer.stop - parallelizer.num_threads.should == 0 - elapsed_time.should > 0.25 - @occupying_job_finished.should == [ true ] - end - - it "resizing the Parallelizer to 2 does not stop the job" do - elapsed_time.should < 0.2 - parallelizer.resize(2) - parallelizer.num_threads.should == 2 - elapsed_time.should < 0.2 - sleep(0.3) - @occupying_job_finished.should == [ true ] - end - end - - 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) - 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 - enum.count.should == 6 - outputs_processed.should == 0 - input_mapper.num_processed.should == 6 - end - - it ".count with arguments works normally" do - outputs_processed = 0 - 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 - end - enum.count { |x| x > 1 }.should == 6 - enum.count(2).should == 3 - outputs_processed.should == 20 - input_mapper.num_processed.should == 20 - end - - 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) - 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 - enum.first.should == 1 - enum.first(2).should == [1,2] - outputs_processed.should == 3 - input_mapper.num_processed.should == 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) - 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 - enum.take(2).should == [1,2] - outputs_processed.should == 2 - input_mapper.num_processed.should == 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) - 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 - enum.drop(2).should == [3,4,5,6] - outputs_processed.should == 4 - input_mapper.num_processed.should == 6 - end - - 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) - 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 - enum.lazy.take(2).to_a.should == [1,2] - outputs_processed.should == 2 - input_mapper.num_processed.should == 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) - 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 - enum.lazy.drop(2).to_a.should == [3,4,5,6] - outputs_processed.should == 4 - input_mapper.num_processed.should == 6 - end - - it "lazy enumerable is actually lazy" do - outputs_processed = 0 - 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 - enum.lazy.take(2) - enum.lazy.drop(2) - sleep(0.1) - outputs_processed.should == 0 - input_mapper.num_processed.should == 0 - end - end - end - - 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) - enum = parallelizer.parallelize(input_mapper) do |x| - outputs_processed += 1 - x - end - enum.map { |x| x }.should == [1,2,3] - enum.map { |x| x }.should == [1,2,3] - outputs_processed.should == 6 - input_mapper.num_processed.should == 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) - enum = parallelizer.parallelize(input_mapper) do |x| - outputs_processed += 1 - x - end - enum.first.should == 1 - enum.map { |x| x }.should == [1,2,3] - outputs_processed.should >= 4 - input_mapper.num_processed.should >= 4 - end - - it "two simultaneous enumerations throws an exception" do - enum = parallelizer.parallelize([1,2,3]) { |x| x } - a = enum.enum_for(:each) - a.next - expect do - b = enum.enum_for(:each) - b.next - end.to raise_error - end - end - end - - context "With a Parallelizer with 0 threads" do - let :parallelizer do - Chef::ChefFS::Parallelizer.new(0) - end - - context "And main_thread_processing on" do - it "succeeds in running" do - parallelizer.parallelize([0.5]) { |x| x*2 }.to_a.should == [1] - end - end - end - - context "With a Parallelizer with 10 threads" do - let :parallelizer do - Chef::ChefFS::Parallelizer.new(10) - end - - it "does not have contention issues with large numbers of inputs" do - parallelizer.parallelize(1.upto(500)) { |x| x+1 }.to_a.should == 2.upto(501).to_a - end - - it "does not have contention issues with large numbers of inputs with ordering off" do - parallelizer.parallelize(1.upto(500), :ordered => false) { |x| x+1 }.to_a.sort.should == 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 } - end - outputs = [] - threads = 0.upto(99).map do |i| - Thread.new { outputs[i] = parallelizers[i].to_a } - end - threads.each { |thread| thread.join } - outputs.each { |output| output.sort.should == 2.upto(501).to_a } - end - end - - class TestEnumerable - include Enumerable - - def initialize(*values, &block) - @values = values - @block = block - @num_processed = 0 - end - - attr_reader :num_processed - - def each(&each_block) - @values.each do |value| - @num_processed += 1 - each_block.call(value) - end - if @block - @block.call do |value| - @num_processed += 1 - each_block.call(value) - end - end - end - end -end diff --git a/spec/unit/chef_spec.rb b/spec/unit/chef_spec.rb deleted file mode 100644 index b0f0359806..0000000000 --- a/spec/unit/chef_spec.rb +++ /dev/null @@ -1,25 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef do - it "should have a version defined" do - Chef::VERSION.should match(/(\d+)\.(\d+)\.(\d+)/) - end -end diff --git a/spec/unit/client_spec.rb b/spec/unit/client_spec.rb deleted file mode 100644 index e05245c413..0000000000 --- a/spec/unit/client_spec.rb +++ /dev/null @@ -1,594 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: Tim Hinderliter (<tim@opscode.com>) -# Author:: Christopher Walters (<cw@opscode.com>) -# Copyright:: Copyright 2008-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. -# - -require 'spec_helper' - -require 'chef/run_context' -require 'chef/rest' -require 'rbconfig' - -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) - ohai_system.stub(:[]) 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::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 - Ohai::System.stub(:new).and_return(ohai_system) - end - - describe "authentication protocol selection" do - after do - Chef::Config[:authentication_protocol_version] = "1.0" - 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 - Chef::Config[:authentication_protocol_version].should == "1.0" - end - 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 - Chef::Config[:authentication_protocol_version].should == "1.1" - 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 - STDOUT.stub(:tty?).and_return(true) - end - - it "configures the :doc formatter" do - client.formatters_for_run.should == [[:doc]] - end - - context "and force_logger is set" do - before do - Chef::Config[:force_logger] = true - end - - it "configures the :null formatter" do - Chef::Config[:force_logger].should be_true - client.formatters_for_run.should == [[:null]] - end - - end - - end - - context "and STDOUT is not a TTY" do - before do - STDOUT.stub(:tty?).and_return(false) - end - - it "configures the :null formatter" do - client.formatters_for_run.should == [[:null]] - end - - context "and force_formatter is set" do - before do - Chef::Config[:force_formatter] = true - end - it "it configures the :doc formatter" do - client.formatters_for_run.should == [[:doc]] - end - end - end - - end - - context "when a formatter is configured" do - context "with no output path" do - before do - Chef::Config.add_formatter(:min) - end - - it "does not configure a default formatter" do - client.formatters_for_run.should == [[:min, nil]] - end - - it "configures the formatter for STDOUT/STDERR" do - configured_formatters = client.configure_formatters - min_formatter = configured_formatters[0] - min_formatter.output.out.should == STDOUT - min_formatter.output.err.should == STDERR - end - end - - context "with an output path" do - before do - @tmpout = Tempfile.open("rspec-for-client-formatter-selection-#{Process.pid}") - Chef::Config.add_formatter(:min, @tmpout.path) - end - - after do - @tmpout.close unless @tmpout.closed? - @tmpout.unlink - end - - it "configures the formatter for the file path" do - configured_formatters = client.configure_formatters - min_formatter = configured_formatters[0] - min_formatter.output.out.path.should == @tmpout.path - min_formatter.output.err.path.should == @tmpout.path - end - end - - end - end - - describe "a full client run" do - shared_examples_for "a successful 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(: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. - File.should_receive(:exists?).with(Chef::Config[:client_key]).exactly(1).times.and_return(api_client_exists?) - - unless api_client_exists? - # Client.register will register with the validation client name. - Chef::ApiClient::Registration.any_instance.should_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. - Chef::REST.should_receive(:new). - with(Chef::Config[:chef_server_url], fqdn, Chef::Config[:client_key]). - exactly(1). - and_return(http_node_load) - - # --Client#build_node - # looks up the node, which we will return, then later saves it. - Chef::Node.should_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.) - Chef::ResourceReporter.any_instance.should_receive(:node_load_completed) - end - - def stub_for_sync_cookbooks - # --Client#setup_run_context - # ---Client#sync_cookbooks -- downloads the list of cookbooks to sync - # - Chef::CookbookSynchronizer.any_instance.should_receive(:sync_cookbooks) - Chef::REST.should_receive(:new).with(Chef::Config[:chef_server_url]).and_return(http_cookbook_sync) - http_cookbook_sync.should_receive(:post). - with("environments/_default/cookbook_versions", {:run_list => []}). - and_return({}) - end - - def stub_for_converge - # --Client#converge - Chef::Runner.should_receive(:new).and_return(runner) - runner.should_receive(:converge).and_return(true) - - # --ResourceReporter#run_completed - # updates the server with the resource history - # (has its own tests, so stubbing it here.) - Chef::ResourceReporter.any_instance.should_receive(:run_completed) - end - - def stub_for_node_save - node.stub(:data_for_save).and_return(node.for_json) - - # --Client#save_updated_node - Chef::REST.should_receive(:new).with(Chef::Config[:chef_server_url]).and_return(http_node_save) - http_node_save.should_receive(:put_rest).with("nodes/#{fqdn}", node.for_json).and_return(true) - end - - def stub_for_run - Chef::RunLock.any_instance.should_receive(:acquire) - Chef::RunLock.any_instance.should_receive(:save_pid) - Chef::RunLock.any_instance.should_receive(:release) - - # Post conditions: check that node has been filled in correctly - client.should_receive(:run_started) - client.should_receive(:run_completed_successfully) - end - - before do - Chef::Config[:client_fork] = enable_fork - Chef::Config[:cache_path] = windows? ? 'C:\chef' : '/var/chef' - - 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_node_save - stub_for_run - end - - it "runs ohai, sets up authentication, loads node state, synchronizes policy, and converges" do - # This is what we're testing. - client.run - - # fork is stubbed, so we can see the outcome of the run - node.automatic_attrs[:platform].should == "example-platform" - node.automatic_attrs[:platform_version].should == "example-platform-1.0" - end - end - - - describe "when running chef-client without fork" do - - include_examples "a successful client run" - end - - describe "when the client key already exists" do - - let(:api_client_exists?) { true } - - include_examples "a successful client run" - 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]') - end - - describe "when running the client" do - include_examples "a successful client run" do - - before do - # Client will try to compile and run override_recipe - Chef::RunContext::CookbookCompiler.any_instance.should_receive(:compile) - end - - def stub_for_sync_cookbooks - # --Client#setup_run_context - # ---Client#sync_cookbooks -- downloads the list of cookbooks to sync - # - Chef::CookbookSynchronizer.any_instance.should_receive(:sync_cookbooks) - Chef::REST.should_receive(:new).with(Chef::Config[:chef_server_url]).and_return(http_cookbook_sync) - http_cookbook_sync.should_receive(:post). - with("environments/_default/cookbook_versions", {:run_list => ["override_recipe"]}). - and_return({}) - end - - def stub_for_node_save - # Expect NO node save - node.should_not_receive(:save) - end - end - end - end - - describe "when a permanent run list is passed as an option" do - - include_examples "a successful client run" do - - let(:new_runlist) { "recipe[new_run_list_recipe]" } - 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 - # - Chef::CookbookSynchronizer.any_instance.should_receive(:sync_cookbooks) - Chef::REST.should_receive(:new).with(Chef::Config[:chef_server_url]).and_return(http_cookbook_sync) - http_cookbook_sync.should_receive(:post). - with("environments/_default/cookbook_versions", {:run_list => ["new_run_list_recipe"]}). - and_return({}) - end - - before do - # Client will try to compile and run the new_run_list_recipe, but we - # do not create a fixture for this. - Chef::RunContext::CookbookCompiler.any_instance.should_receive(:compile) - end - - it "sets the new run list on the node" do - client.run - node.run_list.should == Chef::RunList.new(new_runlist) - 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) - Chef::RunLock.stub(:new).and_return(@run_lock) - - @events = double("Chef::EventDispatch::Dispatcher").as_null_object - Chef::EventDispatch::Dispatcher.stub(:new).and_return(@events) - - # @events is created on Chef::Client.new, so we need to recreate it after mocking - client = Chef::Client.new - client.stub(:load_node).and_raise(Exception) - @run_lock.should_receive(:release) - lambda { client.run }.should raise_error(Exception) - end - end - - describe "when notifying other objects of the status of the chef run" do - before do - Chef::Client.clear_notifications - Chef::Node.stub(:find_or_create).and_return(node) - node.stub(:save) - client.load_node - client.build_node - end - - it "notifies observers that the run has started" do - notified = false - Chef::Client.when_run_starts do |run_status| - run_status.node.should == node - notified = true - end - - client.run_started - notified.should be_true - end - - it "notifies observers that the run has completed successfully" do - notified = false - Chef::Client.when_run_completes_successfully do |run_status| - run_status.node.should == node - notified = true - end - - client.run_completed_successfully - notified.should be_true - end - - it "notifies observers that the run failed" do - notified = false - Chef::Client.when_run_fails do |run_status| - run_status.node.should == node - notified = true - end - - client.run_failed - notified.should be_true - end - end - - describe "build_node" do - it "should expand the roles and recipes for the node" do - node.run_list << "role[role_containing_cookbook1]" - role_containing_cookbook1 = Chef::Role.new - role_containing_cookbook1.name("role_containing_cookbook1") - role_containing_cookbook1.run_list << "cookbook1" - - # 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") - mock_chef_rest.should_receive(:get_rest).with("roles/role_containing_cookbook1").and_return(role_containing_cookbook1) - Chef::REST.should_receive(:new).and_return(mock_chef_rest) - - # check pre-conditions. - node[:roles].should be_nil - node[:recipes].should be_nil - - client.policy_builder.stub(:node).and_return(node) - - # chefspec and possibly others use the return value of this method - client.build_node.should == node - - # check post-conditions. - node[:roles].should_not be_nil - node[:roles].length.should == 1 - node[:roles].should include("role_containing_cookbook1") - node[:recipes].should_not be_nil - node[:recipes].length.should == 1 - node[:recipes].should include("cookbook1") - end - - it "should set the environment from the specified configuration value" do - node.chef_environment.should == "_default" - Chef::Config[:environment] = "A" - - test_env = Chef::Environment.new - test_env.name("A") - - mock_chef_rest = double("Chef::REST") - mock_chef_rest.should_receive(:get_rest).with("environments/A").and_return(test_env) - Chef::REST.should_receive(:new).and_return(mock_chef_rest) - client.policy_builder.stub(:node).and_return(node) - client.build_node.should == node - - node.chef_environment.should == "A" - end - end - - describe "windows_admin_check" do - context "platform is not windows" do - before do - Chef::Platform.stub(:windows?).and_return(false) - end - - it "shouldn't be called" do - client.should_not_receive(:has_admin_privileges?) - client.do_windows_admin_check - end - end - - context "platform is windows" do - before do - Chef::Platform.stub(:windows?).and_return(true) - end - - it "should be called" do - client.should_receive(:has_admin_privileges?) - client.do_windows_admin_check - end - - context "admin privileges exist" do - before do - client.should_receive(:has_admin_privileges?).and_return(true) - end - - it "should not log a warning message" do - Chef::Log.should_not_receive(:warn) - client.do_windows_admin_check - end - - context "fatal admin check is configured" do - it "should not raise an exception" do - client.do_windows_admin_check #should not raise - end - end - end - - context "admin privileges doesn't exist" do - before do - client.should_receive(:has_admin_privileges?).and_return(false) - end - - it "should log a warning message" do - Chef::Log.should_receive(:warn) - client.do_windows_admin_check - end - - context "fatal admin check is configured" do - it "should raise an exception" do - client.do_windows_admin_check # should not raise - end - end - end - end - end - - describe "assert_cookbook_path_not_empty" do - before 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 - client.send(:assert_cookbook_path_not_empty, nil) - end.to raise_error(Chef::Exceptions::CookbookNotFound, 'None of the cookbook paths set in Chef::Config[:cookbook_path], ["/path/to/invalid/cookbook_path"], contain any cookbooks') - end - end - end - - describe "setting node name" do - context "when machinename, hostname and fqdn are all set" do - it "favors the fqdn" do - expect(client.node_name).to eql(fqdn) - end - end - - context "when fqdn is missing" do - # ohai 7 should always have machinename == return of hostname - let(:fqdn) { nil } - it "favors the machinename" do - expect(client.node_name).to eql(machinename) - end - end - - context "when fqdn and machinename are missing" do - # ohai 6 will not have machinename, return the short hostname - let(:fqdn) { nil } - let(:machinename) { nil } - it "falls back to hostname" do - expect(client.node_name).to eql(hostname) - end - end - - context "when they're all missing" do - let(:machinename) { nil } - let(:hostname) { nil } - let(:fqdn) { nil } - - it "throws an exception" do - expect { client.node_name }.to raise_error(Chef::Exceptions::CannotDetermineNodeName) - end - end - - end -end diff --git a/spec/unit/config_fetcher_spec.rb b/spec/unit/config_fetcher_spec.rb deleted file mode 100644 index f6d5436a11..0000000000 --- a/spec/unit/config_fetcher_spec.rb +++ /dev/null @@ -1,96 +0,0 @@ -require 'spec_helper' -require 'chef/config_fetcher' -describe Chef::ConfigFetcher do - let(:valid_json) { {:a=>"b"}.to_json } - 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(:fetcher) { Chef::ConfigFetcher.new(config_location) } - - context "when loading a local file" do - let(:config_location) { "/etc/chef/client.rb" } - let(:config_content) { "# The client.rb content" } - - it "reads the file from disk" do - ::File.should_receive(:read). - with(config_location). - and_return(config_content) - fetcher.read_config.should == config_content - end - - context "and consuming JSON" do - - let(:config_location) { "/etc/chef/first-boot.json" } - - - it "returns the parsed JSON" do - ::File.should_receive(:read). - with(config_location). - and_return(valid_json) - - fetcher.fetch_json.should == {"a" => "b"} - end - - context "and the JSON is invalid" do - - it "reports the JSON error" do - - - ::File.should_receive(:read). - with(config_location). - and_return(invalid_json) - - Chef::Application.should_receive(:fatal!). - with(invalid_json_error_regex, 2) - fetcher.fetch_json - end - end - end - - end - - context "when loading a file over HTTP" do - - let(:config_location) { "https://example.com/client.rb" } - let(:config_content) { "# The client.rb content" } - - before do - Chef::HTTP::Simple.should_receive(:new). - with(config_location). - and_return(http) - end - - it "reads the file over HTTP" do - http.should_receive(:get). - with("").and_return(config_content) - fetcher.read_config.should == config_content - end - - context "and consuming JSON" do - let(:config_location) { "https://example.com/foo.json" } - - it "fetches the file and parses it" do - http.should_receive(:get). - with("").and_return(valid_json) - fetcher.fetch_json.should == {"a" => "b"} - end - - context "and the JSON is invalid" do - it "reports the JSON error" do - http.should_receive(:get). - with("").and_return(invalid_json) - - Chef::Application.should_receive(:fatal!). - with(invalid_json_error_regex, 2) - fetcher.fetch_json - end - end - end - - end - - -end diff --git a/spec/unit/config_spec.rb b/spec/unit/config_spec.rb deleted file mode 100644 index 41411669e6..0000000000 --- a/spec/unit/config_spec.rb +++ /dev/null @@ -1,422 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: Kyle Goodwin (<kgoodwin@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' - -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 - Chef::Config.chef_server_url.should == "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 - Chef::Config.chef_server_url.should == "https://junglist.gen.nz" - end - - end - - context "when the url is a frozen string" do - before do - Chef::Config.chef_server_url = " https://junglist.gen.nz".freeze - end - - it "strips the space from the url when setting without raising an error" do - Chef::Config.chef_server_url.should == "https://junglist.gen.nz" - 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 - Chef::Config.formatters.should == [] - end - - it "configures a formatter with a short name" do - Chef::Config.add_formatter(:doc) - Chef::Config.formatters.should == [[:doc, nil]] - end - - it "configures a formatter with a file output" do - Chef::Config.add_formatter(:doc, "/var/log/formatter.log") - Chef::Config.formatters.should == [[:doc, "/var/log/formatter.log"]] - end - - end - - describe "class method: manage_secret_key" do - before do - Chef::FileCache.stub(:load).and_return(true) - Chef::FileCache.stub(:has_key?).with("chef_server_cookie_id").and_return(false) - end - - it "should generate and store a chef server cookie id" do - Chef::FileCache.should_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 - Chef::FileCache.stub(:has_key?).with("chef_server_cookie_id").and_return(true) - end - - it "should not generate and store a chef server cookie id" do - Chef::FileCache.should_not_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 - Chef::Platform.stub(: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" - Chef::Config.stub(: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 - Chef::Config.platform_specific_path(path).should == "C:\\chef\\cookbooks" - end - else - it "should return given path on non-windows systems" do - path = "/etc/chef/cookbooks" - Chef::Config.platform_specific_path(path).should == "/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 - Chef::Config.stub(:env).and_return({ 'SYSTEMDRIVE' => 'C:' }) - Chef::Config[:user_home] = 'C:\Users\charlie' - else - Chef::Config[:user_home] = '/Users/charlie' - end - - Chef::Config.stub(: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 - Chef::Config.stub(:path_accessible?).with(to_platform("/var/chef")).and_return(true) - Chef::Config[:cache_path].should == primary_cache_path - end - end - - context "when /var/chef does not exist and /var is accessible" do - it "defaults to /var/chef" do - File.stub(:exists?).with(to_platform("/var/chef")).and_return(false) - Chef::Config.stub(:path_accessible?).with(to_platform("/var")).and_return(true) - Chef::Config[:cache_path].should == primary_cache_path - end - end - - context "when /var/chef does not exist and /var is not accessible" do - it "defaults to $HOME/.chef" do - File.stub(:exists?).with(to_platform("/var/chef")).and_return(false) - Chef::Config.stub(:path_accessible?).with(to_platform("/var")).and_return(false) - Chef::Config[:cache_path].should == secondary_cache_path - end - end - - context "when /var/chef exists and is not accessible" do - it "defaults to $HOME/.chef" do - File.stub(:exists?).with(to_platform("/var/chef")).and_return(true) - File.stub(:readable?).with(to_platform("/var/chef")).and_return(true) - File.stub(:writable?).with(to_platform("/var/chef")).and_return(false) - - Chef::Config[:cache_path].should == 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 - Chef::Config.cache_path.should == 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 - Chef::Config.cache_path.should == to_platform('/a/b/c/local-mode-cache') - end - end - end - end - - it "Chef::Config[:file_backup_path] defaults to /var/chef/backup" do - Chef::Config.stub(:cache_path).and_return(primary_cache_path) - backup_path = is_windows ? "#{primary_cache_path}\\backup" : "#{primary_cache_path}/backup" - Chef::Config[:file_backup_path].should == backup_path - end - - it "Chef::Config[:ssl_verify_mode] defaults to :verify_peer" do - Chef::Config[:ssl_verify_mode].should == :verify_peer - end - - it "Chef::Config[:ssl_ca_path] defaults to nil" do - Chef::Config[:ssl_ca_path].should be_nil - end - - # TODO can this be removed? - if !is_windows - it "Chef::Config[:ssl_ca_file] defaults to nil" do - Chef::Config[:ssl_ca_file].should be_nil - end - end - - it "Chef::Config[:data_bag_path] defaults to /var/chef/data_bags" do - Chef::Config.stub(:cache_path).and_return(primary_cache_path) - data_bag_path = is_windows ? "#{primary_cache_path}\\data_bags" : "#{primary_cache_path}/data_bags" - Chef::Config[:data_bag_path].should == data_bag_path - end - - it "Chef::Config[:environment_path] defaults to /var/chef/environments" do - Chef::Config.stub(:cache_path).and_return(primary_cache_path) - environment_path = is_windows ? "#{primary_cache_path}\\environments" : "#{primary_cache_path}/environments" - Chef::Config[:environment_path].should == 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 - Chef::Config.config_dir.should == 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 - Chef::Config.config_dir.should == 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 - Chef::Config.config_dir.should == 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 - Chef::Config.config_dir.should == 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 - Chef::Config.config_dir.should == 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 - Chef::Config.stub(:_this_file).and_return(default_config_location) - Chef::Config.embedded_dir.should == "c:/opscode/chef/embedded" - end - - it "finds the embedded dir in a custom install location" do - Chef::Config.stub(:_this_file).and_return(alternate_install_location) - Chef::Config.embedded_dir.should == "c:/my/alternate/install/place/chef/embedded" - end - - it "doesn't error when not in an omnibus install" do - Chef::Config.stub(:_this_file).and_return(non_omnibus_location) - Chef::Config.embedded_dir.should be_nil - end - - it "sets the ssl_ca_cert path if the cert file is available" do - Chef::Config.stub(:_this_file).and_return(default_config_location) - File.stub(:exist?).with(default_ca_file).and_return(true) - Chef::Config.ssl_ca_file.should == 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") - Chef::Config.stub(:env).and_return({ 'HOME' => expected }) - Chef::Config[:user_home].should == expected - end - - it "should be set when only USERPROFILE is provided" do - expected = to_platform("/users/kitten") - Chef::Config.stub(:env).and_return({ 'USERPROFILE' => expected }) - Chef::Config[:user_home].should == expected - end - - it "falls back to the current working directory when HOME and USERPROFILE is not set" do - Chef::Config.stub(:env).and_return({}) - Chef::Config[:user_home].should == 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 - File.stub(: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 - Chef::Config[:encrypted_data_bag_secret].should 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 - Chef::Config[:encrypted_data_bag_secret].should be_nil - end - end - end - - describe "Chef::Config[:event_handlers]" do - it "sets a event_handlers to an empty array by default" do - Chef::Config[:event_handlers].should eq([]) - end - it "should be able to add custom handlers" do - o = Object.new - Chef::Config[:event_handlers] << o - Chef::Config[:event_handlers].should 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_true - end - end - end - end - end -end diff --git a/spec/unit/cookbook/chefignore_spec.rb b/spec/unit/cookbook/chefignore_spec.rb deleted file mode 100644 index e529a6d05a..0000000000 --- a/spec/unit/cookbook/chefignore_spec.rb +++ /dev/null @@ -1,49 +0,0 @@ -#-- -# Author:: Daniel DeLeo (<dan@opscode.com>) -# Copyright:: Copyright (c) 2011 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::Cookbook::Chefignore do - before do - @chefignore = Chef::Cookbook::Chefignore.new(File.join(CHEF_SPEC_DATA, 'cookbooks')) - end - - it "loads the globs in the chefignore file" do - @chefignore.ignores.should =~ %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 ] - @chefignore.remove_ignores_from(file_list).should == %w[recipes/dontignoreme.rb] - end - - it "determines if a file is ignored" do - @chefignore.ignored?('ignored').should be_true - @chefignore.ignored?('recipes/ignoreme.rb').should be_true - @chefignore.ignored?('recipes/dontignoreme.rb').should be_false - end - - context "when using the single cookbook pattern" do - before do - @chefignore = Chef::Cookbook::Chefignore.new(File.join(CHEF_SPEC_DATA, 'standalone_cookbook')) - end - - it "loads the globs in the chefignore file" do - @chefignore.ignores.should =~ %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 deleted file mode 100644 index 5772c5352d..0000000000 --- a/spec/unit/cookbook/cookbook_version_loader_spec.rb +++ /dev/null @@ -1,182 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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' - -describe Chef::Cookbook::CookbookVersionLoader do - before do - Chef::Platform.stub(:windows?) { false } - end - - describe "loading a cookbook" do - - let(:chefignore) { nil } - - let(:cookbook_path) { File.join(CHEF_SPEC_DATA, "cookbooks/openldap") } - - let(:cookbook_loader) { Chef::Cookbook::CookbookVersionLoader.new(cookbook_path, chefignore) } - - let(:loaded_cookbook) do - cookbook_loader.load! - cookbook_loader.cookbook_version - end - - def full_path(cookbook_relative_path) - File.join(cookbook_path, cookbook_relative_path) - end - - it "loads attribute files of the cookbook" do - expect(loaded_cookbook.attribute_filenames).to include(full_path("/attributes/default.rb")) - expect(loaded_cookbook.attribute_filenames).to include(full_path("/attributes/smokey.rb")) - end - - it "loads definition files" do - expect(loaded_cookbook.definition_filenames).to include(full_path("/definitions/client.rb")) - expect(loaded_cookbook.definition_filenames).to include(full_path("/definitions/server.rb")) - end - - it "loads recipes" do - expect(loaded_cookbook.recipe_filenames).to include(full_path("/recipes/default.rb")) - expect(loaded_cookbook.recipe_filenames).to include(full_path("/recipes/gigantor.rb")) - expect(loaded_cookbook.recipe_filenames).to include(full_path("/recipes/one.rb")) - expect(loaded_cookbook.recipe_filenames).to include(full_path("/recipes/return.rb")) - end - - it "loads static files in the files/ dir" do - expect(loaded_cookbook.file_filenames).to include(full_path("/files/default/remotedir/remotesubdir/remote_subdir_file1.txt")) - expect(loaded_cookbook.file_filenames).to include(full_path("/files/default/remotedir/remotesubdir/remote_subdir_file2.txt")) - end - - it "loads files that start with a ." do - expect(loaded_cookbook.file_filenames).to include(full_path("/files/default/.dotfile")) - expect(loaded_cookbook.file_filenames).to include(full_path("/files/default/.ssh/id_rsa")) - expect(loaded_cookbook.file_filenames).to include(full_path("/files/default/remotedir/.a_dotdir/.a_dotfile_in_a_dotdir")) - end - - it "should load the metadata for the cookbook" do - loaded_cookbook.metadata.name.to_s.should == "openldap" - loaded_cookbook.metadata.should be_a_kind_of(Chef::Cookbook::Metadata) - end - - context "when a cookbook has ignored files" do - - let(:chefignore) { Chef::Cookbook::Chefignore.new(File.join(CHEF_SPEC_DATA, "cookbooks")) } - - let(:cookbook_path) { File.join(CHEF_SPEC_DATA, "kitchen/openldap") } - - it "skips ignored files" do - expect(loaded_cookbook.recipe_filenames).to include(full_path("recipes/gigantor.rb")) - expect(loaded_cookbook.recipe_filenames).to include(full_path("recipes/woot.rb")) - expect(loaded_cookbook.recipe_filenames).to_not include(full_path("recipes/ignoreme.rb")) - end - - end - - context "when the given path is not actually a cookbook" do - - let(:cookbook_path) { File.join(CHEF_SPEC_DATA, "cookbooks/NOTHING_HERE_FOLKS") } - - it "raises an error when loading with #load!" do - expect { cookbook_loader.load! }.to raise_error(Chef::Exceptions::CookbookNotFoundInRepo) - end - - it "skips the cookbook when called with #load" do - expect { cookbook_loader.load }.to_not raise_error - end - - end - - context "when a cookbook has a metadata name different than directory basename" do - - let(:cookbook_path) { File.join(CHEF_SPEC_DATA, "cookbooks/name-mismatch-versionnumber") } - - it "prefers the metadata name to the directory basename" do - expect(loaded_cookbook.name).to eq(:"name-mismatch") - end - - end - - context "when a cookbook has a metadata file with a ruby error [CHEF-2923]" do - - let(:cookbook_path) { File.join(CHEF_SPEC_DATA, "invalid-metadata-chef-repo/invalid-metadata") } - - it "raises an error when loading with #load!" do - expect { cookbook_loader.load! }.to raise_error("THIS METADATA HAS A BUG") - end - - it "raises an error when called with #load" do - expect { cookbook_loader.load }.to raise_error("THIS METADATA HAS A BUG") - end - - it "doesn't raise an error when determining the cookbook name" do - expect { cookbook_loader.cookbook_name }.to_not raise_error - end - - it "doesn't raise an error when metadata is first generated" do - expect { cookbook_loader.metadata }.to_not raise_error - end - - it "sets an error flag containing error information" do - cookbook_loader.metadata - expect(cookbook_loader.metadata_error).to be_a(StandardError) - expect(cookbook_loader.metadata_error.message).to eq("THIS METADATA HAS A BUG") - end - - end - - context "when a cookbook has a metadata file with invalid metadata" do - - let(:cookbook_path) { File.join(CHEF_SPEC_DATA, "incomplete-metadata-chef-repo/incomplete-metadata") } - - let(:error_message) do - "Cookbook loaded at path(s) [#{cookbook_path}] has invalid metadata: The `name' attribute is required in cookbook metadata" - end - - it "raises an error when loading with #load!" do - expect { cookbook_loader.load! }.to raise_error(Chef::Exceptions::MetadataNotValid, error_message) - end - - it "raises an error when called with #load" do - expect { cookbook_loader.load }.to raise_error(Chef::Exceptions::MetadataNotValid, error_message) - end - - it "uses the inferred cookbook name [CHEF-2923]" do - # This behavior is intended to support the CHEF-2923 feature where - # invalid metadata doesn't prevent you from uploading other cookbooks. - # - # The metadata is the definitive source of the cookbook name, but if - # the metadata is incomplete/invalid, we can't read the name from it. - # - # The CookbookLoader stores CookbookVersionLoaders in a Hash with - # cookbook names as the keys, and finds the loader in this Hash to call - # #load on it when the user runs a command like `knife cookbook upload specific-cookbook` - # - # Most of the time this will work, but if the user tries to upload a - # specific cookbook by name, has customized that cookbook's name (so it - # doesn't match the inferred name), and that metadata file has a syntax - # error, we might report a "cookbook not found" error instead of the - # metadata syntax error that is the actual cause. - expect(cookbook_loader.cookbook_name).to eq(:"incomplete-metadata") - end - - end - - end - -end - diff --git a/spec/unit/cookbook/file_vendor_spec.rb b/spec/unit/cookbook/file_vendor_spec.rb deleted file mode 100644 index 4fad7d5808..0000000000 --- a/spec/unit/cookbook/file_vendor_spec.rb +++ /dev/null @@ -1,78 +0,0 @@ -#-- -# Author:: Daniel DeLeo (<dan@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' - -describe Chef::Cookbook::FileVendor do - - let(:file_vendor_class) { Class.new(described_class) } - - # A manifest is a Hash of the format defined by Chef::CookbookVersion#manifest - let(:manifest) { {:cookbook_name => "bob"} } - - context "when configured to fetch files over http" do - - let(:http) { double("Chef::REST") } - - before do - file_vendor_class.fetch_from_remote(http) - end - - it "sets the vendor class to RemoteFileVendor" do - expect(file_vendor_class.vendor_class).to eq(Chef::Cookbook::RemoteFileVendor) - end - - it "sets the initialization options to the given http object" do - expect(file_vendor_class.initialization_options).to eq(http) - end - - it "creates a RemoteFileVendor for a given manifest" do - file_vendor = file_vendor_class.create_from_manifest(manifest) - expect(file_vendor).to be_a_kind_of(Chef::Cookbook::RemoteFileVendor) - expect(file_vendor.rest).to eq(http) - expect(file_vendor.cookbook_name).to eq("bob") - end - - end - - context "when configured to load files from disk" do - - let(:cookbook_path) { %w[/var/chef/cookbooks /var/chef/other_cookbooks] } - - before do - file_vendor_class.fetch_from_disk(cookbook_path) - end - - it "sets the vendor class to FileSystemFileVendor" do - expect(file_vendor_class.vendor_class).to eq(Chef::Cookbook::FileSystemFileVendor) - end - - it "sets the initialization options to the given cookbook paths" do - expect(file_vendor_class.initialization_options).to eq(cookbook_path) - end - - it "creates a FileSystemFileVendor for a given manifest" do - file_vendor = file_vendor_class.create_from_manifest(manifest) - expect(file_vendor).to be_a_kind_of(Chef::Cookbook::FileSystemFileVendor) - expect(file_vendor.cookbook_name).to eq("bob") - expect(file_vendor.repo_paths).to eq(cookbook_path) - end - - end - -end - diff --git a/spec/unit/cookbook/metadata_spec.rb b/spec/unit/cookbook/metadata_spec.rb deleted file mode 100644 index e61c85b42b..0000000000 --- a/spec/unit/cookbook/metadata_spec.rb +++ /dev/null @@ -1,735 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: Seth Falcon (<seth@opscode.com>) -# Copyright:: Copyright 2008-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. -# - -require 'spec_helper' -require 'chef/cookbook/metadata' - -describe Chef::Cookbook::Metadata do - - let(:metadata) { Chef::Cookbook::Metadata.new } - - describe "when comparing for equality" do - before do - @fields = [ :name, :description, :long_description, :maintainer, - :maintainer_email, :license, :platforms, :dependencies, - :recommendations, :suggestions, :conflicting, :providing, - :replacing, :attributes, :groupings, :recipes, :version] - end - - it "does not depend on object identity for equality" do - metadata.should == metadata.dup - end - - it "is not equal to another object if it isn't have all of the metadata fields" do - @fields.each_index do |field_to_remove| - fields_to_include = @fields.dup - fields_to_include.delete_at(field_to_remove) - almost_duck_type = Struct.new(*fields_to_include).new - @fields.each do |field| - setter = "#{field}=" - metadata_value = metadata.send(field) - almost_duck_type.send(setter, metadata_value) if almost_duck_type.respond_to?(setter) - @mets.should_not == almost_duck_type - end - end - end - - it "is equal to another object if it has equal values for all metadata fields" do - duck_type = Struct.new(*@fields).new - @fields.each do |field| - setter = "#{field}=" - metadata_value = metadata.send(field) - duck_type.send(setter, metadata_value) - end - metadata.should == duck_type - end - - it "is not equal if any values are different" do - duck_type_class = Struct.new(*@fields) - @fields.each do |field_to_change| - duck_type = duck_type_class.new - - @fields.each do |field| - setter = "#{field}=" - metadata_value = metadata.send(field) - duck_type.send(setter, metadata_value) - end - - duck_type.send("#{field_to_change}=".to_sym, :epic_fail) - metadata.should_not == duck_type - end - end - - end - - describe "when first created" do - - it "has no name" do - metadata.name.should eq(nil) - end - - it "has an empty description" do - metadata.description.should eq("") - end - - it "has an empty long description" do - metadata.long_description.should eq("") - end - - it "defaults to 'all rights reserved' license" do - metadata.license.should eq("All rights reserved") - end - - it "has an empty maintainer field" do - metadata.maintainer.should eq(nil) - end - - it "has an empty maintainer_email field" do - metadata.maintainer.should eq(nil) - end - - it "has an empty platforms list" do - metadata.platforms.should eq(Mash.new) - end - - it "has an empty dependencies list" do - metadata.dependencies.should eq(Mash.new) - end - - it "has an empty recommends list" do - metadata.recommendations.should eq(Mash.new) - end - - it "has an empty suggestions list" do - metadata.suggestions.should eq(Mash.new) - end - - it "has an empty conflicts list" do - metadata.conflicting.should eq(Mash.new) - end - - it "has an empty replaces list" do - metadata.replacing.should eq(Mash.new) - end - - it "has an empty attributes list" do - metadata.attributes.should eq(Mash.new) - end - - it "has an empty groupings list" do - metadata.groupings.should eq(Mash.new) - end - - it "has an empty recipes list" do - metadata.recipes.should eq(Mash.new) - end - - end - - describe "validation" do - - context "when no required fields are set" do - - it "is not valid" do - metadata.should_not be_valid - end - - it "has a list of validation errors" do - expected_errors = ["The `name' attribute is required in cookbook metadata"] - metadata.errors.should eq(expected_errors) - end - - end - - context "when all required fields are set" do - before do - metadata.name "a-valid-name" - end - - it "is valid" do - metadata.should be_valid - end - - it "has no validation errors" do - metadata.errors.should be_empty - end - - end - - end - - describe "adding a supported platform" do - it "should support adding a supported platform with a single expression" do - metadata.supports("ubuntu", ">= 8.04") - metadata.platforms["ubuntu"].should == '>= 8.04' - end - end - - describe "meta-data attributes" do - params = { - :maintainer => "Adam Jacob", - :maintainer_email => "adam@opscode.com", - :license => "Apache v2.0", - :description => "Foobar!", - :long_description => "Much Longer\nSeriously", - :version => "0.6.0" - } - 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 - metadata.send(field, field_value).should eql(field_value) - end - it "should be get-able via #{field}" do - metadata.send(field, field_value) - metadata.send(field).should eql(field_value) - end - end - end - - describe "version transformation" do - it "should transform an '0.6' version to '0.6.0'" do - metadata.send(:version, "0.6").should eql("0.6.0") - end - - it "should spit out '0.6.0' after transforming '0.6'" do - metadata.send(:version, "0.6") - metadata.send(:version).should eql("0.6.0") - end - end - end - - describe "describing dependencies" do - - dep_types = { - :depends => [ :dependencies, "foo::bar", "> 0.2" ], - :recommends => [ :recommendations, "foo::bar", ">= 0.2" ], - :suggests => [ :suggestions, "foo::bar", "> 0.2" ], - :conflicts => [ :conflicting, "foo::bar", "~> 0.2" ], - :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| - check_with = dep_args.shift - describe dep do - it "should be set-able via #{dep}" do - metadata.send(dep, *dep_args).should == dep_args[1] - end - it "should be get-able via #{check_with}" do - metadata.send(dep, *dep_args) - metadata.send(check_with).should == { dep_args[0] => dep_args[1] } - end - end - end - - dep_types = { - :depends => [ :dependencies, "foo::bar", ">0.2", "> 0.2" ], - :recommends => [ :recommendations, "foo::bar", ">=0.2", ">= 0.2" ], - :suggests => [ :suggestions, "foo::bar", ">0.2", "> 0.2" ], - :conflicts => [ :conflicting, "foo::bar", "~>0.2", "~> 0.2" ], - :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| - check_with = dep_args.shift - normalized_version = dep_args.pop - describe dep do - it "should be set-able and normalized via #{dep}" do - metadata.send(dep, *dep_args).should == normalized_version - end - it "should be get-able and normalized via #{check_with}" do - metadata.send(dep, *dep_args) - metadata.send(check_with).should == { dep_args[0] => normalized_version } - end - end - end - - - describe "in the obsoleted format" do - dep_types = { - :depends => [ "foo::bar", "> 0.2", "< 1.0" ], - :recommends => [ "foo::bar", ">= 0.2", "< 1.0" ], - :suggests => [ "foo::bar", "> 0.2", "< 1.0" ], - :conflicts => [ "foo::bar", "> 0.2", "< 1.0" ], - :provides => [ "foo::bar", "> 0.2", "< 1.0" ], - :replaces => [ "foo::bar", "> 0.2.1", "< 1.0" ], - } - - dep_types.each do |dep, dep_args| - it "for #{dep} raises an informative error instead of vomiting on your shoes" do - lambda {metadata.send(dep, *dep_args)}.should raise_error(Chef::Exceptions::ObsoleteDependencySyntax) - end - end - end - - - describe "with obsolete operators" do - dep_types = { - :depends => [ "foo::bar", ">> 0.2"], - :recommends => [ "foo::bar", ">> 0.2"], - :suggests => [ "foo::bar", ">> 0.2"], - :conflicts => [ "foo::bar", ">> 0.2"], - :provides => [ "foo::bar", ">> 0.2"], - :replaces => [ "foo::bar", ">> 0.2.1"], - } - - dep_types.each do |dep, dep_args| - it "for #{dep} raises an informative error instead of vomiting on your shoes" do - lambda {metadata.send(dep, *dep_args)}.should raise_error(Chef::Exceptions::InvalidVersionConstraint) - end - end - 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" - } - metadata.grouping("/db/mysql/databases/tuning", group).should == group - end - it "should not accept anything but a string for display_name" do - lambda { - metadata.grouping("db/mysql/databases", :title => "foo") - }.should_not raise_error - lambda { - metadata.grouping("db/mysql/databases", :title => Hash.new) - }.should raise_error(ArgumentError) - end - - it "should not accept anything but a string for the description" do - lambda { - metadata.grouping("db/mysql/databases", :description => "foo") - }.should_not raise_error - lambda { - metadata.grouping("db/mysql/databases", :description => Hash.new) - }.should raise_error(ArgumentError) - end - end - - describe "cookbook attributes" do - it "should allow you set an attributes metadata" do - attrs = { - "display_name" => "MySQL Databases", - "description" => "Description of MySQL", - "choice" => ['dedicated', 'shared'], - "calculated" => false, - "type" => 'string', - "required" => 'recommended', - "recipes" => [ "mysql::server", "mysql::master" ], - "default" => [ ] - } - metadata.attribute("/db/mysql/databases", attrs).should == attrs - end - - it "should not accept anything but a string for display_name" do - lambda { - metadata.attribute("db/mysql/databases", :display_name => "foo") - }.should_not raise_error - lambda { - metadata.attribute("db/mysql/databases", :display_name => Hash.new) - }.should raise_error(ArgumentError) - end - - it "should not accept anything but a string for the description" do - lambda { - metadata.attribute("db/mysql/databases", :description => "foo") - }.should_not raise_error - lambda { - metadata.attribute("db/mysql/databases", :description => Hash.new) - }.should raise_error(ArgumentError) - end - - it "should not accept anything but an array of strings for choice" do - lambda { - metadata.attribute("db/mysql/databases", :choice => ['dedicated', 'shared']) - }.should_not raise_error - lambda { - metadata.attribute("db/mysql/databases", :choice => [10, 'shared']) - }.should raise_error(ArgumentError) - lambda { - metadata.attribute("db/mysql/databases", :choice => Hash.new) - }.should raise_error(ArgumentError) - end - - it "should set choice to empty array by default" do - metadata.attribute("db/mysql/databases", {}) - metadata.attributes["db/mysql/databases"][:choice].should == [] - end - - it "should let calculated be true or false" do - lambda { - metadata.attribute("db/mysql/databases", :calculated => true) - }.should_not raise_error - lambda { - metadata.attribute("db/mysql/databases", :calculated => false) - }.should_not raise_error - lambda { - metadata.attribute("db/mysql/databases", :calculated => Hash.new) - }.should raise_error(ArgumentError) - end - - it "should set calculated to false by default" do - metadata.attribute("db/mysql/databases", {}) - metadata.attributes["db/mysql/databases"][:calculated].should == false - end - - it "accepts String for the attribute type" do - lambda { - metadata.attribute("db/mysql/databases", :type => "string") - }.should_not raise_error - end - - it "accepts Array for the attribute type" do - lambda { - metadata.attribute("db/mysql/databases", :type => "array") - }.should_not raise_error - lambda { - metadata.attribute("db/mysql/databases", :type => Array.new) - }.should raise_error(ArgumentError) - end - - it "accepts symbol for the attribute type" do - lambda { - metadata.attribute("db/mysql/databases", :type => "symbol") - }.should_not raise_error - end - - it "should let type be hash (backwards compatability only)" do - lambda { - metadata.attribute("db/mysql/databases", :type => "hash") - }.should_not raise_error - end - - it "should let required be required, recommended or optional" do - lambda { - metadata.attribute("db/mysql/databases", :required => 'required') - }.should_not raise_error - lambda { - metadata.attribute("db/mysql/databases", :required => 'recommended') - }.should_not raise_error - lambda { - metadata.attribute("db/mysql/databases", :required => 'optional') - }.should_not raise_error - end - - it "should convert required true to required" do - lambda { - metadata.attribute("db/mysql/databases", :required => true) - }.should_not raise_error - #attrib = metadata.attributes["db/mysql/databases"][:required].should == "required" - end - - it "should convert required false to optional" do - lambda { - metadata.attribute("db/mysql/databases", :required => false) - }.should_not raise_error - #attrib = metadata.attributes["db/mysql/databases"][:required].should == "optional" - end - - it "should set required to 'optional' by default" do - metadata.attribute("db/mysql/databases", {}) - metadata.attributes["db/mysql/databases"][:required].should == 'optional' - end - - it "should make sure recipes is an array" do - lambda { - metadata.attribute("db/mysql/databases", :recipes => []) - }.should_not raise_error - lambda { - metadata.attribute("db/mysql/databases", :required => Hash.new) - }.should raise_error(ArgumentError) - end - - it "should set recipes to an empty array by default" do - metadata.attribute("db/mysql/databases", {}) - metadata.attributes["db/mysql/databases"][:recipes].should == [] - end - - it "should allow the default value to be a string, array, hash, boolean or numeric" do - lambda { - metadata.attribute("db/mysql/databases", :default => []) - }.should_not raise_error - lambda { - metadata.attribute("db/mysql/databases", :default => {}) - }.should_not raise_error - lambda { - metadata.attribute("db/mysql/databases", :default => "alice in chains") - }.should_not raise_error - lambda { - metadata.attribute("db/mysql/databases", :default => 1337) - }.should_not raise_error - lambda { - metadata.attribute("db/mysql/databases", :default => true) - }.should_not raise_error - lambda { - metadata.attribute("db/mysql/databases", :required => :not_gonna_do_it) - }.should raise_error(ArgumentError) - end - - it "should limit the types allowed in the choice array" do - options = { - :type => "string", - :choice => [ "test1", "test2" ], - :default => "test1" - } - lambda { - metadata.attribute("test_cookbook/test", options) - }.should_not raise_error - - options = { - :type => "boolean", - :choice => [ true, false ], - :default => true - } - lambda { - metadata.attribute("test_cookbook/test", options) - }.should_not raise_error - - options = { - :type => "numeric", - :choice => [ 1337, 420 ], - :default => 1337 - } - lambda { - metadata.attribute("test_cookbook/test", options) - }.should_not raise_error - - options = { - :type => "numeric", - :choice => [ true, "false" ], - :default => false - } - lambda { - metadata.attribute("test_cookbook/test", options) - }.should raise_error - end - - it "should error if default used with calculated" do - lambda { - attrs = { - :calculated => true, - :default => [ "I thought you said calculated" ] - } - metadata.attribute("db/mysql/databases", attrs) - }.should raise_error(ArgumentError) - lambda { - attrs = { - :calculated => true, - :default => "I thought you said calculated" - } - metadata.attribute("db/mysql/databases", attrs) - }.should raise_error(ArgumentError) - end - - it "should allow a default that is a choice" do - lambda { - attrs = { - :choice => [ "a", "b", "c"], - :default => "b" - } - metadata.attribute("db/mysql/databases", attrs) - }.should_not raise_error - lambda { - attrs = { - :choice => [ "a", "b", "c", "d", "e"], - :default => ["b", "d"] - } - metadata.attribute("db/mysql/databases", attrs) - }.should_not raise_error - end - - it "should error if default is not a choice" do - lambda { - attrs = { - :choice => [ "a", "b", "c"], - :default => "d" - } - metadata.attribute("db/mysql/databases", attrs) - }.should raise_error(ArgumentError) - lambda { - attrs = { - :choice => [ "a", "b", "c", "d", "e"], - :default => ["b", "z"] - } - metadata.attribute("db/mysql/databases", attrs) - }.should raise_error(ArgumentError) - end - end - - describe "recipes" do - let(:cookbook) do - c = Chef::CookbookVersion.new('test_cookbook') - c.recipe_files = [ "default.rb", "enlighten.rb" ] - c - end - - before(:each) do - metadata.name("test_cookbook") - metadata.recipes_from_cookbook_version(cookbook) - end - - it "should have the names of the recipes" do - metadata.recipes["test_cookbook"].should == "" - metadata.recipes["test_cookbook::enlighten"].should == "" - end - - it "should let you set the description for a recipe" do - metadata.recipe "test_cookbook", "It, um... tests stuff?" - metadata.recipes["test_cookbook"].should == "It, um... tests stuff?" - end - - it "should automatically provide each recipe" do - metadata.providing.has_key?("test_cookbook").should == true - metadata.providing.has_key?("test_cookbook::enlighten").should == true - end - - end - - describe "json" do - before(:each) do - metadata.version "1.0" - metadata.maintainer "Bobo T. Clown" - metadata.maintainer_email "bobo@example.com" - metadata.long_description "I have a long arm!" - metadata.supports :ubuntu, "> 8.04" - metadata.depends "bobo", "= 1.0" - metadata.depends "bubu", "=1.0" - metadata.depends "bobotclown", "= 1.1" - metadata.recommends "snark", "< 3.0" - metadata.suggests "kindness", "> 2.0" - metadata.conflicts "hatred" - metadata.provides "foo(:bar, :baz)" - metadata.replaces "snarkitron" - metadata.recipe "test_cookbook::enlighten", "is your buddy" - metadata.attribute "bizspark/has_login", - :display_name => "You have nothing" - metadata.version "1.2.3" - end - - describe "serialize" do - - let(:deserialized_metadata) { Chef::JSONCompat.from_json(metadata.to_json) } - - it "should serialize to a json hash" do - deserialized_metadata.should be_a_kind_of(Hash) - end - - %w{ - name - description - long_description - maintainer - maintainer_email - license - platforms - dependencies - suggestions - recommendations - conflicting - providing - replacing - attributes - recipes - version - }.each do |t| - it "should include '#{t}'" do - deserialized_metadata[t].should == metadata.send(t.to_sym) - end - end - end - - describe "deserialize" do - - let(:deserialized_metadata) { Chef::Cookbook::Metadata.from_json(metadata.to_json) } - - - it "should deserialize to a Chef::Cookbook::Metadata object" do - deserialized_metadata.should be_a_kind_of(Chef::Cookbook::Metadata) - end - - %w{ - name - description - long_description - maintainer - maintainer_email - license - platforms - dependencies - suggestions - recommendations - conflicting - providing - replacing - attributes - recipes - version - }.each do |t| - it "should match '#{t}'" do - deserialized_metadata.send(t.to_sym).should == metadata.send(t.to_sym) - end - end - end - - describe "from_hash" do - before(:each) do - @hash = metadata.to_hash - end - - [:dependencies, - :recommendations, - :suggestions, - :conflicting, - :replacing].each do |to_check| - it "should transform deprecated greater than syntax for :#{to_check.to_s}" do - @hash[to_check.to_s]["foo::bar"] = ">> 0.2" - deserial = Chef::Cookbook::Metadata.from_hash(@hash) - deserial.send(to_check)["foo::bar"].should == '> 0.2' - end - - it "should transform deprecated less than syntax for :#{to_check.to_s}" do - @hash[to_check.to_s]["foo::bar"] = "<< 0.2" - deserial = Chef::Cookbook::Metadata.from_hash(@hash) - deserial.send(to_check)["foo::bar"].should == '< 0.2' - end - - it "should ignore multiple dependency constraints for :#{to_check.to_s}" do - @hash[to_check.to_s]["foo::bar"] = [ ">= 1.0", "<= 5.2" ] - deserial = Chef::Cookbook::Metadata.from_hash(@hash) - deserial.send(to_check)["foo::bar"].should == [] - end - - it "should accept an empty array of dependency constraints for :#{to_check.to_s}" do - @hash[to_check.to_s]["foo::bar"] = [] - deserial = Chef::Cookbook::Metadata.from_hash(@hash) - deserial.send(to_check)["foo::bar"].should == [] - end - - it "should accept single-element arrays of dependency constraints for :#{to_check.to_s}" do - @hash[to_check.to_s]["foo::bar"] = [ ">= 2.0" ] - deserial = Chef::Cookbook::Metadata.from_hash(@hash) - deserial.send(to_check)["foo::bar"].should == ">= 2.0" - end - end - end - - end - -end diff --git a/spec/unit/cookbook/synchronizer_spec.rb b/spec/unit/cookbook/synchronizer_spec.rb deleted file mode 100644 index 2b040f3c95..0000000000 --- a/spec/unit/cookbook/synchronizer_spec.rb +++ /dev/null @@ -1,521 +0,0 @@ -require 'spec_helper' -require 'chef/cookbook/synchronizer' -require 'chef/cookbook_version' - -describe Chef::CookbookCacheCleaner do - describe "when cleaning up unused cookbook components" do - - let(:cleaner) do - cleaner = Chef::CookbookCacheCleaner.instance - cleaner.reset! - cleaner - end - - let(:file_cache) { double("Chef::FileCache with files from unused cookbooks") } - - let(:unused_template_files) do - %w{ - cookbooks/unused/templates/default/foo.conf.erb - cookbooks/unused/tempaltes/default/bar.conf.erb - } - end - - let(:valid_cached_cb_files) do - %w{ - cookbooks/valid1/recipes/default.rb - cookbooks/valid2/recipes/default.rb - } - end - - before do - valid_cached_cb_files.each do |cbf| - cleaner.mark_file_as_valid(cbf) - end - end - - it "removes all files not validated during the chef run" do - expect(file_cache).to receive(:find).with(File.join(%w{cookbooks ** {*,.*}})).and_return(valid_cached_cb_files + unused_template_files) - 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 - - it "does not remove anything when skip_removal is true" do - cleaner.skip_removal = true - allow(cleaner.cache).to receive(:find).and_return(%w{cookbooks/valid1/recipes/default.rb cookbooks/valid2/recipes/default.rb}) - expect(cleaner.cache).not_to receive(:delete) - cleaner.cleanup_file_cache - end - - it "does not remove anything on chef-solo" do - Chef::Config[:solo] = true - allow(cleaner.cache).to receive(:find).and_return(%w{cookbooks/valid1/recipes/default.rb cookbooks/valid2/recipes/default.rb}) - expect(cleaner.cache).not_to receive(:delete) - cleaner.cleanup_file_cache - end - end -end - -describe Chef::CookbookSynchronizer do - let(:cookbook_a_default_recipe) do - { - "path" => "recipes/default.rb", - "url" => "http://chef.example.com/abc123", - "checksum" => "abc123", - } - end - - let(:cookbook_a_default_attrs) do - { - "path" => "attributes/default.rb", - "url" => "http://chef.example.com/abc456", - "checksum" => "abc456", - } - end - - let(:cookbook_a_template) do - { - "path" => "templates/default/apache2.conf.erb", - "url" => "http://chef.example.com/ffffff", - "checksum" => "abc125", - } - end - - let(:cookbook_a_file) do - { - "path" => "files/default/megaman.conf", - "url" => "http://chef.example.com/megaman.conf", - "checksum" => "abc124", - } - end - - 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["recipes"] = [ cookbook_a_default_recipe ] - cookbook_a_manifest["attributes"] = [ cookbook_a_default_attrs ] - cookbook_a_manifest["templates"] = [ cookbook_a_template ] - cookbook_a_manifest["files"] = [ cookbook_a_file ] - cookbook_a_manifest - end - - let(:cookbook_a) do - cookbook_a = Chef::CookbookVersion.new("cookbook_a") - cookbook_a.manifest = cookbook_a_manifest - cookbook_a - end - - let(:cookbook_manifest) do - { - "cookbook_a" => cookbook_a - } - end - - let(:events) { Chef::EventDispatch::Dispatcher.new } - - let(:no_lazy_load) { true } - - let(:synchronizer) do - Chef::Config[:no_lazy_load] = no_lazy_load - Chef::CookbookSynchronizer.new(cookbook_manifest, events) - end - - it "lists the cookbook names" do - expect(synchronizer.cookbook_names).to eq(%w[cookbook_a]) - end - - it "lists the cookbook manifests" do - expect(synchronizer.cookbooks).to eq([cookbook_a]) - end - - context "#clear_obsoleted_cookbooks" do - after do - # Singletons == Global State == Bad - Chef::CookbookCacheCleaner.instance.skip_removal = nil - end - - it "behaves correctly when remove_obsoleted_files is false" do - synchronizer.remove_obsoleted_files = false - expect(synchronizer).not_to receive(:remove_old_cookbooks) - expect(synchronizer).to receive(:remove_deleted_files) - synchronizer.clear_obsoleted_cookbooks - expect(Chef::CookbookCacheCleaner.instance.skip_removal).to be true - end - - it "behaves correctly when remove_obsoleted_files is true" do - synchronizer.remove_obsoleted_files = true - expect(synchronizer).to receive(:remove_old_cookbooks) - expect(synchronizer).to receive(:remove_deleted_files) - synchronizer.clear_obsoleted_cookbooks - expect(Chef::CookbookCacheCleaner.instance.skip_removal).to be nil - end - end - - context "#remove_old_cookbooks" do - let(:file_cache) { double("Chef::FileCache with files from unused cookbooks") } - - let(:cookbook_manifest) do - {"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') - allow(synchronizer).to receive(:cache).and_return(file_cache) - synchronizer.remove_old_cookbooks - end - end - - context "#remove_deleted_files" do - let(:file_cache) { double("Chef::FileCache with files from unused cookbooks") } - - let(:cookbook_manifest) do - {"valid1"=> {}, "valid2" => {}} - end - - it "removes only deleted files" do - valid_cached_cb_files = %w{cookbooks/valid1/recipes/default.rb cookbooks/valid2/recipes/default.rb} - obsolete_cb_files = %w{cookbooks/valid1/recipes/deleted.rb cookbooks/valid2/recipes/deleted.rb} - expect(file_cache).to receive(:find).with(File.join(%w{cookbooks ** {*,.*}})).and_return(valid_cached_cb_files + obsolete_cb_files) - # valid1 is a cookbook in our run_list - 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(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 - end - end - - let(:cookbook_a_default_recipe_tempfile) do - double("Tempfile for cookbook_a default.rb recipe", - :path => "/tmp/cookbook_a_recipes_default_rb") - end - - let(:cookbook_a_default_attribute_tempfile) do - double("Tempfile for cookbook_a default.rb attr file", - :path => "/tmp/cookbook_a_attributes_default_rb") - end - - let(:cookbook_a_file_default_tempfile) do - double("Tempfile for cookbook_a megaman.conf file", - :path => "/tmp/cookbook_a_file_default_tempfile") - end - - let(:cookbook_a_template_default_tempfile) do - double("Tempfile for cookbook_a apache.conf.erb template", - :path => "/tmp/cookbook_a_template_default_tempfile") - end - - def setup_common_files_missing_expectations - # Files are not in the cache: - expect(file_cache).to receive(:has_key?). - with("cookbooks/cookbook_a/recipes/default.rb"). - and_return(false) - expect(file_cache).to receive(:has_key?). - with("cookbooks/cookbook_a/attributes/default.rb"). - and_return(false) - - # Fetch and copy default.rb recipe - expect(server_api).to receive(:get_rest). - with('http://chef.example.com/abc123', true). - 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") - expect(file_cache).to receive(:load). - with("cookbooks/cookbook_a/recipes/default.rb", false). - 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). - 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") - expect(file_cache).to receive(:load). - with("cookbooks/cookbook_a/attributes/default.rb", false). - and_return("/file-cache/cookbooks/cookbook_a/attributes/default.rb") - end - - def setup_no_lazy_files_and_templates_missing_expectations - expect(file_cache).to receive(:has_key?). - with("cookbooks/cookbook_a/files/default/megaman.conf"). - and_return(false) - expect(file_cache).to receive(:has_key?). - 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). - 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") - expect(file_cache).to receive(:load). - 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). - 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") - expect(file_cache).to receive(:load). - with("cookbooks/cookbook_a/templates/default/apache2.conf.erb", false). - and_return("/file-cache/cookbooks/cookbook_a/templates/default/apache2.conf.erb") - end - - def setup_common_files_chksum_mismatch_expectations - # Files are in the cache: - expect(file_cache).to receive(:has_key?). - with("cookbooks/cookbook_a/recipes/default.rb"). - and_return(true) - expect(file_cache).to receive(:has_key?). - with("cookbooks/cookbook_a/attributes/default.rb"). - and_return(true) - - # Fetch and copy default.rb recipe - expect(server_api).to receive(:get_rest). - with('http://chef.example.com/abc123', true). - 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") - expect(file_cache).to receive(:load). - with("cookbooks/cookbook_a/recipes/default.rb", false). - twice. - and_return("/file-cache/cookbooks/cookbook_a/recipes/default.rb") - - # Current file has fff000, want abc123 - expect(Chef::CookbookVersion).to receive(:checksum_cookbook_file). - with("/file-cache/cookbooks/cookbook_a/recipes/default.rb"). - and_return("fff000") - - # Fetch and copy default.rb attribute file - expect(server_api).to receive(:get_rest). - with('http://chef.example.com/abc456', true). - 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") - expect(file_cache).to receive(:load). - with("cookbooks/cookbook_a/attributes/default.rb", false). - twice. - and_return("/file-cache/cookbooks/cookbook_a/attributes/default.rb") - - # Current file has fff000, want abc456 - expect(Chef::CookbookVersion).to receive(:checksum_cookbook_file). - with("/file-cache/cookbooks/cookbook_a/attributes/default.rb"). - and_return("fff000") - end - - def setup_no_lazy_files_and_templates_chksum_mismatch_expectations - # Files are in the cache: - expect(file_cache).to receive(:has_key?). - with("cookbooks/cookbook_a/files/default/megaman.conf"). - and_return(true) - expect(file_cache).to receive(:has_key?). - with("cookbooks/cookbook_a/templates/default/apache2.conf.erb"). - and_return(true) - - # Fetch and copy megaman.conf - expect(server_api).to receive(:get_rest). - with('http://chef.example.com/megaman.conf', true). - 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") - expect(file_cache).to receive(:load). - with("cookbooks/cookbook_a/files/default/megaman.conf", false). - twice. - 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). - 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") - expect(file_cache).to receive(:load). - with("cookbooks/cookbook_a/templates/default/apache2.conf.erb", false). - twice. - and_return("/file-cache/cookbooks/cookbook_a/templates/default/apache2.conf.erb") - - # Current file has fff000 - expect(Chef::CookbookVersion).to receive(:checksum_cookbook_file). - with("/file-cache/cookbooks/cookbook_a/default/megaman.conf"). - and_return("fff000") - - # Current file has fff000 - expect(Chef::CookbookVersion).to receive(:checksum_cookbook_file). - with("/file-cache/cookbooks/cookbook_a/templates/default/apache2.conf.erb"). - and_return("fff000") - end - - def setup_common_files_present_expectations - # Files are in the cache: - expect(file_cache).to receive(:has_key?). - with("cookbooks/cookbook_a/recipes/default.rb"). - and_return(true) - expect(file_cache).to receive(:has_key?). - with("cookbooks/cookbook_a/attributes/default.rb"). - and_return(true) - - # Current file has abc123, want abc123 - expect(Chef::CookbookVersion).to receive(:checksum_cookbook_file). - with("/file-cache/cookbooks/cookbook_a/recipes/default.rb"). - and_return("abc123") - - # Current file has abc456, want abc456 - expect(Chef::CookbookVersion).to receive(:checksum_cookbook_file). - with("/file-cache/cookbooks/cookbook_a/attributes/default.rb"). - and_return("abc456") - - # :load called twice - expect(file_cache).to receive(:load). - with("cookbooks/cookbook_a/recipes/default.rb", false). - twice. - and_return("/file-cache/cookbooks/cookbook_a/recipes/default.rb") - expect(file_cache).to receive(:load). - with("cookbooks/cookbook_a/attributes/default.rb", false). - twice. - and_return("/file-cache/cookbooks/cookbook_a/attributes/default.rb") - end - - def setup_no_lazy_files_and_templates_present_expectations - # Files are in the cache: - expect(file_cache).to receive(:has_key?). - with("cookbooks/cookbook_a/files/default/megaman.conf"). - and_return(true) - expect(file_cache).to receive(:has_key?). - with("cookbooks/cookbook_a/templates/default/apache2.conf.erb"). - and_return(true) - - # Current file has abc124, want abc124 - expect(Chef::CookbookVersion).to receive(:checksum_cookbook_file). - with("/file-cache/cookbooks/cookbook_a/default/megaman.conf"). - and_return("abc124") - - # Current file has abc125, want abc125 - expect(Chef::CookbookVersion).to receive(:checksum_cookbook_file). - with("/file-cache/cookbooks/cookbook_a/templates/default/apache2.conf.erb"). - and_return("abc125") - - # :load called twice - expect(file_cache).to receive(:load). - with("cookbooks/cookbook_a/files/default/megaman.conf", false). - twice. - and_return("/file-cache/cookbooks/cookbook_a/default/megaman.conf") - expect(file_cache).to receive(:load). - with("cookbooks/cookbook_a/templates/default/apache2.conf.erb", false). - twice. - and_return("/file-cache/cookbooks/cookbook_a/templates/default/apache2.conf.erb") - end - - describe "when syncing cookbooks with the server" do - let(:server_api) { double("Chef::REST (mock)") } - - let(:file_cache) { double("Chef::FileCache (mock)") } - - before do - # Would rather not stub out methods on the test subject, but setting up - # the state is a PITA and tests for this behavior are above. - allow(synchronizer).to receive(:clear_obsoleted_cookbooks) - allow(synchronizer).to receive(:server_api).and_return(server_api) - allow(synchronizer).to receive(:cache).and_return(file_cache) - end - - context "when the cache does not contain the desired files" do - before do - setup_common_files_missing_expectations - end - - context "Chef::Config[:no_lazy_load] is false" do - let(:no_lazy_load) { false } - - it "fetches eagerly loaded files" do - synchronizer.sync_cookbooks - end - - 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) - - synchronizer.sync_cookbooks - end - end - - context "Chef::Config[:no_lazy_load] is true" do - let(:no_lazy_load) { true } - - before do - setup_no_lazy_files_and_templates_missing_expectations - end - - it "fetches templates and cookbook files" do - synchronizer.sync_cookbooks - end - end - end - - context "when the cache contains outdated files" do - before do - setup_common_files_chksum_mismatch_expectations - end - - context "Chef::Config[:no_lazy_load] is true" do - let(:no_lazy_load) { true } - - before do - setup_no_lazy_files_and_templates_chksum_mismatch_expectations - end - - it "updates the outdated files" do - synchronizer.sync_cookbooks - end - end - - context "Chef::Config[:no_lazy_load] is false" do - let(:no_lazy_load) { false } - - it "updates the outdated files" do - synchronizer.sync_cookbooks - end - end - end - - context "when the cache is up to date" do - before do - setup_common_files_present_expectations - end - - context "Chef::Config[:no_lazy_load] is true" do - let(:no_lazy_load) { true } - - before do - setup_no_lazy_files_and_templates_present_expectations - end - - it "does not update files" do - expect(file_cache).not_to receive(:move_to) - expect(server_api).not_to receive(:get_rest) - synchronizer.sync_cookbooks - end - end - - context "Chef::Config[:no_lazy_load] is false" do - let(:no_lazy_load) { false } - - it "does not update files" do - expect(file_cache).not_to receive(:move_to) - expect(server_api).not_to receive(:get_rest) - synchronizer.sync_cookbooks - end - end - end - end -end diff --git a/spec/unit/cookbook/syntax_check_spec.rb b/spec/unit/cookbook/syntax_check_spec.rb deleted file mode 100644 index cd1ce96716..0000000000 --- a/spec/unit/cookbook/syntax_check_spec.rb +++ /dev/null @@ -1,206 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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. -# - -require 'spec_helper' -require "chef/cookbook/syntax_check" - -describe Chef::Cookbook::SyntaxCheck do - before do - Chef::Platform.stub(:windows?) { false } - end - - 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 - %w{ attributes/default.rb - attributes/smokey.rb - definitions/client.rb - definitions/server.rb - metadata.rb - recipes/default.rb - recipes/gigantor.rb - recipes/one.rb - recipes/return.rb }.map{ |f| File.join(cookbook_path, f) } - end - - before do - Chef::Log.logger = Logger.new(StringIO.new) - Chef::Log.level = :warn # suppress "Syntax OK" messages - - @attr_files = %w{default.rb smokey.rb}.map { |f| File.join(cookbook_path, 'attributes', 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 + @defn_files + @recipes + [File.join(cookbook_path, "metadata.rb")] - basenames = %w{ helpers_via_partial_test.erb - helper_test.erb - openldap_stuff.conf.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)} - end - - it "creates a syntax checker given the cookbook name when Chef::Config.cookbook_path is set" do - Chef::Config[:cookbook_path] = File.dirname(cookbook_path) - syntax_check = Chef::Cookbook::SyntaxCheck.for_cookbook(:openldap) - syntax_check.cookbook_path.should == cookbook_path - syntax_check.ruby_files.sort.should == open_ldap_cookbook_files.sort - 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.cookbook_path.should == cookbook_path - syntax_check.ruby_files.sort.should == open_ldap_cookbook_files.sort - end - - context "when using a standalone cookbook" do - 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) - syntax_check.cookbook_path.should == cookbook_path - syntax_check.ruby_files.should == [File.join(cookbook_path, 'recipes/default.rb')] - end - end - - describe "when first created" do - it "has the path to the cookbook to syntax check" do - syntax_check.cookbook_path.should == cookbook_path - end - - it "lists the ruby files in the cookbook" do - syntax_check.ruby_files.sort.should == @ruby_files.sort - end - - it "lists the erb templates in the cookbook" do - syntax_check.template_files.sort.should == @template_files.sort - end - - end - - describe "when validating cookbooks" do - let(:cache_path) { Dir.mktmpdir } - - before do - Chef::Config[:syntax_check_cache_path] = cache_path - end - - after do - FileUtils.rm_rf(cache_path) if File.exist?(cache_path) - end - - describe "and the files have not been syntax checked previously" do - it "shows that all ruby files require a syntax check" do - syntax_check.untested_ruby_files.sort.should == @ruby_files.sort - end - - it "shows that all template files require a syntax check" do - syntax_check.untested_template_files.sort.should == @template_files.sort - 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') - syntax_check.validated(recipe) - syntax_check.untested_ruby_files.should_not 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') - syntax_check.validated(template) - syntax_check.untested_template_files.should_not include(template) - end - - it "validates all ruby files" do - syntax_check.validate_ruby_files.should be_true - syntax_check.untested_ruby_files.should be_empty - end - - it "validates all templates" do - syntax_check.validate_templates.should be_true - syntax_check.untested_template_files.should be_empty - end - - describe "and a file has a syntax error" do - before do - cookbook_path = File.join(CHEF_SPEC_DATA, 'cookbooks', 'borken') - syntax_check.cookbook_path.replace(cookbook_path) - end - - it "it indicates that a ruby file has a syntax error" do - syntax_check.validate_ruby_files.should be_false - end - - it "does not remove the invalid file from the list of untested files" do - syntax_check.untested_ruby_files.should include(File.join(cookbook_path, 'recipes', 'default.rb')) - syntax_check.validate_ruby_files - syntax_check.untested_ruby_files.should include(File.join(cookbook_path, 'recipes', 'default.rb')) - end - - it "indicates that a template file has a syntax error" do - syntax_check.validate_templates.should be_false - end - - it "does not remove the invalid template from the list of untested templates" do - syntax_check.untested_template_files.should include(File.join(cookbook_path, 'templates', 'default', 'borken.erb')) - lambda {syntax_check.validate_templates}.should_not 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') - 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')] - end - - it "shows that ignored ruby files do not require a syntax check" do - syntax_check.untested_ruby_files.sort.should == @ruby_files.sort - end - - it "does not indicate that a ruby file has a syntax error" do - syntax_check.validate_ruby_files.should be_true - syntax_check.untested_ruby_files.should be_empty - end - - end - - end - - describe "and the files have been syntax checked previously" do - before do - syntax_check.untested_ruby_files.each { |f| syntax_check.validated(f) } - syntax_check.untested_template_files.each { |f| syntax_check.validated(f) } - end - - it "does not syntax check ruby files" do - syntax_check.should_not_receive(:shell_out) - syntax_check.validate_ruby_files.should be_true - end - - it "does not syntax check templates" do - syntax_check.should_not_receive(:shell_out) - syntax_check.validate_templates.should be_true - end - end - end -end diff --git a/spec/unit/cookbook_loader_spec.rb b/spec/unit/cookbook_loader_spec.rb deleted file mode 100644 index f40bbd5696..0000000000 --- a/spec/unit/cookbook_loader_spec.rb +++ /dev/null @@ -1,287 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef::CookbookLoader do - before do - Chef::Platform.stub(: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")) - ] - end - - let(:cookbook_loader) { Chef::CookbookLoader.new(repo_paths) } - - it "checks each directory only once when loading (CHEF-3487)" do - cookbook_paths = [] - repo_paths.each do |repo_path| - cookbook_paths |= Dir[File.join(repo_path, "*")] - end - - cookbook_paths.delete_if { |path| File.basename(path) == "chefignore" } - - cookbook_paths.each do |cookbook_path| - Chef::Cookbook::CookbookVersionLoader.should_receive(:new). - with(cookbook_path, anything). - once. - and_call_original - end - cookbook_loader.load_cookbooks - end - - - context "after loading all cookbooks" do - before(:each) do - cookbook_loader.load_cookbooks - end - - describe "[]" do - it "should return cookbook objects with []" do - cookbook_loader[:openldap].should be_a_kind_of(Chef::CookbookVersion) - end - - it "should raise an exception if it cannot find a cookbook with []" do - lambda { cookbook_loader[:monkeypoop] }.should raise_error(Chef::Exceptions::CookbookNotFoundInRepo) - end - - it "should allow you to look up available cookbooks with [] and a symbol" do - cookbook_loader[:openldap].name.should eql(:openldap) - end - - it "should allow you to look up available cookbooks with [] and a string" do - cookbook_loader["openldap"].name.should eql(:openldap) - end - end - - describe "each" do - it "should allow you to iterate over cookbooks with each" do - seen = Hash.new - cookbook_loader.each do |cookbook_name, cookbook| - seen[cookbook_name] = true - end - seen.should have_key("openldap") - seen.should have_key("apache2") - end - - it "should iterate in alphabetical order" do - seen = Array.new - cookbook_loader.each do |cookbook_name, cookbook| - seen << cookbook_name - end - seen[0].should == "angrybash" - seen[1].should == "apache2" - seen[2].should == "borken" - seen[3].should == "ignorken" - seen[4].should == "java" - seen[5].should == "name-mismatch" - seen[6].should == "openldap" - end - end - - describe "referencing cookbook files" do - it "should find all the cookbooks in the cookbook path" do - cookbook_loader.load_cookbooks - cookbook_loader.should have_key(:openldap) - cookbook_loader.should have_key(:apache2) - end - - it "should allow you to override an attribute file via cookbook_path" do - cookbook_loader[:openldap].attribute_filenames.detect { |f| - f =~ /cookbooks\/openldap\/attributes\/default.rb/ - }.should_not eql(nil) - cookbook_loader[:openldap].attribute_filenames.detect { |f| - f =~ /kitchen\/openldap\/attributes\/default.rb/ - }.should eql(nil) - end - - it "should load different attribute files from deeper paths" do - cookbook_loader[:openldap].attribute_filenames.detect { |f| - f =~ /kitchen\/openldap\/attributes\/robinson.rb/ - }.should_not eql(nil) - end - - it "should allow you to override a definition file via cookbook_path" do - cookbook_loader[:openldap].definition_filenames.detect { |f| - f =~ /cookbooks\/openldap\/definitions\/client.rb/ - }.should_not eql(nil) - cookbook_loader[:openldap].definition_filenames.detect { |f| - f =~ /kitchen\/openldap\/definitions\/client.rb/ - }.should eql(nil) - end - - it "should load definition files from deeper paths" do - cookbook_loader[:openldap].definition_filenames.detect { |f| - f =~ /kitchen\/openldap\/definitions\/drewbarrymore.rb/ - }.should_not eql(nil) - end - - it "should allow you to override a recipe file via cookbook_path" do - cookbook_loader[:openldap].recipe_filenames.detect { |f| - f =~ /cookbooks\/openldap\/recipes\/gigantor.rb/ - }.should_not eql(nil) - cookbook_loader[:openldap].recipe_filenames.detect { |f| - f =~ /kitchen\/openldap\/recipes\/gigantor.rb/ - }.should eql(nil) - end - - it "should load recipe files from deeper paths" do - cookbook_loader[:openldap].recipe_filenames.detect { |f| - f =~ /kitchen\/openldap\/recipes\/woot.rb/ - }.should_not eql(nil) - end - - it "should allow you to have an 'ignore' file, which skips loading files in later cookbooks" do - cookbook_loader[:openldap].recipe_filenames.detect { |f| - f =~ /kitchen\/openldap\/recipes\/ignoreme.rb/ - }.should eql(nil) - end - - it "should find files that start with a ." do - cookbook_loader[:openldap].file_filenames.detect { |f| - f =~ /\.dotfile$/ - }.should =~ /\.dotfile$/ - cookbook_loader[:openldap].file_filenames.detect { |f| - f =~ /\.ssh\/id_rsa$/ - }.should =~ /\.ssh\/id_rsa$/ - end - - it "should load the metadata for the cookbook" do - cookbook_loader.metadata[:openldap].name.to_s.should == "openldap" - cookbook_loader.metadata[:openldap].should be_a_kind_of(Chef::Cookbook::Metadata) - end - - end # referencing cookbook files - - end # loading all cookbooks - - context "loading all cookbooks when one has invalid metadata" do - - let(:repo_paths) do - [ - File.join(CHEF_SPEC_DATA, "kitchen"), - File.join(CHEF_SPEC_DATA, "cookbooks"), - File.join(CHEF_SPEC_DATA, "invalid-metadata-chef-repo") - ] - end - - it "does not squelch the exception" do - expect { cookbook_loader.load_cookbooks }.to raise_error("THIS METADATA HAS A BUG") - end - - end - - describe "loading only one cookbook" do - before(:each) do - cookbook_loader.load_cookbook("openldap") - end - - it "should have loaded the correct cookbook" do - seen = Hash.new - cookbook_loader.each do |cookbook_name, cookbook| - seen[cookbook_name] = true - end - seen.should have_key("openldap") - end - - it "should not duplicate keys when serialized to JSON" do - # Chef JSON serialization will generate duplicate keys if given - # a Hash containing matching string and symbol keys. See CHEF-4571. - aa = cookbook_loader["openldap"] - aa.to_hash["metadata"].recipes.keys.should_not include(:openldap) - aa.to_hash["metadata"].recipes.keys.should include("openldap") - expected_desc = "Main Open LDAP configuration" - aa.to_hash["metadata"].recipes["openldap"].should == expected_desc - raw = aa.to_hash["metadata"].recipes.to_json - search_str = "\"openldap\":\"" - key_idx = raw.index(search_str) - key_idx.should be > 0 - dup_idx = raw[(key_idx + 1)..-1].index(search_str) - dup_idx.should be_nil - end - - it "should not load the cookbook again when accessed" do - cookbook_loader.should_not_receive('load_cookbook') - cookbook_loader["openldap"] - end - - it "should not load the other cookbooks" do - seen = Hash.new - cookbook_loader.each do |cookbook_name, cookbook| - seen[cookbook_name] = true - end - seen.should_not have_key("apache2") - end - - it "should load another cookbook lazily with []" do - cookbook_loader["apache2"].should be_a_kind_of(Chef::CookbookVersion) - end - - context "when an unrelated cookbook has invalid metadata" do - - let(:repo_paths) do - [ - File.join(CHEF_SPEC_DATA, "kitchen"), - File.join(CHEF_SPEC_DATA, "cookbooks"), - File.join(CHEF_SPEC_DATA, "invalid-metadata-chef-repo") - ] - end - - it "ignores the invalid cookbook" do - expect { cookbook_loader["openldap"] }.to_not raise_error - end - - it "surfaces the exception if the cookbook is loaded later" do - expect { cookbook_loader["invalid-metadata"] }.to raise_error("THIS METADATA HAS A BUG") - end - - end - - describe "loading all cookbooks after loading only one cookbook" do - before(:each) do - cookbook_loader.load_cookbooks - end - - it "should load all cookbooks" do - seen = Hash.new - cookbook_loader.each do |cookbook_name, cookbook| - seen[cookbook_name] = true - end - seen.should have_key("openldap") - seen.should have_key("apache2") - end - end - end # loading only one cookbook - - describe "loading a single cookbook with a different name than basename" do - - before(:each) do - cookbook_loader.load_cookbook("name-mismatch") - end - - it "loads the correct cookbook" do - cookbook_version = cookbook_loader["name-mismatch"] - cookbook_version.should be_a_kind_of(Chef::CookbookVersion) - cookbook_version.name.should == :"name-mismatch" - end - - end -end diff --git a/spec/unit/cookbook_manifest_spec.rb b/spec/unit/cookbook_manifest_spec.rb deleted file mode 100644 index e87b8e1e9a..0000000000 --- a/spec/unit/cookbook_manifest_spec.rb +++ /dev/null @@ -1,554 +0,0 @@ -# -# Author:: Tim Hinderliter (<tim@opscode.com>) -# Author:: Christopher Walters (<cw@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. -# - -require 'spec_helper' - -describe "Chef::CookbookVersion manifest" do - before(:each) do - @cookbook = Chef::CookbookVersion.new "test-cookbook" - @cookbook.manifest = { - "files" => - [ - # afile.rb - { - :name => "afile.rb", - :path => "files/host-examplehost.example.org/afile.rb", - :checksum => "csum-host", - :specificity => "host-examplehost.example.org" - }, - { - :name => "afile.rb", - :path => "files/ubuntu-9.10/afile.rb", - :checksum => "csum-platver-full", - :specificity => "ubuntu-9.10" - }, - { - :name => "afile.rb", - :path => "files/newubuntu-9/afile.rb", - :checksum => "csum-platver-partial", - :specificity => "newubuntu-9" - }, - { - :name => "afile.rb", - :path => "files/ubuntu/afile.rb", - :checksum => "csum-plat", - :specificity => "ubuntu" - }, - { - :name => "afile.rb", - :path => "files/default/afile.rb", - :checksum => "csum-default", - :specificity => "default" - }, - - # for different/odd platform_versions - { - :name => "bfile.rb", - :path => "files/fakeos-2.0.rc.1/bfile.rb", - :checksum => "csum2-platver-full", - :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" - }, - { - :name => "bfile.rb", - :path => "files/fakeos-maple tree/bfile.rb", - :checksum => "csum3-platver-full", - :specificity => "maple tree" - }, - { - :name => "bfile.rb", - :path => "files/fakeos-1/bfile.rb", - :checksum => "csum4-platver-full", - :specificity => "fakeos-1" - }, - - # directory adirectory - { - :name => "anotherfile1.rb", - :path => "files/host-examplehost.example.org/adirectory/anotherfile1.rb.host", - :checksum => "csum-host-1", - :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" - }, - - { - :name => "anotherfile1.rb", - :path => "files/ubuntu-9.10/adirectory/anotherfile1.rb.platform-full-version", - :checksum => "csum-platver-full-1", - :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" - }, - - { - :name => "anotherfile1.rb", - :path => "files/newubuntu-9/adirectory/anotherfile1.rb.platform-partial-version", - :checksum => "csum-platver-partial-1", - :specificity => "newubuntu-9" - }, - { - :name => "anotherfile2.rb", - :path => "files/newubuntu-9/adirectory/anotherfile2.rb.platform-partial-version", - :checksum => "csum-platver-partial-2", - :specificity => "nweubuntu-9" - }, - - { - :name => "anotherfile1.rb", - :path => "files/ubuntu/adirectory/anotherfile1.rb.platform", - :checksum => "csum-plat-1", - :specificity => "ubuntu" - }, - { - :name => "anotherfile2.rb", - :path => "files/ubuntu/adirectory/anotherfile2.rb.platform", - :checksum => "csum-plat-2", - :specificity => "ubuntu" - }, - - { - :name => "anotherfile1.rb", - :path => "files/default/adirectory/anotherfile1.rb.default", - :checksum => "csum-default-1", - :specificity => "default" - }, - { - :name => "anotherfile2.rb", - :path => "files/default/adirectory/anotherfile2.rb.default", - :checksum => "csum-default-2", - :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" - }, - { - :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" - }, - { - :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" - }, - { - :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" - }, - { - :name => "anotherfile1.rb", - :path => "files/fakeos-maple tree/adirectory/anotherfile1.rb.platform-full-version", - :checksum => "csum3-platver-full-1", - :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" - }, - { - :name => "anotherfile1.rb", - :path => "files/fakeos-1/adirectory/anotherfile1.rb.platform-full-version", - :checksum => "csum4-platver-full-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" - }, - ] - } - - end - - - it "should return a manifest record based on priority preference: host" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "ubuntu" - node.automatic_attrs[:platform_version] = "9.10" - node.automatic_attrs[:fqdn] = "examplehost.example.org" - - manifest_record = @cookbook.preferred_manifest_record(node, :files, "afile.rb") - manifest_record.should_not be_nil - manifest_record[:checksum].should == "csum-host" - end - - it "should return a manifest record based on priority preference: platform & full version" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "ubuntu" - node.automatic_attrs[:platform_version] = "9.10" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - manifest_record = @cookbook.preferred_manifest_record(node, :files, "afile.rb") - manifest_record.should_not be_nil - manifest_record[:checksum].should == "csum-platver-full" - end - - it "should return a manifest record based on priority preference: platform & partial version" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "newubuntu" - node.automatic_attrs[:platform_version] = "9.10" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - manifest_record = @cookbook.preferred_manifest_record(node, :files, "afile.rb") - manifest_record.should_not be_nil - manifest_record[:checksum].should == "csum-platver-partial" - end - - it "should return a manifest record based on priority preference: platform only" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "ubuntu" - node.automatic_attrs[:platform_version] = "1.0" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - manifest_record = @cookbook.preferred_manifest_record(node, :files, "afile.rb") - manifest_record.should_not be_nil - manifest_record[:checksum].should == "csum-plat" - end - - it "should return a manifest record based on priority preference: default" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "notubuntu" - node.automatic_attrs[:platform_version] = "1.0" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - manifest_record = @cookbook.preferred_manifest_record(node, :files, "afile.rb") - manifest_record.should_not be_nil - manifest_record[:checksum].should == "csum-default" - end - - it "should return a manifest record based on priority preference: platform & full version - platform_version variant 1" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "fakeos" - node.automatic_attrs[:platform_version] = "2.0.rc.1" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - manifest_record = @cookbook.preferred_manifest_record(node, :files, "bfile.rb") - manifest_record.should_not be_nil - manifest_record[:checksum].should == "csum2-platver-full" - end - - it "should return a manifest record based on priority preference: platform & partial version - platform_version variant 1" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "newfakeos" - node.automatic_attrs[:platform_version] = "2.0.rc.1" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - manifest_record = @cookbook.preferred_manifest_record(node, :files, "bfile.rb") - manifest_record.should_not be_nil - manifest_record[:checksum].should == "csum2-platver-partial" - end - - it "should return a manifest record based on priority preference: platform & full version - platform_version variant 2" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "fakeos" - node.automatic_attrs[:platform_version] = "maple tree" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - manifest_record = @cookbook.preferred_manifest_record(node, :files, "bfile.rb") - manifest_record.should_not be_nil - manifest_record[:checksum].should == "csum3-platver-full" - end - - it "should return a manifest record based on priority preference: platform & full version - platform_version variant 3" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "fakeos" - node.automatic_attrs[:platform_version] = "1" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - manifest_record = @cookbook.preferred_manifest_record(node, :files, "bfile.rb") - manifest_record.should_not be_nil - manifest_record[:checksum].should == "csum4-platver-full" - end - - describe "when fetching the contents of a directory by file specificity" do - - it "should return a directory of manifest records based on priority preference: host" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "ubuntu" - node.automatic_attrs[:platform_version] = "9.10" - node.automatic_attrs[:fqdn] = "examplehost.example.org" - - manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") - manifest_records.should_not be_nil - manifest_records.size.should == 2 - - checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } - checksums.sort.should == ["csum-host-1", "csum-host-2"] - end - - it "should return a directory of manifest records based on priority preference: platform & full version" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "ubuntu" - node.automatic_attrs[:platform_version] = "9.10" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") - manifest_records.should_not be_nil - manifest_records.size.should == 2 - - checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } - checksums.sort.should == ["csum-platver-full-1", "csum-platver-full-2"] - end - - it "should return a directory of manifest records based on priority preference: platform & partial version" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "newubuntu" - node.automatic_attrs[:platform_version] = "9.10" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") - manifest_records.should_not be_nil - manifest_records.size.should == 2 - - checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } - checksums.sort.should == ["csum-platver-partial-1", "csum-platver-partial-2"] - end - - it "should return a directory of manifest records based on priority preference: platform only" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "ubuntu" - node.automatic_attrs[:platform_version] = "1.0" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") - manifest_records.should_not be_nil - manifest_records.size.should == 2 - - checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } - checksums.sort.should == ["csum-plat-1", "csum-plat-2"] - end - - it "should return a directory of manifest records based on priority preference: default" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "notubuntu" - node.automatic_attrs[:platform_version] = "1.0" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") - manifest_records.should_not be_nil - manifest_records.size.should == 2 - - checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } - checksums.sort.should == ["csum-default-1", "csum-default-2"] - end - - it "should return a manifest record based on priority preference: platform & full version - platform_version variant 1" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "fakeos" - node.automatic_attrs[:platform_version] = "2.0.rc.1" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") - manifest_records.should_not be_nil - manifest_records.size.should == 2 - - checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } - checksums.sort.should == ["csum2-platver-full-1", "csum2-platver-full-2"] - end - - it "should return a manifest record based on priority preference: platform & partial version - platform_version variant 1" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "newfakeos" - node.automatic_attrs[:platform_version] = "2.0.rc.1" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") - manifest_records.should_not be_nil - manifest_records.size.should == 2 - - checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } - checksums.sort.should == ["csum2-platver-partial-1", "csum2-platver-partial-2"] - end - - it "should return a manifest record based on priority preference: platform & full version - platform_version variant 2" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "fakeos" - node.automatic_attrs[:platform_version] = "maple tree" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") - manifest_records.should_not be_nil - manifest_records.size.should == 2 - - checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } - checksums.sort.should == ["csum3-platver-full-1", "csum3-platver-full-2"] - end - - it "should return a manifest record based on priority preference: platform & full version - platform_version variant 3" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "fakeos" - node.automatic_attrs[:platform_version] = "1" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - manifest_records = @cookbook.preferred_manifest_records_for_directory(node, :files, "adirectory") - manifest_records.should_not be_nil - manifest_records.size.should == 2 - - checksums = manifest_records.map{ |manifest_record| manifest_record[:checksum] } - checksums.sort.should == ["csum4-platver-full-1", "csum4-platver-full-2"] - end - end - - ## Globbing the relative paths out of the manifest records ## - - describe "when globbing for relative file paths based on filespecificity" do - it "should return a list of relative paths based on priority preference: host" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "ubuntu" - node.automatic_attrs[:platform_version] = "9.10" - node.automatic_attrs[:fqdn] = "examplehost.example.org" - - filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") - filenames.should_not be_nil - filenames.size.should == 2 - - filenames.sort.should == ['anotherfile1.rb.host', 'anotherfile2.rb.host'] - end - - it "should return a list of relative paths based on priority preference: platform & full version" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "ubuntu" - node.automatic_attrs[:platform_version] = "9.10" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") - filenames.should_not be_nil - filenames.size.should == 2 - - filenames.sort.should == ['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 - node = Chef::Node.new - node.automatic_attrs[:platform] = "newubuntu" - node.automatic_attrs[:platform_version] = "9.10" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") - filenames.should_not be_nil - filenames.size.should == 2 - - filenames.sort.should == ['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 - node = Chef::Node.new - node.automatic_attrs[:platform] = "ubuntu" - node.automatic_attrs[:platform_version] = "1.0" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") - filenames.should_not be_nil - filenames.size.should == 2 - - filenames.sort.should == ['anotherfile1.rb.platform', 'anotherfile2.rb.platform'] - end - - it "should return a list of relative paths based on priority preference: default" do - node = Chef::Node.new - node.automatic_attrs[:platform] = "notubuntu" - node.automatic_attrs[:platform_version] = "1.0" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") - filenames.should_not be_nil - filenames.size.should == 2 - - filenames.sort.should == ['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 - node = Chef::Node.new - node.automatic_attrs[:platform] = "fakeos" - node.automatic_attrs[:platform_version] = "2.0.rc.1" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") - filenames.should_not be_nil - filenames.size.should == 2 - - filenames.sort.should == ['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 - node = Chef::Node.new - node.automatic_attrs[:platform] = "newfakeos" - node.automatic_attrs[:platform_version] = "2.0.rc.1" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") - filenames.should_not be_nil - filenames.size.should == 2 - - filenames.sort.should == ['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 - node = Chef::Node.new - node.automatic_attrs[:platform] = "fakeos" - node.automatic_attrs[:platform_version] = "maple tree" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") - filenames.should_not be_nil - filenames.size.should == 2 - - filenames.sort.should == ['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 - node = Chef::Node.new - node.automatic_attrs[:platform] = "fakeos" - node.automatic_attrs[:platform_version] = "1" - node.automatic_attrs[:fqdn] = "differenthost.example.org" - - filenames = @cookbook.relative_filenames_in_preferred_directory(node, :files, "adirectory") - filenames.should_not be_nil - filenames.size.should == 2 - - filenames.sort.should == ['anotherfile1.rb.platform-full-version', 'anotherfile2.rb.platform-full-version'] - end - end -end diff --git a/spec/unit/cookbook_site_streaming_uploader_spec.rb b/spec/unit/cookbook_site_streaming_uploader_spec.rb deleted file mode 100644 index 1d7009e31c..0000000000 --- a/spec/unit/cookbook_site_streaming_uploader_spec.rb +++ /dev/null @@ -1,220 +0,0 @@ -# -# Author:: Xabier de Zuazo (xabier@onddo.com) -# Copyright:: Copyright (c) 2013 Onddo Labs, SL. -# 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/cookbook_site_streaming_uploader' - -class FakeTempfile - def initialize(basename) - @basename = basename - end - - def close - end - - def path - "#{@basename}.ZZZ" - end - -end - -describe Chef::CookbookSiteStreamingUploader do - - describe "create_build_dir" do - - before(:each) do - @cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, 'cookbooks')) - @loader = Chef::CookbookLoader.new(@cookbook_repo) - @loader.load_cookbooks - File.stub(:unlink).and_return() - end - - 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) } - - Tempfile.should_receive(:new).with("chef-#{cookbook.name}-build").and_return(FakeTempfile.new("chef-#{cookbook.name}-build")) - FileUtils.should_receive(:mkdir_p).exactly(files_count + 1).times - FileUtils.should_receive(:cp).exactly(files_count).times - Chef::CookbookSiteStreamingUploader.create_build_dir(cookbook) - end - - end # create_build_dir - - describe "make_request" do - - before(:each) do - @uri = "http://cookbooks.dummy.com/api/v1/cookbooks" - @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') - Net::HTTP.any_instance.stub(:request).and_return(response) - end - - it "should send an http request" do - Net::HTTP.any_instance.should_receive(:request) - Chef::CookbookSiteStreamingUploader.make_request(:post, @uri, 'bill', @secret_filename) - end - - it "should read the private key file" do - File.should_receive(:read).with(@secret_filename).and_return(@rsa_key) - Chef::CookbookSiteStreamingUploader.make_request(:post, @uri, 'bill', @secret_filename) - end - - it "should add the authentication signed header" do - Mixlib::Authentication::SigningObject.any_instance.should_receive(:sign).and_return({}) - Chef::CookbookSiteStreamingUploader.make_request(:post, @uri, 'bill', @secret_filename) - end - - it "should be able to send post requests" do - post = Net::HTTP::Post.new(@uri, {}) - - Net::HTTP::Post.should_receive(:new).once.and_return(post) - Net::HTTP::Put.should_not_receive(:new) - Net::HTTP::Get.should_not_receive(:new) - Chef::CookbookSiteStreamingUploader.make_request(:post, @uri, 'bill', @secret_filename) - end - - it "should be able to send put requests" do - put = Net::HTTP::Put.new(@uri, {}) - - Net::HTTP::Post.should_not_receive(:new) - Net::HTTP::Put.should_receive(:new).once.and_return(put) - Net::HTTP::Get.should_not_receive(:new) - 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 - }) - 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', - }) - 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', - }) - 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) - Net::HTTP.should_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) - @http.verify_mode.should == 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) - @http.verify_mode.should == 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')) - @stream_part = Chef::CookbookSiteStreamingUploader::StreamPart.new(@file, File.size(@file)) - end - - it "should create a StreamPart" do - @stream_part.should be_instance_of(Chef::CookbookSiteStreamingUploader::StreamPart) - end - - it "should expose its size" do - @stream_part.size.should eql(File.size(@file)) - end - - it "should read with offset and how_much" do - content = @file.read(4) - @file.rewind - @stream_part.read(0, 4).should eql(content) - end - - end # StreamPart - - describe "StringPart" do - before(:each) do - @str = 'What a boring string' - @string_part = Chef::CookbookSiteStreamingUploader::StringPart.new(@str) - end - - it "should create a StringPart" do - @string_part.should be_instance_of(Chef::CookbookSiteStreamingUploader::StringPart) - end - - it "should expose its size" do - @string_part.size.should eql(@str.size) - end - - it "should read with offset and how_much" do - @string_part.read(2, 4).should eql(@str[2, 4]) - end - - end # StringPart - - describe "MultipartStream" do - before(:each) do - @string1 = "stream1" - @string2 = "stream2" - @stream1 = Chef::CookbookSiteStreamingUploader::StringPart.new(@string1) - @stream2 = Chef::CookbookSiteStreamingUploader::StringPart.new(@string2) - @parts = [ @stream1, @stream2 ] - - @multipart_stream = Chef::CookbookSiteStreamingUploader::MultipartStream.new(@parts) - end - - it "should create a MultipartStream" do - @multipart_stream.should be_instance_of(Chef::CookbookSiteStreamingUploader::MultipartStream) - end - - it "should expose its size" do - @multipart_stream.size.should eql(@stream1.size + @stream2.size) - end - - it "should read with how_much" do - @multipart_stream.read(10).should eql("#{@string1}#{@string2}"[0, 10]) - end - - it "should read receiving destination buffer as second argument (CHEF-4456: Ruby 2 compat)" do - dst_buf = '' - @multipart_stream.read(10, dst_buf) - dst_buf.should eql("#{@string1}#{@string2}"[0, 10]) - end - - end # MultipartStream - -end diff --git a/spec/unit/cookbook_spec.rb b/spec/unit/cookbook_spec.rb deleted file mode 100644 index 9bcea97d98..0000000000 --- a/spec/unit/cookbook_spec.rb +++ /dev/null @@ -1,75 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef::CookbookVersion do -# COOKBOOK_PATH = File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "cookbooks", "openldap")) - before(:each) do - @cookbook_repo = File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "cookbooks")) - cl = Chef::CookbookLoader.new(@cookbook_repo) - cl.load_cookbooks - @cookbook_collection = Chef::CookbookCollection.new(cl) - @cookbook = @cookbook_collection[:openldap] - @node = Chef::Node.new - @node.name "JuliaChild" - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events) - end - - it "should have a name" do - @cookbook.name.should == :openldap - end - - it "should allow you to set the list of attribute files and create the mapping from short names to paths" do - @cookbook.attribute_filenames = [ "attributes/one.rb", "attributes/two.rb" ] - @cookbook.attribute_filenames.should == [ "attributes/one.rb", "attributes/two.rb" ] - @cookbook.attribute_filenames_by_short_filename.keys.sort.should eql(["one", "two"]) - @cookbook.attribute_filenames_by_short_filename["one"].should == "attributes/one.rb" - @cookbook.attribute_filenames_by_short_filename["two"].should == "attributes/two.rb" - end - - it "should allow you to set the list of recipe files and create the mapping of recipe short name to filename" do - @cookbook.recipe_filenames = [ "recipes/one.rb", "recipes/two.rb" ] - @cookbook.recipe_filenames.should == [ "recipes/one.rb", "recipes/two.rb" ] - @cookbook.recipe_filenames_by_name.keys.sort.should eql(["one", "two"]) - @cookbook.recipe_filenames_by_name["one"].should == "recipes/one.rb" - @cookbook.recipe_filenames_by_name["two"].should == "recipes/two.rb" - end - - it "should generate a list of recipes by fully-qualified name" do - @cookbook.recipe_filenames = [ "recipes/one.rb", "/recipes/two.rb", "three.rb" ] - @cookbook.fully_qualified_recipe_names.include?("openldap::one").should == true - @cookbook.fully_qualified_recipe_names.include?("openldap::two").should == true - @cookbook.fully_qualified_recipe_names.include?("openldap::three").should == true - end - - it "should find a preferred file" do - pending - end - - it "should not return an unchanged preferred file" do - pending - @cookbook.preferred_filename(@node, :files, 'a-filename', 'the-checksum').should be_nil - end - - it "should raise an ArgumentException if you try to load a bad recipe name" do - lambda { @cookbook.load_recipe("doesnt_exist", @node) }.should raise_error(ArgumentError) - end - -end diff --git a/spec/unit/cookbook_uploader_spec.rb b/spec/unit/cookbook_uploader_spec.rb deleted file mode 100644 index af25baff13..0000000000 --- a/spec/unit/cookbook_uploader_spec.rb +++ /dev/null @@ -1,160 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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' - -describe Chef::CookbookUploader do - - let(:http_client) { double("Chef::REST") } - - let(:cookbook_loader) do - loader = Chef::CookbookLoader.new(File.join(CHEF_SPEC_DATA, "cookbooks")) - loader.load_cookbooks - loader - end - - let(:apache2_cookbook) { cookbook_loader.cookbooks_by_name["apache2"] } - - let(:java_cookbook) { cookbook_loader.cookbooks_by_name["java"] } - - let(:cookbooks_to_upload) { [apache2_cookbook, java_cookbook] } - - let(:checksums_of_cookbook_files) { apache2_cookbook.checksums.merge(java_cookbook.checksums) } - - let(:checksums_set) do - checksums_of_cookbook_files.keys.inject({}) do |set, cksum| - set[cksum] = nil - set - end - end - - let(:sandbox_commit_uri) { "https://chef.example.org/sandboxes/abc123" } - - let(:uploader) { described_class.new(cookbooks_to_upload, :rest => http_client) } - - it "has a list of cookbooks to upload" do - expect(uploader.cookbooks).to eq(cookbooks_to_upload) - 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) - uploader = described_class.new(cookbooks_to_upload) - expect(uploader.rest).to eq(default_http_client) - end - - describe "uploading cookbooks" do - - def url_for(cksum) - "https://storage.example.com/#{cksum}" - end - - 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 - end - { "checksums" => sandbox_checksums, "uri" => sandbox_commit_uri } - end - - def expect_sandbox_create - expect(http_client).to receive(:post). - with("sandboxes", {:checksums => checksums_set}). - and_return(sandbox_response) - end - - def expect_checksum_upload - checksums_of_cookbook_files.each do |md5, file_path| - next unless cksums_not_on_remote.include?(md5) - - upload_headers = { - "content-type" => "application/x-binary", - "content-md5" => an_instance_of(String), - "accept" => "application/json" - } - - expect(http_client).to receive(:put). - with(url_for(md5), IO.binread(file_path), upload_headers) - - end - end - - def expect_sandbox_commit - expect(http_client).to receive(:put).with(sandbox_commit_uri, {:is_completed => true}) - end - - def expect_cookbook_create - cookbooks_to_upload.each do |cookbook| - - expect(http_client).to receive(:put). - with(cookbook.save_url, cookbook) - - end - end - - context "when no files exist on the server" do - - let(:cksums_not_on_remote) do - checksums_of_cookbook_files.keys - end - - it "uploads all files in a sandbox transaction, then creates cookbooks on the server" do - expect_sandbox_create - expect_checksum_upload - expect_sandbox_commit - expect_cookbook_create - - uploader.upload_cookbooks - end - - end - - context "when some files exist on the server" do - - let(:cksums_not_on_remote) do - checksums_of_cookbook_files.keys[0, 1] - end - - it "uploads all files in a sandbox transaction, then creates cookbooks on the server" do - expect_sandbox_create - expect_checksum_upload - expect_sandbox_commit - expect_cookbook_create - - uploader.upload_cookbooks - end - - end - - context "when all files already exist on the server" do - - let(:cksums_not_on_remote) { [] } - - it "uploads all files in a sandbox transaction, then creates cookbooks on the server" do - expect_sandbox_create - expect_checksum_upload - expect_sandbox_commit - expect_cookbook_create - - uploader.upload_cookbooks - end - - end - end - -end diff --git a/spec/unit/cookbook_version_spec.rb b/spec/unit/cookbook_version_spec.rb deleted file mode 100644 index f20bc3766a..0000000000 --- a/spec/unit/cookbook_version_spec.rb +++ /dev/null @@ -1,425 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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. - -require 'spec_helper' - -describe Chef::CookbookVersion do - describe "when first created" do - before do - @cookbook_version = Chef::CookbookVersion.new("tatft", '/tmp/blah') - end - - it "has a name" do - @cookbook_version.name.should == 'tatft' - end - - it "has no attribute files" do - @cookbook_version.attribute_filenames.should be_empty - end - - it "has no resource definition files" do - @cookbook_version.definition_filenames.should be_empty - end - - it "has no cookbook files" do - @cookbook_version.file_filenames.should be_empty - end - - it "has no recipe files" do - @cookbook_version.recipe_filenames.should be_empty - end - - it "has no library files" do - @cookbook_version.library_filenames.should be_empty - end - - it "has no LWRP resource files" do - @cookbook_version.resource_filenames.should be_empty - end - - it "has no LWRP provider files" do - @cookbook_version.provider_filenames.should be_empty - end - - it "has no metadata files" do - @cookbook_version.metadata_filenames.should be_empty - end - - it "is not frozen" do - @cookbook_version.should_not be_frozen_version - end - - it "can be frozen" do - @cookbook_version.freeze_version - @cookbook_version.should be_frozen_version - end - - it "is \"ready\"" do - # WTF is this? what are the valid states? and why aren't they set with encapsulating methods? - # [Dan 15-Jul-2010] - @cookbook_version.status.should == :ready - end - - it "has empty metadata" do - @cookbook_version.metadata.should == Chef::Cookbook::Metadata.new - end - - it "creates a manifest hash of its contents" do - expected = {"recipes"=>[], - "definitions"=>[], - "libraries"=>[], - "attributes"=>[], - "files"=>[], - "templates"=>[], - "resources"=>[], - "providers"=>[], - "root_files"=>[], - "cookbook_name"=>"tatft", - "metadata"=>Chef::Cookbook::Metadata.new, - "version"=>"0.0.0", - "name"=>"tatft-0.0.0"} - @cookbook_version.manifest.should == expected - end - end - - describe "with a cookbook directory named tatft" do - MD5 = /[0-9a-f]{32}/ - - before do - @cookbook = Hash.new { |hash, key| hash[key] = [] } - - @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')) - - 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.attribute_filenames = @cookbook[:attribute_filenames] - @cookbook_version.definition_filenames = @cookbook[:definition_filenames] - @cookbook_version.recipe_filenames = @cookbook[:recipe_filenames] - @cookbook_version.template_filenames = @cookbook[:template_filenames] - @cookbook_version.file_filenames = @cookbook[:file_filenames] - @cookbook_version.library_filenames = @cookbook[:library_filenames] - @cookbook_version.resource_filenames = @cookbook[:resource_filenames] - @cookbook_version.provider_filenames = @cookbook[:provider_filenames] - @cookbook_version.root_filenames = @cookbook[:root_filenames] - @cookbook_version.metadata_filenames = @cookbook[:metadata_filenames] - - # Used to test file-specificity related file lookups - @node = Chef::Node.new - @node.set[:platform] = "ubuntu" - @node.set[:platform_version] = "13.04" - @node.name("testing") - end - - it "generates a manifest containing the cookbook's files" do - manifest = @cookbook_version.manifest - - manifest["metadata"].should == Chef::Cookbook::Metadata.new - manifest["cookbook_name"].should == "tatft" - - manifest["recipes"].should have(1).recipe_file - - recipe = manifest["recipes"].first - recipe["name"].should == "default.rb" - recipe["path"].should == "recipes/default.rb" - recipe["checksum"].should match(MD5) - recipe["specificity"].should == "default" - - manifest["definitions"].should have(1).definition_file - - definition = manifest["definitions"].first - definition["name"].should == "runit_service.rb" - definition["path"].should == "definitions/runit_service.rb" - definition["checksum"].should match(MD5) - definition["specificity"].should == "default" - - manifest["libraries"].should have(1).library_file - - library = manifest["libraries"].first - library["name"].should == "ownage.rb" - library["path"].should == "libraries/ownage.rb" - library["checksum"].should match(MD5) - library["specificity"].should == "default" - - manifest["attributes"].should have(1).attribute_file - - attribute_file = manifest["attributes"].first - attribute_file["name"].should == "default.rb" - attribute_file["path"].should == "attributes/default.rb" - attribute_file["checksum"].should match(MD5) - attribute_file["specificity"].should == "default" - - manifest["files"].should have(1).cookbook_file - - cookbook_file = manifest["files"].first - cookbook_file["name"].should == "giant_blob.tgz" - cookbook_file["path"].should == "files/default/giant_blob.tgz" - cookbook_file["checksum"].should match(MD5) - cookbook_file["specificity"].should == "default" - - manifest["templates"].should have(1).template - - template = manifest["templates"].first - template["name"].should == "configuration.erb" - template["path"].should == "templates/default/configuration.erb" - template["checksum"].should match(MD5) - template["specificity"].should == "default" - - manifest["resources"].should have(1).lwr - - lwr = manifest["resources"].first - lwr["name"].should == "lwr.rb" - lwr["path"].should == "resources/lwr.rb" - lwr["checksum"].should match(MD5) - lwr["specificity"].should == "default" - - manifest["providers"].should have(1).lwp - - lwp = manifest["providers"].first - lwp["name"].should == "lwp.rb" - lwp["path"].should == "providers/lwp.rb" - lwp["checksum"].should match(MD5) - lwp["specificity"].should == "default" - - manifest["root_files"].should have(1).file_in_the_cookbook_root - - readme = manifest["root_files"].first - readme["name"].should == "README.rdoc" - readme["path"].should == "README.rdoc" - readme["checksum"].should match(MD5) - readme["specificity"].should == "default" - end - - it "determines whether a template is available for a given node" do - @cookbook_version.should have_template_for_node(@node, "configuration.erb") - @cookbook_version.should_not have_template_for_node(@node, "missing.erb") - end - - it "determines whether a cookbook_file is available for a given node" do - @cookbook_version.should have_cookbook_file_for_node(@node, "giant_blob.tgz") - @cookbook_version.should_not have_cookbook_file_for_node(@node, "missing.txt") - end - - describe "raises an error when attempting to load a missing cookbook_file and" do - before do - node = Chef::Node.new.tap do |n| - n.name("sample.node") - n.automatic_attrs[:fqdn] = "sample.example.com" - n.automatic_attrs[:platform] = "ubuntu" - n.automatic_attrs[:platform_version] = "10.04" - end - @attempt_to_load_file = lambda { @cookbook_version.preferred_manifest_record(node, :files, "no-such-thing.txt") } - end - - it "describes the cookbook and version" do - useful_explanation = Regexp.new(Regexp.escape("Cookbook 'tatft' (0.0.0) does not contain")) - @attempt_to_load_file.should raise_error(Chef::Exceptions::FileNotFound, useful_explanation) - end - - it "lists suggested places to look" do - useful_explanation = Regexp.new(Regexp.escape("files/default/no-such-thing.txt")) - @attempt_to_load_file.should raise_error(Chef::Exceptions::FileNotFound, useful_explanation) - end - end - end - - describe "and a cookbook_version with a different name" do - before do - # Currently the cookbook loader finds all the files then tells CookbookVersion - # where they are. - @cookbook_version = Chef::CookbookVersion.new("blarghle", @cookbook_root) - @cookbook_version.attribute_filenames = @cookbook[:attribute_filenames] - @cookbook_version.definition_filenames = @cookbook[:definition_filenames] - @cookbook_version.recipe_filenames = @cookbook[:recipe_filenames] - @cookbook_version.template_filenames = @cookbook[:template_filenames] - @cookbook_version.file_filenames = @cookbook[:file_filenames] - @cookbook_version.library_filenames = @cookbook[:library_filenames] - @cookbook_version.resource_filenames = @cookbook[:resource_filenames] - @cookbook_version.provider_filenames = @cookbook[:provider_filenames] - @cookbook_version.root_filenames = @cookbook[:root_filenames] - @cookbook_version.metadata_filenames = @cookbook[:metadata_filenames] - end - - it "generates a manifest containing the cookbook's files" do - manifest = @cookbook_version.manifest - - manifest["metadata"].should == Chef::Cookbook::Metadata.new - manifest["cookbook_name"].should == "blarghle" - - manifest["recipes"].should have(1).recipe_file - - recipe = manifest["recipes"].first - recipe["name"].should == "default.rb" - recipe["path"].should == "recipes/default.rb" - recipe["checksum"].should match(MD5) - recipe["specificity"].should == "default" - - manifest["definitions"].should have(1).definition_file - - definition = manifest["definitions"].first - definition["name"].should == "runit_service.rb" - definition["path"].should == "definitions/runit_service.rb" - definition["checksum"].should match(MD5) - definition["specificity"].should == "default" - - manifest["libraries"].should have(1).library_file - - library = manifest["libraries"].first - library["name"].should == "ownage.rb" - library["path"].should == "libraries/ownage.rb" - library["checksum"].should match(MD5) - library["specificity"].should == "default" - - manifest["attributes"].should have(1).attribute_file - - attribute_file = manifest["attributes"].first - attribute_file["name"].should == "default.rb" - attribute_file["path"].should == "attributes/default.rb" - attribute_file["checksum"].should match(MD5) - attribute_file["specificity"].should == "default" - - manifest["files"].should have(1).cookbook_file - - cookbook_file = manifest["files"].first - cookbook_file["name"].should == "giant_blob.tgz" - cookbook_file["path"].should == "files/default/giant_blob.tgz" - cookbook_file["checksum"].should match(MD5) - cookbook_file["specificity"].should == "default" - - manifest["templates"].should have(1).template - - template = manifest["templates"].first - template["name"].should == "configuration.erb" - template["path"].should == "templates/default/configuration.erb" - template["checksum"].should match(MD5) - template["specificity"].should == "default" - - manifest["resources"].should have(1).lwr - - lwr = manifest["resources"].first - lwr["name"].should == "lwr.rb" - lwr["path"].should == "resources/lwr.rb" - lwr["checksum"].should match(MD5) - lwr["specificity"].should == "default" - - manifest["providers"].should have(1).lwp - - lwp = manifest["providers"].first - lwp["name"].should == "lwp.rb" - lwp["path"].should == "providers/lwp.rb" - lwp["checksum"].should match(MD5) - lwp["specificity"].should == "default" - - manifest["root_files"].should have(1).file_in_the_cookbook_root - - readme = manifest["root_files"].first - readme["name"].should == "README.rdoc" - readme["path"].should == "README.rdoc" - readme["checksum"].should match(MD5) - readme["specificity"].should == "default" - end - end - - end - - - describe "<=>" do - - it "should sort based on the version number" do - examples = [ - # smaller, larger - ["1.0", "2.0"], - ["1.2.3", "1.2.4"], - ["1.2.3", "1.3.0"], - ["1.2.3", "1.3"], - ["1.2.3", "2.1.1"], - ["1.2.3", "2.1"], - ["1.2", "1.2.4"], - ["1.2", "1.3.0"], - ["1.2", "1.3"], - ["1.2", "2.1.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.version = smaller - lg.version = larger - sm.should be < lg - lg.should be > sm - sm.should_not == lg - end - 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.version = "1.2" - b.version = "1.2.0" - a.should == b - end - - - it "should not allow you to sort cookbooks with different names" do - apt = Chef::CookbookVersion.new "apt", '/tmp/blah' - apt.version = "1.0" - god = Chef::CookbookVersion.new "god", '/tmp/blah' - god.version = "2.0" - lambda {apt <=> god}.should raise_error(Chef::Exceptions::CookbookVersionNameMismatch) - end - end - - describe "when you set a version" do - before do - @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.each do |v| - @cbv.version = v - end - end - - it "should raise InvalidVersion for bad cookbook versions" do - bad_versions = ["1.2.3.4", "1.2.a4", "1", "a", "1.2 3", "1.2 a", - "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| - lambda {@cbv.version = v}.should raise_error(the_error) - end - end - - end - -end diff --git a/spec/unit/daemon_spec.rb b/spec/unit/daemon_spec.rb deleted file mode 100644 index 9132dae389..0000000000 --- a/spec/unit/daemon_spec.rb +++ /dev/null @@ -1,174 +0,0 @@ -# -# Author:: AJ Christensen (<aj@junglist.gen.nz>) -# 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 'ostruct' - -describe Chef::Daemon do - before do - if windows? - mock_struct = #Struct::Passwd.new(nil, nil, 111, 111) - mock_struct = OpenStruct.new(:uid => 2342, :gid => 2342) - Etc.stub(:getpwnam).and_return mock_struct - Etc.stub(:getgrnam).and_return mock_struct - # mock unimplemented methods - Process.stub(:initgroups).and_return nil - Process::GID.stub(:change_privilege).and_return 11 - Process::UID.stub(:change_privilege).and_return 11 - end - end - - describe ".pid_file" do - - describe "when the pid_file option has been set" do - - before do - Chef::Config[:pid_file] = "/var/run/chef/chef-client.pid" - end - - it "should return the supplied value" do - Chef::Daemon.pid_file.should eql("/var/run/chef/chef-client.pid") - end - end - - describe "without the pid_file option set" do - - before do - Chef::Daemon.name = "chef-client" - end - - it "should return a valued based on @name" do - Chef::Daemon.pid_file.should eql("/tmp/chef-client.pid") - end - - end - end - - describe ".pid_from_file" do - - before do - Chef::Config[:pid_file] = "/var/run/chef/chef-client.pid" - end - - it "should suck the pid out of pid_file" do - File.should_receive(:read).with("/var/run/chef/chef-client.pid").and_return("1337") - Chef::Daemon.pid_from_file - end - end - - describe ".change_privilege" do - - before do - Chef::Application.stub(:fatal!).and_return(true) - Chef::Config[:user] = 'aj' - Dir.stub(:chdir) - end - - it "changes the working directory to root" do - Dir.should_receive(:chdir).with("/").and_return(0) - Chef::Daemon.change_privilege - end - - describe "when the user and group options are supplied" do - - before do - Chef::Config[:group] = 'staff' - end - - it "should log an appropriate info message" do - Chef::Log.should_receive(:info).with("About to change privilege to aj:staff") - Chef::Daemon.change_privilege - end - - it "should call _change_privilege with the user and group" do - Chef::Daemon.should_receive(:_change_privilege).with("aj", "staff") - Chef::Daemon.change_privilege - end - end - - describe "when just the user option is supplied" do - it "should log an appropriate info message" do - Chef::Log.should_receive(:info).with("About to change privilege to aj") - Chef::Daemon.change_privilege - end - - it "should call _change_privilege with just the user" do - Chef::Daemon.should_receive(:_change_privilege).with("aj") - Chef::Daemon.change_privilege - end - end - end - - describe "._change_privilege" do - - before do - Process.stub(:euid).and_return(0) - Process.stub(:egid).and_return(0) - - Process::UID.stub(:change_privilege).and_return(nil) - Process::GID.stub(:change_privilege).and_return(nil) - - @pw_user = double("Struct::Passwd", :uid => 501) - @pw_group = double("Struct::Group", :gid => 20) - - Process.stub(:initgroups).and_return(true) - - Etc.stub(:getpwnam).and_return(@pw_user) - Etc.stub(:getgrnam).and_return(@pw_group) - end - - describe "with sufficient privileges" do - before do - Process.stub(:euid).and_return(0) - Process.stub(:egid).and_return(0) - end - - it "should initialize the supplemental group list" do - Process.should_receive(:initgroups).with("aj", 20) - Chef::Daemon._change_privilege("aj") - end - - it "should attempt to change the process GID" do - Process::GID.should_receive(:change_privilege).with(20).and_return(20) - Chef::Daemon._change_privilege("aj") - end - - it "should attempt to change the process UID" do - Process::UID.should_receive(:change_privilege).with(501).and_return(501) - Chef::Daemon._change_privilege("aj") - end - end - - describe "with insufficient privileges" do - before do - Process.stub(:euid).and_return(999) - Process.stub(:egid).and_return(999) - end - - it "should log an appropriate error message and fail miserably" do - Process.stub(:initgroups).and_raise(Errno::EPERM) - error = "Operation not permitted" - if RUBY_PLATFORM.match("solaris2") || RUBY_PLATFORM.match("aix") - error = "Not owner" - end - Chef::Application.should_receive(:fatal!).with("Permission denied when trying to change 999:999 to 501:20. #{error}") - Chef::Daemon._change_privilege("aj") - end - end - - end -end diff --git a/spec/unit/data_bag_item_spec.rb b/spec/unit/data_bag_item_spec.rb deleted file mode 100644 index ead0dadfa2..0000000000 --- a/spec/unit/data_bag_item_spec.rb +++ /dev/null @@ -1,288 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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/data_bag_item' - -describe Chef::DataBagItem do - before(:each) do - @data_bag_item = Chef::DataBagItem.new - end - - describe "initialize" do - it "should be a Chef::DataBagItem" do - @data_bag_item.should be_a_kind_of(Chef::DataBagItem) - end - end - - describe "data_bag" do - it "should let you set the data_bag to a string" do - @data_bag_item.data_bag("clowns").should == "clowns" - end - - it "should return the current data_bag type" do - @data_bag_item.data_bag "clowns" - @data_bag_item.data_bag.should == "clowns" - end - - it "should not accept spaces" do - lambda { @data_bag_item.data_bag "clown masters" }.should raise_error(ArgumentError) - end - - it "should throw an ArgumentError if you feed it anything but a string" do - lambda { @data_bag_item.data_bag Hash.new }.should raise_error(ArgumentError) - end - end - - describe "raw_data" do - it "should let you set the raw_data with a hash" do - lambda { @data_bag_item.raw_data = { "id" => "octahedron" } }.should_not raise_error - end - - it "should let you set the raw_data from a mash" do - lambda { @data_bag_item.raw_data = Mash.new({ "id" => "octahedron" }) }.should_not raise_error - end - - it "should raise an exception if you set the raw data without a key" do - lambda { @data_bag_item.raw_data = { "monkey" => "pants" } }.should raise_error(ArgumentError) - end - - it "should raise an exception if you set the raw data to something other than a hash" do - lambda { @data_bag_item.raw_data = "katie rules" }.should raise_error(ArgumentError) - end - - it "should accept alphanum/-/_ for the id" do - lambda { @data_bag_item.raw_data = { "id" => "h1-_" } }.should_not raise_error - end - - it "should accept alphanum.alphanum for the id" do - lambda { @data_bag_item.raw_data = { "id" => "foo.bar" } }.should_not raise_error - end - - it "should accept .alphanum for the id" do - lambda { @data_bag_item.raw_data = { "id" => ".bozo" } }.should_not raise_error - end - - it "should raise an exception if the id contains anything but alphanum/-/_" do - lambda { @data_bag_item.raw_data = { "id" => "!@#" } }.should raise_error(ArgumentError) - end - - it "should return the raw data" do - @data_bag_item.raw_data = { "id" => "highway_of_emptiness" } - @data_bag_item.raw_data.should == { "id" => "highway_of_emptiness" } - end - - it "should be a Mash by default" do - @data_bag_item.raw_data.should be_a_kind_of(Mash) - end - end - - describe "object_name" do - before(:each) do - @data_bag_item.data_bag("dreams") - @data_bag_item.raw_data = { "id" => "the_beatdown" } - end - - it "should return an object name based on the bag name and the raw_data id" do - @data_bag_item.object_name.should == "data_bag_item_dreams_the_beatdown" - end - end - - describe "class method object_name" do - it "should return an object name based based on the bag name and an id" do - Chef::DataBagItem.object_name("zen", "master").should == "data_bag_item_zen_master" - end - end - - describe "when used like a Hash" do - before(:each) do - @data_bag_item.raw_data = { "id" => "journey", "trials" => "been through" } - end - - it "responds to keys" do - @data_bag_item.keys.should include("id") - @data_bag_item.keys.should include("trials") - end - - it "supports element reference with []" do - @data_bag_item["id"].should == "journey" - end - - it "implements all the methods of Hash" do - methods = [:rehash, :to_hash, :[], :fetch, :[]=, :store, :default, - :default=, :default_proc, :index, :size, :length, - :empty?, :each_value, :each_key, :each_pair, :each, :keys, :values, - :values_at, :delete, :delete_if, :reject!, :clear, - :invert, :update, :replace, :merge!, :merge, :has_key?, :has_value?, - :key?, :value?] - methods.each do |m| - @data_bag_item.should respond_to(m) - end - end - - end - - describe "to_hash" do - before(:each) do - @data_bag_item.data_bag("still_lost") - @data_bag_item.raw_data = { "id" => "whoa", "i_know" => "kung_fu" } - @to_hash = @data_bag_item.to_hash - end - - it "should return a hash" do - @to_hash.should be_a_kind_of(Hash) - end - - it "should have the raw_data keys as top level keys" do - @to_hash["id"].should == "whoa" - @to_hash["i_know"].should == "kung_fu" - end - - it "should have the chef_type of data_bag_item" do - @to_hash["chef_type"].should == "data_bag_item" - end - - it "should have the data_bag set" do - @to_hash["data_bag"].should == "still_lost" - end - end - - describe "when deserializing from JSON" do - before(:each) do - @data_bag_item.data_bag('mars_volta') - @data_bag_item.raw_data = { "id" => "octahedron", "snooze" => { "finally" => :world_will }} - @deserial = Chef::JSONCompat.from_json(@data_bag_item.to_json) - end - - it "should deserialize to a Chef::DataBagItem object" do - @deserial.should be_a_kind_of(Chef::DataBagItem) - end - - it "should have a matching 'data_bag' value" do - @deserial.data_bag.should == @data_bag_item.data_bag - end - - it "should have a matching 'id' key" do - @deserial["id"].should == "octahedron" - end - - it "should have a matching 'snooze' key" do - @deserial["snooze"].should == { "finally" => "world_will" } - 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" - @data_bag_item.to_s.should == '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"} - @data_bag_item.raw_data = raw_data - @data_bag_item.data_bag("books") - - @data_bag_item.inspect.should == "data_bag_item[\"books\", \"heart_of_darkness\", #{raw_data.inspect}]" - end - end - - describe "save" do - before do - @rest = double("Chef::REST") - Chef::REST.stub(:new).and_return(@rest) - @data_bag_item['id'] = "heart of darkness" - raw_data = {"id" => "heart_of_darkness", "author" => "Conrad"} - @data_bag_item.raw_data = raw_data - @data_bag_item.data_bag("books") - end - it "should update the item when it already exists" do - @rest.should_receive(:put_rest).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") - @rest.should_receive(:put_rest).and_raise(Net::HTTPServerException.new("foo", exception)) - @rest.should_receive(:post_rest).with("data/books", @data_bag_item) - @data_bag_item.save - end - describe "when whyrun mode is enabled" do - before do - Chef::Config[:why_run] = true - end - after do - Chef::Config[:why_run] = false - end - it "should not save" do - @rest.should_not_receive(:put_rest) - @rest.should_not_receive(:post_rest) - @data_bag_item.data_bag("books") - @data_bag_item.save - end - end - - - end - - describe "when loading" do - before do - @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 - before do - @http_client = double("Chef::REST") - Chef::REST.stub(:new).and_return(@http_client) - end - - it "converts raw data to a data bag item" do - @http_client.should_receive(:get_rest).with("data/users/charlie").and_return(@data_bag_item.to_hash) - item = Chef::DataBagItem.load(:users, "charlie") - item.should be_a_kind_of(Chef::DataBagItem) - item.should == @data_bag_item - end - - it "does not convert when a DataBagItem is returned from the API call" do - @http_client.should_receive(:get_rest).with("data/users/charlie").and_return(@data_bag_item) - item = Chef::DataBagItem.load(:users, "charlie") - item.should be_a_kind_of(Chef::DataBagItem) - item.should equal(@data_bag_item) - end - end - - describe "in solo mode" do - before do - Chef::Config[:solo] = true - end - - after do - Chef::Config[:solo] = false - end - - it "converts the raw data to a data bag item" do - Chef::DataBag.should_receive(:load).with('users').and_return({'charlie' => @data_bag_item.to_hash}) - item = Chef::DataBagItem.load('users', 'charlie') - item.should be_a_kind_of(Chef::DataBagItem) - item.should == @data_bag_item - end - end - - end - -end diff --git a/spec/unit/data_bag_spec.rb b/spec/unit/data_bag_spec.rb deleted file mode 100644 index c905277b7c..0000000000 --- a/spec/unit/data_bag_spec.rb +++ /dev/null @@ -1,256 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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/data_bag' - -describe Chef::DataBag do - before(:each) do - @data_bag = Chef::DataBag.new - Chef::Platform::stub(:windows?) { false } - end - - describe "initialize" do - it "should be a Chef::DataBag" do - @data_bag.should be_a_kind_of(Chef::DataBag) - end - end - - describe "name" do - it "should let you set the name to a string" do - @data_bag.name("clowns").should == "clowns" - end - - it "should return the current name" do - @data_bag.name "clowns" - @data_bag.name.should == "clowns" - end - - it "should not accept spaces" do - lambda { @data_bag.name "clown masters" }.should raise_error(ArgumentError) - end - - it "should throw an ArgumentError if you feed it anything but a string" do - lambda { @data_bag.name Hash.new }.should raise_error(ArgumentError) - end - - [ ".", "-", "_", "1"].each do |char| - it "should allow a '#{char}' character in the data bag name" do - @data_bag.name("clown#{char}clown").should == "clown#{char}clown" - end - end - end - - describe "deserialize" do - before(:each) do - @data_bag.name('mars_volta') - @deserial = Chef::JSONCompat.from_json(@data_bag.to_json) - end - - it "should deserialize to a Chef::DataBag object" do - @deserial.should be_a_kind_of(Chef::DataBag) - end - - %w{ - name - }.each do |t| - it "should match '#{t}'" do - @deserial.send(t.to_sym).should == @data_bag.send(t.to_sym) - end - end - - end - - describe "when saving" do - before do - @data_bag.name('piggly_wiggly') - @rest = double("Chef::REST") - Chef::REST.stub(:new).and_return(@rest) - end - - it "should silently proceed when the data bag already exists" do - exception = double("409 error", :code => "409") - @rest.should_receive(:post_rest).and_raise(Net::HTTPServerException.new("foo", exception)) - @data_bag.save - end - - it "should create the data bag" do - @rest.should_receive(:post_rest).with("data", @data_bag) - @data_bag.save - end - - describe "when whyrun mode is enabled" do - before do - Chef::Config[:why_run] = true - end - after do - Chef::Config[:why_run] = false - end - it "should not save" do - @rest.should_not_receive(:post_rest) - @data_bag.save - end - end - - end - 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') - end - - it "should get the data bag from the server" do - Chef::REST.should_receive(:new).with('https://myserver.example.com').and_return(@http_client) - @http_client.should_receive(:get_rest).with('data/foo') - Chef::DataBag.load('foo') - end - - it "should return the data bag" do - Chef::REST.stub(:new).and_return(@http_client) - @http_client.should_receive(:get_rest).with('data/foo').and_return({'bar' => 'https://myserver.example.com/data/foo/bar'}) - data_bag = Chef::DataBag.load('foo') - data_bag.should == {'bar' => 'https://myserver.example.com/data/foo/bar'} - end - end - - def file_dir_stub(path, returns = true) - File.should_receive(:directory?).with(path).and_return(returns) - end - - def dir_glob_stub(path, returns = []) - Dir.should_receive(:glob).with(File.join(path, 'foo/*.json')).and_return(returns) - end - - shared_examples_for "data bag in solo mode" do |data_bag_path| - before do - Chef::Config[:solo] = true - Chef::Config[:data_bag_path] = data_bag_path - @paths = Array(data_bag_path) - end - - after do - Chef::Config[:solo] = false - end - - it "should get the data bag from the data_bag_path" do - @paths.each do |path| - file_dir_stub(path) - dir_glob_stub(path) - end - Chef::DataBag.load('foo') - end - - it "should get the data bag from the data_bag_path by symbolic name" do - @paths.each do |path| - file_dir_stub(path) - dir_glob_stub(path) - end - Chef::DataBag.load(:foo) - end - - it "should return the data bag" 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')]) - else - dir_glob_stub(path) - end - end - IO.should_receive(:read).with(File.join(@paths.first, 'foo/bar.json')).and_return('{"id": "bar", "name": "Bob Bar" }') - IO.should_receive(:read).with(File.join(@paths.first, 'foo/baz.json')).and_return('{"id": "baz", "name": "John Baz" }') - data_bag = Chef::DataBag.load('foo') - data_bag.should == { '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}\"}" - IO.should_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')]) - item_2_with_different_content = '{"id": "bar", "name": "John Baz"}' - IO.should_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')]) - end - end - 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')]) - item_with_same_content = '{"id": "bar", "name": "Bob Bar"}' - IO.should_receive(:read).with(File.join(path, 'foo/bar.json')).and_return(item_with_same_content) - IO.should_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.should == 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')]) - test_item_with_same_content = '{"id": "bar", "name": "Bob Bar"}' - IO.should_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}\"}" - IO.should_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'} } - @paths.each_with_index do |path, index| - test_data_bag["baz_#{index}"] = { "id" => "baz_#{index}", "name" => "John Baz", "path" => path } - end - data_bag.should == test_data_bag - end - - it "should return the data bag list" do - @paths.each do |path| - file_dir_stub(path) - Dir.should_receive(:glob).and_return([File.join(path, 'foo'), File.join(path, 'bar')]) - end - data_bag_list = Chef::DataBag.list - data_bag_list.should == { 'bar' => 'bar', 'foo' => 'foo' } - end - - it 'should raise an error if the configured data_bag_path is invalid' do - file_dir_stub(@paths.first, false) - - lambda { - Chef::DataBag.load('foo') - }.should raise_error Chef::Exceptions::InvalidDataBagPath, "Data bag path '/var/chef/data_bags' is invalid" - end - - end - - describe "data bag with string path" do - it_should_behave_like "data bag in solo mode", "/var/chef/data_bags" - end - - describe "data bag with array path" do - it_should_behave_like "data bag in solo mode", ["/var/chef/data_bags", "/var/chef/data_bags_2"] - end - end - -end diff --git a/spec/unit/deprecation_spec.rb b/spec/unit/deprecation_spec.rb deleted file mode 100644 index c5ab41fbab..0000000000 --- a/spec/unit/deprecation_spec.rb +++ /dev/null @@ -1,85 +0,0 @@ -# -# Author:: Serdar Sutay (<serdar@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' -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| - mod.const_get(class_name) - end - end - - module DeprecatedMethods - def deprecated_method(value) - @value = value - end - - def get_value - @value - end - end - - class TestClass - extend Chef::Deprecation::Warnings - include DeprecatedMethods - add_deprecation_warnings_for(DeprecatedMethods.instance_methods) - end - - method_snapshot_file = File.join(CHEF_SPEC_DATA, "file-providers-method-snapshot-chef-11-4.json") - method_snapshot = Chef::JSONCompat.parse(File.open(method_snapshot_file).read()) - - method_snapshot.each do |class_name, old_methods| - class_object = class_from_string(class_name) - current_methods = class_object.public_instance_methods.map(&:to_sym) - - it "defines all methods on #{class_object} that were available in 11.0" do - old_methods.each do |old_method| - current_methods.should include(old_method.to_sym) - end - end - end - - context 'deprecation warning messages' do - before(:each) do - @warning_output = [ ] - Chef::Log.stub(:warn) { |msg| @warning_output << msg } - end - - it 'should be enabled for deprecated methods' do - TestClass.new.deprecated_method(10) - @warning_output.should_not be_empty - end - - it 'should contain stack trace' do - TestClass.new.deprecated_method(10) - @warning_output.join("").include?(".rb").should be_true - end - end - - it 'deprecated methods should still be called' do - test_instance = TestClass.new - test_instance.deprecated_method(10) - test_instance.get_value.should == 10 - end - -end diff --git a/spec/unit/digester_spec.rb b/spec/unit/digester_spec.rb deleted file mode 100644 index fdf20aca7c..0000000000 --- a/spec/unit/digester_spec.rb +++ /dev/null @@ -1,50 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: Daniel DeLeo (<dan@kallistec.com>) -# Copyright:: Copyright (c) 2009 Opscode, Inc. -# Copyright:: Copyright (c) 2009 Daniel DeLeo -# 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::Digester do - before(:each) do - @cache = Chef::Digester.instance - end - - describe "when computing checksums of cookbook files and templates" do - - it "proxies the class method checksum_for_file to the instance" do - @cache.should_receive(:checksum_for_file).with("a_file_or_a_fail") - Chef::Digester.checksum_for_file("a_file_or_a_fail") - end - - it "computes a checksum of a file" do - fixture_file = CHEF_SPEC_DATA + "/checksum/random.txt" - expected = "09ee9c8cc70501763563bcf9c218d71b2fbf4186bf8e1e0da07f0f42c80a3394" - @cache.checksum_for_file(fixture_file).should == expected - end - - it "generates a checksum from a non-file IO object" do - io = StringIO.new("riseofthemachines\nriseofthechefs\n") - expected_md5 = '0e157ac1e2dd73191b76067fb6b4bceb' - @cache.generate_md5_checksum(io).should == expected_md5 - end - - end - -end - diff --git a/spec/unit/dsl/data_query_spec.rb b/spec/unit/dsl/data_query_spec.rb deleted file mode 100644 index 78cd5569e8..0000000000 --- a/spec/unit/dsl/data_query_spec.rb +++ /dev/null @@ -1,106 +0,0 @@ -# -# Author:: Seth Falcon (<seth@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. -# - -require 'spec_helper' -require 'chef/dsl/data_query' - -class DataQueryDSLTester - include Chef::DSL::DataQuery -end - -describe Chef::DSL::DataQuery do - let(:node) { Hash.new } - - let(:language) do - language = DataQueryDSLTester.new - language.stub(:node).and_return(@node) - language - end - - 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) - 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) - 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) - 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) - end - end - - describe "::data_bag_item" do - let(:bag_name) { "bag_name" } - - let(:item_name) { "item_name" } - - let(:raw_data) {{ - "id" => item_name, - "greeting" => "hello", - "nested" => { - "a1" => [1, 2, 3], - "a2" => { "b1" => true } - } - }} - - let(:item) do - item = Chef::DataBagItem.new - item.data_bag(bag_name) - item.raw_data = raw_data - item - end - - it "fetches a data bag item" do - allow( Chef::DataBagItem ).to receive(:load).with(bag_name, item_name).and_return(item) - expect( language.data_bag_item(bag_name, item_name) ).to eql item - end - - include_examples "a data bag item" do - let(:method_name) { :data_bag_item } - end - - context "when the item is encrypted" do - let(:secret) { "abc123SECRET" } - let(:enc_data_bag) { double("Chef::EncryptedDataBagItem") } - - before do - allow( Chef::DataBagItem ).to receive(:load).with(bag_name, item_name).and_return(item) - expect(language).to receive(:encrypted?).and_return(true) - expect( Chef::EncryptedDataBagItem ).to receive(:load_secret).and_return(secret) - end - - it "detects encrypted data bag" do - expect( Chef::EncryptedDataBagItem ).to receive(:new).with(raw_data, secret).and_return(enc_data_bag) - expect( Chef::Log ).to receive(:debug).with(/Data bag item looks encrypted/) - expect(language.data_bag_item(bag_name, item_name)).to eq(enc_data_bag) - end - - end - end -end diff --git a/spec/unit/dsl/platform_introspection_spec.rb b/spec/unit/dsl/platform_introspection_spec.rb deleted file mode 100644 index f00d5a2ab8..0000000000 --- a/spec/unit/dsl/platform_introspection_spec.rb +++ /dev/null @@ -1,130 +0,0 @@ -# -# Author:: Seth Falcon (<seth@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. -# - -require 'spec_helper' -require 'chef/dsl/platform_introspection' - -class LanguageTester - attr_reader :node - def initialize(node) - @node = node - end - include Chef::DSL::PlatformIntrospection -end - -describe "PlatformIntrospection implementors" do - - let(:node) { Chef::Node.new } - let(:platform_introspector) { LanguageTester.new(node) } - - it_behaves_like "a platform introspector" - -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' - } - @platform_specific_value = Chef::DSL::PlatformIntrospection::PlatformDependentValue.new(platform_hash) - end - - it "returns the default value when the platform doesn't match" do - @platform_specific_value.value_for_node(:platform => :dos).should == 'bork da bork' - end - - it "returns a value for a platform set as a group" do - @platform_specific_value.value_for_node(:platform => :centos).should == '"stable"' - end - - it "returns a value for the platform when it was set as a symbol but fetched as a string" do - @platform_specific_value.value_for_node(:platform => "centos").should == '"stable"' - end - - it "returns a value for a specific platform version" do - node = {:platform => 'ubuntu', :platform_version => '10.04'} - @platform_specific_value.value_for_node(node).should == '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' } - @platform_specific_value.value_for_node(node).should == '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({}) - platform_specific_value.value_for_node(:platform => 'foo').should 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'} - lambda {Chef::DSL::PlatformIntrospection::PlatformDependentValue.new(bad_hash)}.should raise_error(ArgumentError) - end - -end -describe Chef::DSL::PlatformIntrospection::PlatformFamilyDependentValue do - before do - @array_values = [:stop, :start, :reload] - - @platform_family_hash = { - "debian" => "debian value", - [:rhel, "fedora"] => "redhatty value", - "suse" => @array_values, - :gentoo => "gentoo 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 - @platform_family_value.value_for_node(:platform_family => :os2).should == 'default value' - end - - - it "returns a value for the platform family when it was set as a string but fetched as a symbol" do - @platform_family_value.value_for_node(:platform_family => :debian).should == "debian value" - end - - it "returns a value for the platform family when it was set as a symbol but fetched as a string" do - @platform_family_value.value_for_node(:platform_family => "gentoo").should == "gentoo value" - end - - it "returns an array value stored for a platform family" do - @platform_family_value.value_for_node(:platform_family => "suse").should == @array_values - end - - it "returns a value for the platform family when it was set within an array hash key as a symbol" do - @platform_family_value.value_for_node(:platform_family => :rhel).should == "redhatty value" - end - - it "returns a value for the platform family when it was set within an array hash key as a string" do - @platform_family_value.value_for_node(:platform_family => "fedora").should == "redhatty value" - end - - it "returns nil if there is no default and no platforms match" do - platform_specific_value = Chef::DSL::PlatformIntrospection::PlatformFamilyDependentValue.new({}) - platform_specific_value.value_for_node(:platform_family => 'foo').should be_nil - end - -end diff --git a/spec/unit/dsl/reboot_pending_spec.rb b/spec/unit/dsl/reboot_pending_spec.rb deleted file mode 100644 index 0d643514e0..0000000000 --- a/spec/unit/dsl/reboot_pending_spec.rb +++ /dev/null @@ -1,94 +0,0 @@ -# -# Author:: Bryan McLellan <btm@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/dsl/reboot_pending" -require "spec_helper" - -describe Chef::DSL::RebootPending do - describe "reboot_pending?" do - describe "in isolation" do - let(:recipe) { Object.new.extend(Chef::DSL::RebootPending) } - - before do - recipe.stub(:platform?).and_return(false) - end - - context "platform is windows" do - before do - recipe.stub(:platform?).with('windows').and_return(true) - recipe.stub(:registry_key_exists?).and_return(false) - recipe.stub(:registry_value_exists?).and_return(false) - end - - it 'should return true if "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations" exists' do - recipe.stub(:registry_value_exists?).with('HKLM\SYSTEM\CurrentControlSet\Control\Session Manager', { :name => 'PendingFileRenameOperations' }).and_return(true) - expect(recipe.reboot_pending?).to be_true - end - - it 'should return true if "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired" exists' do - recipe.stub(:registry_key_exists?).with('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired').and_return(true) - expect(recipe.reboot_pending?).to be_true - end - - it 'should return true if key "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootRequired" exists' do - recipe.stub(:registry_key_exists?).with('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootRequired').and_return(true) - expect(recipe.reboot_pending?).to be_true - end - - it 'should return true if value "HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile" contains specific data' do - recipe.stub(:registry_key_exists?).with('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile').and_return(true) - recipe.stub(:registry_get_values).with('HKLM\SOFTWARE\Microsoft\Updates\UpdateExeVolatile').and_return( - [{:name => "Flags", :type => :dword, :data => 3}]) - expect(recipe.reboot_pending?).to be_true - end - end - - context "platform is ubuntu" do - before do - recipe.stub(:platform?).with('ubuntu').and_return(true) - end - - it 'should return true if /var/run/reboot-required exists' do - File.stub(:exists?).with('/var/run/reboot-required').and_return(true) - expect(recipe.reboot_pending?).to be_true - end - - it 'should return false if /var/run/reboot-required does not exist' do - File.stub(:exists?).with('/var/run/reboot-required').and_return(false) - expect(recipe.reboot_pending?).to be_false - end - end - - end # describe in isolation - - 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)) - expect(recipe).to respond_to(:reboot_pending?) - end - end # describe in a recipe - - describe "in a resource" do - it "responds to reboot_pending?" do - resource = Chef::Resource::new("Crackerjack::Timing", nil) - expect(resource).to respond_to(:reboot_pending?) - end - end # describe in a resource - end -end diff --git a/spec/unit/dsl/recipe_spec.rb b/spec/unit/dsl/recipe_spec.rb deleted file mode 100644 index dfaad0b73e..0000000000 --- a/spec/unit/dsl/recipe_spec.rb +++ /dev/null @@ -1,82 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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 'chef/dsl/recipe' - - -RecipeDSLExampleClass = Struct.new(:cookbook_name, :recipe_name) -class RecipeDSLExampleClass - include Chef::DSL::Recipe -end - -RecipeDSLBaseAPI = Struct.new(:cookbook_name, :recipe_name) -class RecipeDSLExampleSubclass < RecipeDSLBaseAPI - include Chef::DSL::Recipe -end - -# TODO: most of DSL::Recipe's implementation is tested in Chef::Recipe's tests, -# move those to here. -describe Chef::DSL::Recipe do - - let(:cookbook_name) { "example_cb" } - let(:recipe_name) { "example_recipe" } - - shared_examples_for "A Recipe DSL Implementation" do - - it "responds to cookbook_name" do - expect(recipe.cookbook_name).to eq(cookbook_name) - end - - it "responds to recipe_name" do - expect(recipe.recipe_name).to eq(recipe_name) - end - - it "responds to shell_out" do - expect(recipe.respond_to?(:shell_out)).to be true - end - - it "responds to shell_out" do - expect(recipe.respond_to?(:shell_out!)).to be true - end - - it "responds to shell_out" do - expect(recipe.respond_to?(:shell_out_with_systems_locale)).to be true - end - end - - context "when included in a class that defines the required interface directly" do - - let(:recipe) { RecipeDSLExampleClass.new(cookbook_name, recipe_name) } - - include_examples "A Recipe DSL Implementation" - - end - - # This is the situation that occurs when the Recipe DSL gets mixed in to a - # resource, for example. - context "when included in a class that defines the required interface in a superclass" do - - let(:recipe) { RecipeDSLExampleSubclass.new(cookbook_name, recipe_name) } - - include_examples "A Recipe DSL Implementation" - - end - -end - diff --git a/spec/unit/dsl/regsitry_helper_spec.rb b/spec/unit/dsl/regsitry_helper_spec.rb deleted file mode 100644 index 7fe08e310f..0000000000 --- a/spec/unit/dsl/regsitry_helper_spec.rb +++ /dev/null @@ -1,55 +0,0 @@ -# -# Author:: Prajakta Purohit (<prajakta@opscode.com>) -# Copyright:: Copyright (c) 2011 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/dsl/registry_helper" -require "spec_helper" - -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,{}) - 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 - @resource.respond_to?('registry_key_exists?').should == true - end - it "resource can access registry_helper method registry_get_values" do - @resource.respond_to?('registry_get_values').should == true - end - it "resource can access registry_helper method registry_has_subkey" do - @resource.respond_to?('registry_has_subkeys?').should == true - end - it "resource can access registry_helper method registry_get_subkeys" do - @resource.respond_to?('registry_get_subkeys').should == true - end - it "resource can access registry_helper method registry_value_exists" do - @resource.respond_to?('registry_value_exists?').should == true - end - it "resource can access registry_helper method data_value_exists" do - @resource.respond_to?('registry_data_exists?').should == true - end - 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 deleted file mode 100644 index 1da5efb36e..0000000000 --- a/spec/unit/encrypted_data_bag_item/check_encrypted_spec.rb +++ /dev/null @@ -1,95 +0,0 @@ -# -# Author:: Tyler Ball (<tball@getchef.com>) -# Copyright:: Copyright (c) 2010-2014 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/encrypted_data_bag_item/check_encrypted' - -class CheckEncryptedTester - include Chef::EncryptedDataBagItem::CheckEncrypted -end - -describe Chef::EncryptedDataBagItem::CheckEncrypted do - - let(:tester) { CheckEncryptedTester.new } - - it "detects the item is not encrypted when the data is empty" do - expect(tester.encrypted?({})).to eq(false) - end - - it "detects the item is not encrypted when the data only contains an id" do - expect(tester.encrypted?({id: "foo"})).to eq(false) - end - - context "when the item is encrypted" do - - let(:default_secret) { "abc123SECRET" } - let(:item_name) { "item_name" } - let(:raw_data) {{ - "id" => item_name, - "greeting" => "hello", - "nested" => { - "a1" => [1, 2, 3], - "a2" => { "b1" => true } - } - }} - - let(:version) { 1 } - let(:encoded_data) do - Chef::Config[:data_bag_encrypt_version] = version - Chef::EncryptedDataBagItem.encrypt_data_bag_item(raw_data, default_secret) - end - - it "does not detect encryption when the item version is unknown" do - # It shouldn't be possible for someone to normally encrypt an item with an unknown version - they would have to - # do something funky like encrypting it and then manually changing the version - modified_encoded_data = encoded_data - modified_encoded_data["greeting"]["version"] = 4 - expect(tester.encrypted?(modified_encoded_data)).to eq(false) - end - - shared_examples_for "encryption detected" do - it "detects encrypted data bag" do - expect( encryptor ).to receive(:encryptor_keys).at_least(:once).and_call_original - expect(tester.encrypted?(encoded_data)).to eq(true) - end - end - - context "when encryption version is 1" do - include_examples "encryption detected" do - let(:version) { 1 } - let(:encryptor) { Chef::EncryptedDataBagItem::Encryptor::Version1Encryptor } - end - end - - context "when encryption version is 2" do - include_examples "encryption detected" do - let(:version) { 2 } - let(:encryptor) { Chef::EncryptedDataBagItem::Encryptor::Version2Encryptor } - end - end - - context "when encryption version is 3", :ruby_20_only do - include_examples "encryption detected" do - let(:version) { 3 } - let(:encryptor) { Chef::EncryptedDataBagItem::Encryptor::Version3Encryptor } - end - end - - end - -end diff --git a/spec/unit/encrypted_data_bag_item_spec.rb b/spec/unit/encrypted_data_bag_item_spec.rb deleted file mode 100644 index 5ee245b9bc..0000000000 --- a/spec/unit/encrypted_data_bag_item_spec.rb +++ /dev/null @@ -1,468 +0,0 @@ -# -# Author:: Seth Falcon (<seth@opscode.com>) -# Copyright:: Copyright 2010-2011 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/encrypted_data_bag_item' - -module Version0Encryptor - def self.encrypt_value(plaintext_data, key) - data = plaintext_data.to_yaml - - cipher = OpenSSL::Cipher.new("aes-256-cbc") - cipher.encrypt - cipher.pkcs5_keyivgen(key) - encrypted_bytes = cipher.update(data) - encrypted_bytes << cipher.final - Base64.encode64(encrypted_bytes) - end -end - -describe Chef::EncryptedDataBagItem::Encryptor do - - subject(:encryptor) { described_class.new(plaintext_data, key) } - let(:plaintext_data) { {"foo" => "bar"} } - let(:key) { "passwd" } - - it "encrypts to format version 1 by default" do - encryptor.should be_a_instance_of(Chef::EncryptedDataBagItem::Encryptor::Version1Encryptor) - end - - describe "generating a random IV" do - it "generates a new IV for each encryption pass" do - encryptor2 = Chef::EncryptedDataBagItem::Encryptor.new(plaintext_data, key) - - # No API in ruby OpenSSL to get the iv is used for the encryption back - # out. Instead we test if the encrypted data is the same. If it *is* the - # same, we assume the IV was the same each time. - encryptor.encrypted_data.should_not eq encryptor2.encrypted_data - end - end - - describe "when encrypting a non-hash non-array value" do - let(:plaintext_data) { 5 } - it "serializes the value in a de-serializable way" do - Chef::JSONCompat.from_json(encryptor.serialized_data)["json_wrapper"].should eq 5 - end - - end - - describe "wrapping secret values in an envelope" do - it "wraps the encrypted data in an envelope with the iv and version" do - final_data = encryptor.for_encrypted_item - final_data["encrypted_data"].should eq encryptor.encrypted_data - final_data["iv"].should eq Base64.encode64(encryptor.iv) - final_data["version"].should eq 1 - final_data["cipher"].should eq"aes-256-cbc" - end - end - - describe "when using version 2 format" do - - before do - Chef::Config[:data_bag_encrypt_version] = 2 - end - - it "creates a version 2 encryptor" do - encryptor.should be_a_instance_of(Chef::EncryptedDataBagItem::Encryptor::Version2Encryptor) - end - - it "generates an hmac based on ciphertext with different iv" do - encryptor2 = Chef::EncryptedDataBagItem::Encryptor.new(plaintext_data, key) - encryptor.hmac.should_not eq(encryptor2.hmac) - end - - it "includes the hmac in the envelope" do - final_data = encryptor.for_encrypted_item - final_data["hmac"].should eq(encryptor.hmac) - end - end - - describe "when using version 3 format" do - before do - Chef::Config[:data_bag_encrypt_version] = 3 - end - - context "on supported platforms", :ruby_gte_20_and_openssl_gte_101 do - - it "creates a version 3 encryptor" do - encryptor.should be_a_instance_of(Chef::EncryptedDataBagItem::Encryptor::Version3Encryptor) - end - - it "generates different authentication tags" do - encryptor3 = Chef::EncryptedDataBagItem::Encryptor.new(plaintext_data, key) - encryptor.for_encrypted_item # required to generate the auth_tag - encryptor3.for_encrypted_item - encryptor.auth_tag.should_not eq(encryptor3.auth_tag) - end - - it "includes the auth_tag in the envelope" do - final_data = encryptor.for_encrypted_item - final_data["auth_tag"].should eq(Base64::encode64(encryptor.auth_tag)) - end - - it "throws an error if auth tag is read before encrypting the data" do - lambda { encryptor.auth_tag }.should raise_error(Chef::EncryptedDataBagItem::EncryptionFailure) - end - - end # context on supported platforms - - context "on unsupported platforms" do - let(:aead_algorithm) { Chef::EncryptedDataBagItem::AEAD_ALGORITHM } - - it "throws an error warning about the Ruby version if it has no GCM support" do - # Force OpenSSL with AEAD support - OpenSSL::Cipher.stub(:ciphers).and_return([ aead_algorithm ]) - # Ruby without AEAD support - OpenSSL::Cipher.should_receive(:method_defined?).with(:auth_data=).and_return(false) - lambda { encryptor }.should raise_error(Chef::EncryptedDataBagItem::EncryptedDataBagRequirementsFailure, /requires Ruby/) - end - - it "throws an error warning about the OpenSSL version if it has no GCM support" do - # Force Ruby with AEAD support - OpenSSL::Cipher.stub(:method_defined?).with(:auth_data=).and_return(true) - # OpenSSL without AEAD support - OpenSSL::Cipher.should_receive(:ciphers).and_return([]) - lambda { encryptor }.should raise_error(Chef::EncryptedDataBagItem::EncryptedDataBagRequirementsFailure, /requires an OpenSSL/) - end - - context "on platforms with old Ruby", :ruby_lt_20 do - - it "throws an error warning about the Ruby version" do - lambda { encryptor }.should raise_error(Chef::EncryptedDataBagItem::EncryptedDataBagRequirementsFailure, /requires Ruby/) - end - - end # context on platforms with old Ruby - - context "on platforms with old OpenSSL", :openssl_lt_101 do - - it "throws an error warning about the OpenSSL version" do - lambda { encryptor }.should raise_error(Chef::EncryptedDataBagItem::EncryptedDataBagRequirementsFailure, /requires an OpenSSL/) - end - - end # context on platforms with old OpenSSL - - end # context on unsupported platforms - - end # when using version 3 format - -end - -describe Chef::EncryptedDataBagItem::Decryptor do - - subject(:decryptor) { described_class.for(encrypted_value, decryption_key) } - let(:plaintext_data) { {"foo" => "bar"} } - let(:encryption_key) { "passwd" } - let(:decryption_key) { encryption_key } - - context "when decrypting a version 3 (JSON+aes-256-gcm+random iv+auth tag) encrypted value" do - - context "on supported platforms", :ruby_gte_20_and_openssl_gte_101 do - - let(:encrypted_value) do - Chef::EncryptedDataBagItem::Encryptor::Version3Encryptor.new(plaintext_data, encryption_key).for_encrypted_item - end - - let(:bogus_auth_tag) { "bogus_auth_tag" } - - it "decrypts the encrypted value" do - decryptor.decrypted_data.should eq({"json_wrapper" => plaintext_data}.to_json) - end - - it "unwraps the encrypted data and returns it" do - decryptor.for_decrypted_item.should eq plaintext_data - end - - it "rejects the data if the authentication tag is wrong" do - encrypted_value["auth_tag"] = bogus_auth_tag - lambda { decryptor.for_decrypted_item }.should raise_error(Chef::EncryptedDataBagItem::DecryptionFailure) - end - - it "rejects the data if the authentication tag is missing" do - encrypted_value.delete("auth_tag") - lambda { decryptor.for_decrypted_item }.should raise_error(Chef::EncryptedDataBagItem::DecryptionFailure) - end - - end # context on supported platforms - - context "on unsupported platforms" do - let(:encrypted_value) do - { - "encrypted_data" => "", - "iv" => "", - "version" => 3, - "cipher" => "aes-256-cbc", - } - end - - context "on platforms with old Ruby", :ruby_lt_20 do - - it "throws an error warning about the Ruby version" do - lambda { decryptor }.should raise_error(Chef::EncryptedDataBagItem::EncryptedDataBagRequirementsFailure, /requires Ruby/) - end - - end # context on platforms with old Ruby - - context "on platforms with old OpenSSL", :openssl_lt_101 do - - it "throws an error warning about the OpenSSL version" do - lambda { decryptor }.should raise_error(Chef::EncryptedDataBagItem::EncryptedDataBagRequirementsFailure, /requires an OpenSSL/) - end - - end # context on unsupported platforms - - end # context on platforms with old OpenSSL - - end # context when decrypting a version 3 - - context "when decrypting a version 2 (JSON+aes-256-cbc+hmac-sha256+random iv) encrypted value" do - let(:encrypted_value) do - Chef::EncryptedDataBagItem::Encryptor::Version2Encryptor.new(plaintext_data, encryption_key).for_encrypted_item - end - - let(:bogus_hmac) do - digest = OpenSSL::Digest.new("sha256") - raw_hmac = OpenSSL::HMAC.digest(digest, "WRONG", encrypted_value["encrypted_data"]) - Base64.encode64(raw_hmac) - end - - it "decrypts the encrypted value" do - decryptor.decrypted_data.should eq({"json_wrapper" => plaintext_data}.to_json) - end - - it "unwraps the encrypted data and returns it" do - decryptor.for_decrypted_item.should eq plaintext_data - end - - it "rejects the data if the hmac is wrong" do - encrypted_value["hmac"] = bogus_hmac - lambda { decryptor.for_decrypted_item }.should raise_error(Chef::EncryptedDataBagItem::DecryptionFailure) - end - - it "rejects the data if the hmac is missing" do - encrypted_value.delete("hmac") - lambda { decryptor.for_decrypted_item }.should raise_error(Chef::EncryptedDataBagItem::DecryptionFailure) - end - - end - - context "when decrypting a version 1 (JSON+aes-256-cbc+random iv) encrypted value" do - - let(:encrypted_value) do - Chef::EncryptedDataBagItem::Encryptor.new(plaintext_data, encryption_key).for_encrypted_item - end - - it "selects the correct strategy for version 1" do - decryptor.should be_a_instance_of Chef::EncryptedDataBagItem::Decryptor::Version1Decryptor - end - - it "decrypts the encrypted value" do - decryptor.decrypted_data.should eq({"json_wrapper" => plaintext_data}.to_json) - end - - it "unwraps the encrypted data and returns it" do - decryptor.for_decrypted_item.should eq plaintext_data - end - - describe "and the decryption step returns invalid data" do - it "raises a decryption failure error" do - # Over a large number of tests on a variety of systems, we occasionally - # see the decryption step "succeed" but return invalid data (e.g., not - # the original plain text) [CHEF-3858] - decryptor.should_receive(:decrypted_data).and_return("lksajdf") - lambda { decryptor.for_decrypted_item }.should raise_error(Chef::EncryptedDataBagItem::DecryptionFailure) - end - end - - context "and the provided key is incorrect" do - let(:decryption_key) { "wrong-passwd" } - - it "raises a sensible error" do - lambda { decryptor.for_decrypted_item }.should raise_error(Chef::EncryptedDataBagItem::DecryptionFailure) - end - end - - context "and the cipher is not supported" do - let(:encrypted_value) do - ev = Chef::EncryptedDataBagItem::Encryptor.new(plaintext_data, encryption_key).for_encrypted_item - ev["cipher"] = "aes-256-foo" - ev - end - - it "raises a sensible error" do - lambda { decryptor.for_decrypted_item }.should raise_error(Chef::EncryptedDataBagItem::UnsupportedCipher) - end - end - - context "and version 2 format is required" do - before do - Chef::Config[:data_bag_decrypt_minimum_version] = 2 - end - - it "raises an error attempting to decrypt" do - lambda { decryptor }.should raise_error(Chef::EncryptedDataBagItem::UnacceptableEncryptedDataBagItemFormat) - end - - end - - end - - context "when decrypting a version 0 (YAML+aes-256-cbc+no iv) encrypted value" do - let(:encrypted_value) do - Version0Encryptor.encrypt_value(plaintext_data, encryption_key) - end - - it "selects the correct strategy for version 0" do - decryptor.should be_a_instance_of(Chef::EncryptedDataBagItem::Decryptor::Version0Decryptor) - end - - it "decrypts the encrypted value" do - decryptor.for_decrypted_item.should eq plaintext_data - end - - context "and version 1 format is required" do - before do - Chef::Config[:data_bag_decrypt_minimum_version] = 1 - end - - it "raises an error attempting to decrypt" do - lambda { decryptor }.should raise_error(Chef::EncryptedDataBagItem::UnacceptableEncryptedDataBagItemFormat) - end - - end - - end -end - -describe Chef::EncryptedDataBagItem do - subject { described_class } - let(:encrypted_data_bag_item) { subject.new(encoded_data, secret) } - let(:plaintext_data) {{ - "id" => "item_name", - "greeting" => "hello", - "nested" => { "a1" => [1, 2, 3], "a2" => { "b1" => true }} - }} - let(:secret) { "abc123SECRET" } - let(:encoded_data) { subject.encrypt_data_bag_item(plaintext_data, secret) } - - describe "encrypting" do - - it "doesn't encrypt the 'id' key" do - encoded_data["id"].should eq "item_name" - end - - it "encrypts non-collection objects" do - encoded_data["greeting"]["version"].should eq 1 - encoded_data["greeting"].should have_key("iv") - - iv = encoded_data["greeting"]["iv"] - encryptor = Chef::EncryptedDataBagItem::Encryptor.new("hello", secret, iv) - - encoded_data["greeting"]["encrypted_data"].should eq(encryptor.for_encrypted_item["encrypted_data"]) - end - - it "encrypts nested values" do - encoded_data["nested"]["version"].should eq 1 - encoded_data["nested"].should have_key("iv") - - iv = encoded_data["nested"]["iv"] - encryptor = Chef::EncryptedDataBagItem::Encryptor.new(plaintext_data["nested"], secret, iv) - - encoded_data["nested"]["encrypted_data"].should eq(encryptor.for_encrypted_item["encrypted_data"]) - end - - end - - describe "decrypting" do - - it "doesn't try to decrypt 'id'" do - encrypted_data_bag_item["id"].should eq(plaintext_data["id"]) - end - - it "decrypts 'greeting'" do - encrypted_data_bag_item["greeting"].should eq(plaintext_data["greeting"]) - end - - it "decrypts 'nested'" do - encrypted_data_bag_item["nested"].should eq(plaintext_data["nested"]) - end - - it "decrypts everyting via to_hash" do - encrypted_data_bag_item.to_hash.should eq(plaintext_data) - end - - it "handles missing keys gracefully" do - encrypted_data_bag_item["no-such-key"].should be_nil - end - end - - describe "loading" do - it "should defer to Chef::DataBagItem.load" do - Chef::DataBagItem.stub(:load).with(:the_bag, "my_codes").and_return(encoded_data) - edbi = Chef::EncryptedDataBagItem.load(:the_bag, "my_codes", secret) - edbi["greeting"].should eq(plaintext_data["greeting"]) - end - end - - describe ".load_secret" do - let(:secret) { "opensesame" } - - context "when /var/mysecret exists" do - before do - ::File.stub(:exist?).with("/var/mysecret").and_return(true) - IO.stub(:read).with("/var/mysecret").and_return(secret) - end - - it "load_secret('/var/mysecret') reads the secret" do - Chef::EncryptedDataBagItem.load_secret("/var/mysecret").should eq secret - end - end - - context "when /etc/chef/encrypted_data_bag_secret exists" do - before do - path = Chef::Config.platform_specific_path("/etc/chef/encrypted_data_bag_secret") - ::File.stub(:exist?).with(path).and_return(true) - IO.stub(:read).with(path).and_return(secret) - end - - it "load_secret(nil) reads the secret" do - Chef::EncryptedDataBagItem.load_secret(nil).should eq secret - end - end - - context "when /etc/chef/encrypted_data_bag_secret does not exist" do - before do - path = Chef::Config.platform_specific_path("/etc/chef/encrypted_data_bag_secret") - ::File.stub(:exist?).with(path).and_return(false) - end - - it "load_secret(nil) emits a reasonable error message" do - lambda { Chef::EncryptedDataBagItem.load_secret(nil) }.should raise_error(ArgumentError, /No secret specified and no secret found at #{Chef::Config[:encrypted_data_bag_secret]}/) - end - end - - context "path argument is a URL" do - before do - Kernel.stub(:open).with("http://www.opscode.com/").and_return(StringIO.new(secret)) - end - - it "reads from the URL" do - Chef::EncryptedDataBagItem.load_secret("http://www.opscode.com/").should eq secret - end - end - end -end diff --git a/spec/unit/environment_spec.rb b/spec/unit/environment_spec.rb deleted file mode 100644 index 5a2c400d3c..0000000000 --- a/spec/unit/environment_spec.rb +++ /dev/null @@ -1,466 +0,0 @@ -# -# Author:: Stephen Delano (<stephen@ospcode.com>) -# Author:: Seth Falcon (<seth@ospcode.com>) -# Author:: John Keiser (<jkeiser@ospcode.com>) -# Author:: Kyle Goodwin (<kgoodwin@primerevenue.com>) -# Copyright:: Copyright 2010-2011 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/environment' - -describe Chef::Environment do - before(:each) do - @environment = Chef::Environment.new - end - - describe "initialize" do - it "should be a Chef::Environment" do - @environment.should be_a_kind_of(Chef::Environment) - end - end - - describe "name" do - it "should let you set the name to a string" do - @environment.name("production").should == "production" - end - - it "should return the current name" do - @environment.name("production") - @environment.name.should == "production" - end - - it "should not accept spaces" do - lambda { @environment.name("production environment") }.should raise_error(ArgumentError) - end - - it "should not accept anything but strings" do - lambda { @environment.name(Array.new) }.should raise_error(ArgumentError) - lambda { @environment.name(Hash.new) }.should raise_error(ArgumentError) - lambda { @environment.name(2) }.should raise_error(ArgumentError) - end - end - - describe "description" do - it "should let you set the description to a string" do - @environment.description("this is my test environment").should == "this is my test environment" - end - - it "should return the correct description" do - @environment.description("I like running tests") - @environment.description.should == "I like running tests" - end - - it "should not accept anything but strings" do - lambda { @environment.description(Array.new) }.should raise_error(ArgumentError) - lambda { @environment.description(Hash.new) }.should raise_error(ArgumentError) - lambda { @environment.description(42) }.should raise_error(ArgumentError) - end - end - - describe "default attributes" do - it "should let you set the attributes hash explicitly" do - @environment.default_attributes({ :one => 'two' }).should == { :one => 'two' } - end - - it "should let you return the attributes hash" do - @environment.default_attributes({ :one => 'two' }) - @environment.default_attributes.should == { :one => 'two' } - end - - it "should throw an ArgumentError if we aren't a kind of hash" do - lambda { @environment.default_attributes(Array.new) }.should raise_error(ArgumentError) - end - end - - describe "override attributes" do - it "should let you set the attributes hash explicitly" do - @environment.override_attributes({ :one => 'two' }).should == { :one => 'two' } - end - - it "should let you return the attributes hash" do - @environment.override_attributes({ :one => 'two' }) - @environment.override_attributes.should == { :one => 'two' } - end - - it "should throw an ArgumentError if we aren't a kind of hash" do - lambda { @environment.override_attributes(Array.new) }.should raise_error(ArgumentError) - end - end - - describe "cookbook_versions" do - before(:each) do - @cookbook_versions = { - "apt" => "= 1.0.0", - "god" => "= 2.0.0", - "apache2" => "= 4.2.0" - } - end - - it "should let you set the cookbook versions in a hash" do - @environment.cookbook_versions(@cookbook_versions).should == @cookbook_versions - end - - it "should return the cookbook versions" do - @environment.cookbook_versions(@cookbook_versions) - @environment.cookbook_versions.should == @cookbook_versions - end - - it "should not accept anything but a hash" do - lambda { @environment.cookbook_versions("I am a string!") }.should raise_error(ArgumentError) - lambda { @environment.cookbook_versions(Array.new) }.should raise_error(ArgumentError) - lambda { @environment.cookbook_versions(42) }.should raise_error(ArgumentError) - end - - it "should validate the hash" do - Chef::Environment.should_receive(:validate_cookbook_versions).with(@cookbook_versions).and_return true - @environment.cookbook_versions(@cookbook_versions) - end - end - - describe "cookbook" do - it "should set the version of the cookbook in the cookbook_versions hash" do - @environment.cookbook("apt", "~> 1.2.3") - @environment.cookbook_versions["apt"].should == "~> 1.2.3" - end - - it "should validate the cookbook version it is passed" do - Chef::Environment.should_receive(:validate_cookbook_version).with(">= 1.2.3").and_return true - @environment.cookbook("apt", ">= 1.2.3") - end - end - - describe "update_from!" do - before(:each) do - @environment.name("prod") - @environment.description("this is prod") - @environment.cookbook_versions({ "apt" => "= 1.2.3" }) - - @example = Chef::Environment.new - @example.name("notevenprod") - @example.description("this is pre-prod") - @example.cookbook_versions({ "apt" => "= 2.3.4" }) - end - - it "should update everything but name" do - @environment.update_from!(@example) - @environment.name.should == "prod" - @environment.description.should == @example.description - @environment.cookbook_versions.should == @example.cookbook_versions - end - end - - describe "to_hash" do - before(:each) do - @environment.name("spec") - @environment.description("Where we run the spec tests") - @environment.cookbook_versions({:apt => "= 1.2.3"}) - @hash = @environment.to_hash - end - - %w{name description cookbook_versions}.each do |t| - it "should include '#{t}'" do - @hash[t].should == @environment.send(t.to_sym) - end - end - - it "should include 'json_class'" do - @hash["json_class"].should == "Chef::Environment" - end - - it "should include 'chef_type'" do - @hash["chef_type"].should == "environment" - end - end - - describe "to_json" do - before(:each) do - @environment.name("spec") - @environment.description("Where we run the spec tests") - @environment.cookbook_versions({:apt => "= 1.2.3"}) - @json = @environment.to_json - end - - %w{name description cookbook_versions}.each do |t| - it "should include '#{t}'" do - @json.should =~ /"#{t}":#{Regexp.escape(@environment.send(t.to_sym).to_json)}/ - end - end - - it "should include 'json_class'" do - @json.should =~ /"json_class":"Chef::Environment"/ - end - - it "should include 'chef_type'" do - @json.should =~ /"chef_type":"environment"/ - end - end - - describe "from_json" do - before(:each) do - @data = { - "name" => "production", - "description" => "We are productive", - "cookbook_versions" => { - "apt" => "= 1.2.3", - "god" => ">= 4.2.0", - "apache2" => "= 2.0.0" - }, - "json_class" => "Chef::Environment", - "chef_type" => "environment" - } - @environment = Chef::JSONCompat.from_json(@data.to_json) - end - - it "should return a Chef::Environment" do - @environment.should be_a_kind_of(Chef::Environment) - end - - %w{name description cookbook_versions}.each do |t| - it "should match '#{t}'" do - @environment.send(t.to_sym).should == @data[t] - end - end - end - - describe "self.validate_cookbook_versions" do - before(:each) do - @cookbook_versions = { - "apt" => "= 1.0.0", - "god" => "= 2.0.0", - "apache2" => "= 4.2.0" - } - end - - it "should validate the version string of each cookbook" do - @cookbook_versions.each do |cookbook, version| - Chef::Environment.should_receive(:validate_cookbook_version).with(version).and_return true - end - Chef::Environment.validate_cookbook_versions(@cookbook_versions) - end - - it "should return false if anything other than a hash is passed as the argument" do - Chef::Environment.validate_cookbook_versions(Array.new).should == false - Chef::Environment.validate_cookbook_versions(42).should == false - Chef::Environment.validate_cookbook_versions(Chef::CookbookVersion.new("meta")).should == false - Chef::Environment.validate_cookbook_versions("cookbook => 1.2.3").should == false - end - end - - describe "self.validate_cookbook_version" do - it "should validate correct version numbers" do - Chef::Environment.validate_cookbook_version("= 1.2.3").should == true - Chef::Environment.validate_cookbook_version("=1.2.3").should == true - Chef::Environment.validate_cookbook_version(">= 0.0.3").should == true - Chef::Environment.validate_cookbook_version(">=0.0.3").should == true - # A lone version is allowed, interpreted as implicit '=' - Chef::Environment.validate_cookbook_version("1.2.3").should == true - end - - it "should return false when an invalid version is given" do - Chef::Environment.validate_cookbook_version(Chef::CookbookVersion.new("meta")).should == false - Chef::Environment.validate_cookbook_version("= 1.2.3a").should == false - Chef::Environment.validate_cookbook_version("=1.2.3a").should == false - Chef::Environment.validate_cookbook_version("= 1").should == false - Chef::Environment.validate_cookbook_version("=1").should == false - Chef::Environment.validate_cookbook_version("= a").should == false - Chef::Environment.validate_cookbook_version("=a").should == false - Chef::Environment.validate_cookbook_version("= 1.2.3.4").should == false - Chef::Environment.validate_cookbook_version("=1.2.3.4").should == false - end - - describe "in solo mode" do - before do - Chef::Config[:solo] = true - end - - after do - Chef::Config[:solo] = false - end - - it "should raise and exception" do - lambda { - Chef::Environment.validate_cookbook_version("= 1.2.3.4") - }.should raise_error Chef::Exceptions::IllegalVersionConstraint, - "Environment cookbook version constraints not allowed in chef-solo" - end - end - - end - - describe "when updating from a parameter hash" do - before do - @environment = Chef::Environment.new - end - - it "updates the name from parameters[:name]" do - @environment.update_from_params(:name => "kurrupt") - @environment.name.should == "kurrupt" - end - - it "validates the name given in the params" do - @environment.update_from_params(:name => "@$%^&*()").should be_false - @environment.invalid_fields[:name].should == %q|Option name's value @$%^&*() does not match regular expression /^[\-[:alnum:]_]+$/| - end - - it "updates the description from parameters[:description]" do - @environment.update_from_params(:description => "wow, writing your own object mapper is kinda painful") - @environment.description.should == "wow, writing your own object mapper is kinda painful" - end - - it "updates cookbook version constraints from the hash in parameters[:cookbook_version_constraints]" 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"}} - @environment.update_from_params(params) - @environment.cookbook_versions.should == {"apache2" => "~> 1.0.0", "nginx" => "< 2.0.0"} - end - - it "validates the cookbook constraints" do - params = {:cookbook_version => {"0" => "apache2 >>> 1.0.0"}} - @environment.update_from_params(params).should be_false - err_msg = @environment.invalid_fields[:cookbook_version]["0"] - err_msg.should == "apache2 >>> 1.0.0 is not a valid cookbook constraint" - end - - it "is not valid if the name is not present" do - @environment.validate_required_attrs_present.should be_false - @environment.invalid_fields[:name].should == "name cannot be empty" - end - - it "is not valid after updating from params if the name is not present" do - @environment.update_from_params({}).should be_false - @environment.invalid_fields[:name].should == "name cannot be empty" - end - - it "updates default attributes from a JSON string in params[:attributes]" do - @environment.update_from_params(:name => "fuuu", :default_attributes => %q|{"fuuu":"RAGE"}|) - @environment.default_attributes.should == {"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"}|) - @environment.override_attributes.should == {"foo" => "override"} - end - - end - - describe "api model" do - before(:each) do - @rest = double("Chef::REST") - Chef::REST.stub(:new).and_return(@rest) - @query = double("Chef::Search::Query") - Chef::Search::Query.stub(:new).and_return(@query) - end - - describe "list" do - describe "inflated" do - it "should return a hash of environment names and objects" do - e1 = double("Chef::Environment", :name => "one") - @query.should_receive(:search).with(:environment).and_yield(e1) - r = Chef::Environment.list(true) - r["one"].should == e1 - end - end - - it "should return a hash of environment names and urls" do - @rest.should_receive(:get_rest).and_return({ "one" => "http://foo" }) - r = Chef::Environment.list - r["one"].should == "http://foo" - end - end - end - - describe "when loading" do - describe "in solo mode" do - before do - Chef::Config[:solo] = true - Chef::Config[:environment_path] = '/var/chef/environments' - end - - after do - Chef::Config[:solo] = false - end - - it "should get the environment from the environment_path" do - File.should_receive(:directory?).with(Chef::Config[:environment_path]).and_return(true) - File.should_receive(:exists?).with(File.join(Chef::Config[:environment_path], 'foo.json')).and_return(false) - File.should_receive(:exists?).with(File.join(Chef::Config[:environment_path], 'foo.rb')).exactly(2).times.and_return(true) - File.should_receive(:readable?).with(File.join(Chef::Config[:environment_path], 'foo.rb')).and_return(true) - role_dsl="name \"foo\"\ndescription \"desc\"\n" - IO.should_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 - File.should_receive(:directory?).with(Chef::Config[:environment_path]).and_return(true) - File.should_receive(:exists?).with(File.join(Chef::Config[:environment_path], 'foo.json')).and_return(true) - environment_hash = { - "name" => "foo", - "default_attributes" => { - "foo" => { - "bar" => 1 - } - }, - "json_class" => "Chef::Environment", - "description" => "desc", - "chef_type" => "environment" - } - IO.should_receive(:read).with(File.join(Chef::Config[:environment_path], 'foo.json')).and_return(Chef::JSONCompat.to_json(environment_hash)) - environment = Chef::Environment.load('foo') - - environment.should be_a_kind_of(Chef::Environment) - environment.name.should == environment_hash['name'] - environment.description.should == environment_hash['description'] - environment.default_attributes.should == environment_hash['default_attributes'] - end - - it "should return a Chef::Environment object from Ruby DSL" do - File.should_receive(:directory?).with(Chef::Config[:environment_path]).and_return(true) - File.should_receive(:exists?).with(File.join(Chef::Config[:environment_path], 'foo.json')).and_return(false) - File.should_receive(:exists?).with(File.join(Chef::Config[:environment_path], 'foo.rb')).exactly(2).times.and_return(true) - File.should_receive(:readable?).with(File.join(Chef::Config[:environment_path], 'foo.rb')).and_return(true) - role_dsl="name \"foo\"\ndescription \"desc\"\n" - IO.should_receive(:read).with(File.join(Chef::Config[:environment_path], 'foo.rb')).and_return(role_dsl) - environment = Chef::Environment.load('foo') - - environment.should be_a_kind_of(Chef::Environment) - environment.name.should == 'foo' - environment.description.should == 'desc' - end - - it 'should raise an error if the configured environment_path is invalid' do - File.should_receive(:directory?).with(Chef::Config[:environment_path]).and_return(false) - - lambda { - Chef::Environment.load('foo') - }.should 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 - File.should_receive(:directory?).with(Chef::Config[:environment_path]).and_return(true) - File.should_receive(:exists?).with(File.join(Chef::Config[:environment_path], 'foo.json')).and_return(false) - File.should_receive(:exists?).with(File.join(Chef::Config[:environment_path], 'foo.rb')).and_return(false) - - lambda { - Chef::Environment.load('foo') - }.should raise_error Chef::Exceptions::EnvironmentNotFound, "Environment 'foo' could not be loaded from disk" - end - end - end - -end diff --git a/spec/unit/exceptions_spec.rb b/spec/unit/exceptions_spec.rb deleted file mode 100644 index 3e7b1ba93f..0000000000 --- a/spec/unit/exceptions_spec.rb +++ /dev/null @@ -1,78 +0,0 @@ -# -# Author:: Thomas Bishop (<bishop.thomas@gmail.com>) -# Author:: Christopher Walters (<cw@opscode.com>) -# Author:: Kyle Goodwin (<kgoodwin@primerevenue.com>) -# Copyright:: Copyright (c) 2010 Thomas Bishop -# 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. -# - -require 'spec_helper' - -describe Chef::Exceptions do - exception_to_super_class = { - Chef::Exceptions::Application => RuntimeError, - Chef::Exceptions::Cron => RuntimeError, - Chef::Exceptions::Env => RuntimeError, - Chef::Exceptions::Exec => RuntimeError, - Chef::Exceptions::FileNotFound => RuntimeError, - Chef::Exceptions::Package => RuntimeError, - Chef::Exceptions::Service => RuntimeError, - Chef::Exceptions::Route => RuntimeError, - Chef::Exceptions::SearchIndex => RuntimeError, - Chef::Exceptions::Override => RuntimeError, - Chef::Exceptions::UnsupportedAction => RuntimeError, - Chef::Exceptions::MissingLibrary => RuntimeError, - Chef::Exceptions::MissingRole => RuntimeError, - Chef::Exceptions::CannotDetermineNodeName => RuntimeError, - Chef::Exceptions::User => RuntimeError, - Chef::Exceptions::Group => RuntimeError, - Chef::Exceptions::Link => RuntimeError, - Chef::Exceptions::Mount => RuntimeError, - Chef::Exceptions::PrivateKeyMissing => RuntimeError, - Chef::Exceptions::CannotWritePrivateKey => RuntimeError, - Chef::Exceptions::RoleNotFound => RuntimeError, - Chef::Exceptions::ValidationFailed => ArgumentError, - Chef::Exceptions::InvalidPrivateKey => ArgumentError, - Chef::Exceptions::ConfigurationError => ArgumentError, - Chef::Exceptions::RedirectLimitExceeded => RuntimeError, - Chef::Exceptions::AmbiguousRunlistSpecification => ArgumentError, - Chef::Exceptions::CookbookNotFound => RuntimeError, - Chef::Exceptions::AttributeNotFound => RuntimeError, - Chef::Exceptions::InvalidCommandOption => RuntimeError, - Chef::Exceptions::CommandTimeout => RuntimeError, - Mixlib::ShellOut::ShellCommandFailed => RuntimeError, - Chef::Exceptions::RequestedUIDUnavailable => RuntimeError, - Chef::Exceptions::InvalidHomeDirectory => ArgumentError, - Chef::Exceptions::DsclCommandFailed => RuntimeError, - Chef::Exceptions::UserIDNotFound => ArgumentError, - Chef::Exceptions::GroupIDNotFound => ArgumentError, - Chef::Exceptions::InvalidResourceReference => RuntimeError, - Chef::Exceptions::ResourceNotFound => RuntimeError, - Chef::Exceptions::InvalidResourceSpecification => ArgumentError, - Chef::Exceptions::SolrConnectionError => RuntimeError, - Chef::Exceptions::InvalidDataBagPath => ArgumentError, - Chef::Exceptions::InvalidEnvironmentPath => ArgumentError, - Chef::Exceptions::EnvironmentNotFound => RuntimeError, - Chef::Exceptions::InvalidVersionConstraint => ArgumentError, - 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 - lambda{ raise exception }.should raise_error(expected_super_class) - end - end -end diff --git a/spec/unit/file_access_control_spec.rb b/spec/unit/file_access_control_spec.rb deleted file mode 100644 index 4e257c2a22..0000000000 --- a/spec/unit/file_access_control_spec.rb +++ /dev/null @@ -1,302 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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. -# - -require 'spec_helper' -require 'ostruct' - -describe Chef::FileAccessControl do - describe "Unix" do - before do - platform_mock :unix do - # we have to re-load the file so the proper - # 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') - - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - @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) - - @fac = Chef::FileAccessControl.new(@current_resource, @resource, @provider) - end - end - - it "has a resource" do - @fac.resource.should equal(@resource) - end - - it "has a file to manage" do - @fac.file.should == '/tmp/different_file.txt' - end - - it "is not modified yet" do - @fac.should_not be_modified - end - - it "determines the uid of the owner specified by the resource" do - Etc.should_receive(:getpwnam).with('toor').and_return(OpenStruct.new(:uid => 2342)) - @fac.target_uid.should == 2342 - end - - it "raises a Chef::Exceptions::UserIDNotFound error when Etc can't find the user's name" do - Etc.should_receive(:getpwnam).with('toor').and_raise(ArgumentError) - lambda { @fac.target_uid ; @provider_requirements.run(:create) }.should raise_error(Chef::Exceptions::UserIDNotFound, "cannot determine user id for 'toor', does the user exist on this system?") - end - - it "does not attempt to resolve the uid if the user is not specified" do - resource = Chef::Resource::File.new("a file") - fac = Chef::FileAccessControl.new(@current_resource, resource, @provider) - fac.target_uid.should be_nil - end - - it "does not want to update the owner if none is specified" do - resource = Chef::Resource::File.new("a file") - fac = Chef::FileAccessControl.new(@current_resource, resource, @provider) - fac.should_update_owner?.should be_false - end - - it "raises an ArgumentError if the resource's owner is set to something wack" do - @resource.instance_variable_set(:@owner, :diaf) - lambda { @fac.target_uid ; @provider_requirements.run(:create) }.should raise_error(ArgumentError) - end - - it "uses the resource's uid for the target uid when the resource's owner is specified by an integer" do - @resource.owner(2342) - @fac.target_uid.should == 2342 - end - - it "wraps uids to their negative complements to correctly handle negative uids" do - # More: Mac OS X (at least) has negative UIDs for 'nobody' and some other - # users. Ruby doesn't believe in negative UIDs so you get the diminished radix - # 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') - Etc.should_receive(:getpwnam).with('nobody').and_return(OpenStruct.new(:uid => (4294967294))) - @fac.target_uid.should == -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') - Etc.should_receive(:getpwnam).with('bigdude').and_return(OpenStruct.new(:uid => (4294967286))) - @fac.target_uid.should == 4294967286 - end - - it "wants to update the owner when the current owner is nil (creating a file)" do - @current_resource.owner(nil) - @resource.owner(2342) - @fac.should_update_owner?.should be_true - end - - it "wants to update the owner when the current owner doesn't match desired" do - @current_resource.owner(3224) - @resource.owner(2342) - @fac.should_update_owner?.should be_true - end - - it "includes updating ownership in its list of desired changes" do - resource = Chef::Resource::File.new("a file") - resource.owner(2342) - @current_resource.owner(100) - fac = Chef::FileAccessControl.new(@current_resource, resource, @provider) - fac.describe_changes.should == ["change owner from '100' to '2342'"] - end - - it "sets the file's owner as specified in the resource when the current owner is incorrect" do - @resource.owner(2342) - File.should_receive(:chown).with(2342, nil, '/tmp/different_file.txt') - @fac.set_owner - @fac.should be_modified - end - - it "doesn't set the file's owner if it already matches" do - @resource.owner(2342) - @current_resource.owner(2342) - File.should_not_receive(:chown) - @fac.set_owner - @fac.should_not be_modified - end - - it "doesn't want to update a file's owner when it's already correct" do - @resource.owner(2342) - @current_resource.owner(2342) - @fac.should_update_owner?.should be_false - end - - it "determines the gid of the group specified by the resource" do - Etc.should_receive(:getgrnam).with('wheel').and_return(OpenStruct.new(:gid => 2342)) - @fac.target_gid.should == 2342 - end - - it "uses a user specified gid as the gid" do - @resource.group(2342) - @fac.target_gid.should == 2342 - end - - it "raises a Chef::Exceptions::GroupIDNotFound error when Etc can't find the user's name" do - Etc.should_receive(:getgrnam).with('wheel').and_raise(ArgumentError) - lambda { @fac.target_gid; @provider_requirements.run(:create) }.should 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') - fac = Chef::FileAccessControl.new(@current_resource, resource, @provider) - fac.target_gid.should be_nil - end - - it "does not want to update the group when no target group is specified" do - resource = Chef::Resource::File.new('crab') - fac = Chef::FileAccessControl.new(@current_resource, resource, @provider) - fac.should_update_group?.should be_false - end - - it "raises an error when the supplied group name is an alien" do - @resource.instance_variable_set(:@group, :failburger) - lambda { @fac.target_gid; @provider_requirements.run(:create) }.should raise_error(ArgumentError) - end - - it "wants to update the group when the current group is nil (creating a file)" do - @resource.group(2342) - @current_resource.group(nil) - @fac.should_update_group?.should be_true - end - - it "wants to update the group when the current group doesn't match the target group" do - @resource.group(2342) - @current_resource.group(815) - @fac.should_update_group?.should be_true - end - - it "includes updating the group in the list of changes" do - resource = Chef::Resource::File.new('crab') - resource.group(2342) - @current_resource.group(815) - fac = Chef::FileAccessControl.new(@current_resource, resource, @provider) - fac.describe_changes.should == ["change group from '815' to '2342'"] - end - - it "sets the file's group as specified in the resource when the group is not correct" do - @resource.group(2342) - @current_resource.group(815) - - File.should_receive(:chown).with(nil, 2342, '/tmp/different_file.txt') - @fac.set_group - @fac.should be_modified - end - - it "doesn't want to modify the file's group when the current group is correct" do - @resource.group(2342) - @current_resource.group(2342) - @fac.should_update_group?.should be_false - end - - it "doesnt set the file's group if it is already correct" do - @resource.group(2342) - @current_resource.group(2342) - - # @fac.stub(:stat).and_return(OpenStruct.new(:gid => 2342)) - File.should_not_receive(:chown) - @fac.set_group - @fac.should_not be_modified - end - - it "uses the supplied mode as octal when it's a string" do - @resource.mode('444') - @fac.target_mode.should == 292 # octal 444 => decimal 292 - end - - it "uses the supplied mode verbatim when it's an integer" do - @resource.mode(00444) - @fac.target_mode.should == 292 - end - - it "does not try to determine the mode when none is given" do - resource = Chef::Resource::File.new('blahblah') - fac = Chef::FileAccessControl.new(@current_resource, resource, @provider) - fac.target_mode.should be_nil - end - - it "doesn't want to update the mode when no target mode is given" do - resource = Chef::Resource::File.new('blahblah') - fac = Chef::FileAccessControl.new(@current_resource, resource, @provider) - fac.should_update_mode?.should be_false - end - - it "wants to update the mode when the current mode is nil (creating a file)" do - @resource.mode("0400") - @current_resource.mode(nil) - @fac.should_update_mode?.should be_true - end - - it "wants to update the mode when the desired mode does not match the current mode" do - @resource.mode("0400") - @current_resource.mode("0644") - @fac.should_update_mode?.should be_true - end - - it "includes changing the mode in the list of desired changes" do - resource = Chef::Resource::File.new('blahblah') - resource.mode("0750") - @current_resource.mode("0444") - fac = Chef::FileAccessControl.new(@current_resource, resource, @provider) - fac.describe_changes.should == ["change mode from '0444' to '0750'"] - end - - it "sets the file's mode as specified in the resource when the current modes are incorrect" do - # stat returns modes like 0100644 (octal) => 33188 (decimal) - #@fac.stub(:stat).and_return(OpenStruct.new(:mode => 33188)) - @current_resource.mode("0644") - File.should_receive(:chmod).with(256, '/tmp/different_file.txt') - @fac.set_mode - @fac.should be_modified - end - - it "does not want to update the mode when the current mode is correct" do - @current_resource.mode("0400") - @fac.should_update_mode?.should be_false - end - - it "does not set the file's mode when the current modes are correct" do - #@fac.stub(:stat).and_return(OpenStruct.new(:mode => 0100400)) - @current_resource.mode("0400") - File.should_not_receive(:chmod) - @fac.set_mode - @fac.should_not be_modified - end - - it "sets all access controls on a file" do - @fac.stub(:stat).and_return(OpenStruct.new(:owner => 99, :group => 99, :mode => 0100444)) - @resource.mode(0400) - @resource.owner(0) - @resource.group(0) - File.should_receive(:chmod).with(0400, '/tmp/different_file.txt') - File.should_receive(:chown).with(0, nil, '/tmp/different_file.txt') - File.should_receive(:chown).with(nil, 0, '/tmp/different_file.txt') - @fac.set_all - @fac.should be_modified - end - end -end diff --git a/spec/unit/file_cache_spec.rb b/spec/unit/file_cache_spec.rb deleted file mode 100644 index f57f11dcc2..0000000000 --- a/spec/unit/file_cache_spec.rb +++ /dev/null @@ -1,114 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef::FileCache do - before do - @file_cache_path = Dir.mktmpdir - Chef::Config[:file_cache_path] = @file_cache_path - @io = StringIO.new - end - - after do - FileUtils.rm_rf(Chef::Config[:file_cache_path]) - end - - 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") - File.should exist(File.join(@file_cache_path, 'whiz')) - end - - it "creates the cached file at the correct relative path" do - File.should_receive(:open).with(File.join(@file_cache_path, 'whiz', 'bang'), "w",416).and_yield(@io) - Chef::FileCache.store("whiz/bang", "borkborkbork") - end - - end - - describe "when storing a file" do - before do - File.stub(:open).and_yield(@io) - end - - it "should print the contents to the file" do - Chef::FileCache.store("whiz/bang", "borkborkbork") - @io.string.should == "borkborkbork" - end - - end - - 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") } - Chef::FileCache.load('whiz/bang').should == 'borkborkbork' - end - - it "should raise a Chef::Exceptions::FileNotFound if the file doesn't exist" do - lambda { Chef::FileCache.load('whiz/bang') }.should 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") } - end - - it "unlinks the file" do - Chef::FileCache.delete("whiz/bang") - File.should_not 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')) - end - - it "should return the relative paths" do - Chef::FileCache.list.sort.should == %w{snappy/patter whiz/bang} - end - - it "searches for cached files by globbing" do - Chef::FileCache.find('snappy/**/*').should == %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')) - end - - it "has a key if the corresponding cache file exists" do - FileUtils.touch(File.join(@file_cache_path, 'whiz', 'bang')) - Chef::FileCache.should have_key("whiz/bang") - end - - it "doesn't have a key if the corresponding cache file doesn't exist" do - Chef::FileCache.should_not have_key("whiz/bang") - end - end -end diff --git a/spec/unit/file_content_management/deploy/cp_spec.rb b/spec/unit/file_content_management/deploy/cp_spec.rb deleted file mode 100644 index dacf39295c..0000000000 --- a/spec/unit/file_content_management/deploy/cp_spec.rb +++ /dev/null @@ -1,46 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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::FileContentManagement::Deploy::Cp do - - let(:content_deployer) { described_class.new } - let(:target_file_path) { "/etc/my_app.conf" } - - describe "creating the file" do - - it "touches the file to create it" do - FileUtils.should_receive(:touch).with(target_file_path) - content_deployer.create(target_file_path) - end - end - - describe "updating the file" do - - let(:staging_file_path) { "/tmp/random-dir/staging-file.tmp" } - - it "copies the staging file's content" do - FileUtils.should_receive(:cp).with(staging_file_path, target_file_path) - content_deployer.deploy(staging_file_path, target_file_path) - end - - 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 deleted file mode 100644 index 0e8662b8ec..0000000000 --- a/spec/unit/file_content_management/deploy/mv_unix_spec.rb +++ /dev/null @@ -1,103 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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::FileContentManagement::Deploy::MvUnix do - - let(:content_deployer) { described_class.new } - let(:target_file_path) { "/etc/my_app.conf" } - - describe "creating the file" do - - it "touches the file to create it" do - FileUtils.should_receive(:touch).with(target_file_path) - content_deployer.create(target_file_path) - end - end - - describe "updating the file" do - - let(:staging_file_path) { "/tmp/random-dir/staging-file.tmp" } - - let(:target_file_mode) { 0644 } - let(:target_file_stat) do - double "File::Stat struct for target file", - :mode => target_file_mode, - :uid => target_file_uid, - :gid => target_file_gid - end - - before do - File.should_receive(:stat).with(target_file_path).and_return(target_file_stat) - File.should_receive(:chmod).with(target_file_mode, staging_file_path).and_return(1) - FileUtils.should_receive(:mv).with(staging_file_path, target_file_path) - end - - # This context represents the case where: - # * Chef runs as root - # * The owner and group of the target file match the owner and group of the - # staging file. - context "when the user has permissions to set file ownership" do - - # For the purposes of this test, the uid/gid can be anything. These - # values are just chosen because (assuming chef-client's euid == 1001 and - # egid == 1001), the `chown` call is allowed by the OS. See the - # description of `EPERM` in `man 2 chown` for reference. - let(:target_file_uid) { 1001 } - let(:target_file_gid) { 1001 } - - before do - File.should_receive(:chown).with(target_file_uid, nil, staging_file_path).and_return(1) - File.should_receive(:chown).with(nil, target_file_gid, staging_file_path).and_return(1) - end - - it "fixes up permissions and moves the file into place" do - content_deployer.deploy(staging_file_path, target_file_path) - end - - end - - context "when the user does not have permissions to set file ownership" do - - # The test code does not care what these values are. These values are - # chosen because they're representitive of the case that chef-client is - # running as non-root and is managing a file that got ownership set to - # root somehow. In this example, gid==20 is something like "staff" which - # the user running chef-client is a member of (but it's not that user's - # primary group). - let(:target_file_uid) { 0 } - let(:target_file_gid) { 20 } - - before do - File.should_receive(:chown).with(target_file_uid, nil, staging_file_path).and_raise(Errno::EPERM) - File.should_receive(:chown).with(nil, target_file_gid, staging_file_path).and_raise(Errno::EPERM) - - Chef::Log.should_receive(:warn).with(/^Could not set uid/) - Chef::Log.should_receive(:warn).with(/^Could not set gid/) - end - - it "fixes up permissions and moves the file into place" do - content_deployer.deploy(staging_file_path, target_file_path) - end - end - - 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 deleted file mode 100644 index 7c2a2d7e71..0000000000 --- a/spec/unit/file_content_management/deploy/mv_windows_spec.rb +++ /dev/null @@ -1,179 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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' - -unless Chef::Platform.windows? - class Chef - module ReservedNames - module Win32 - module Security - ACL = Object.new - SecurableObject = Object.new - end - end - end - end -end - -require 'chef/file_content_management/deploy/mv_windows' - -describe Chef::FileContentManagement::Deploy::MvWindows do - - let(:content_deployer) { described_class.new } - let(:target_file_path) { "/etc/my_app.conf" } - - describe "creating the file" do - - it "touches the file to create it" do - FileUtils.should_receive(:touch).with(target_file_path) - content_deployer.create(target_file_path) - end - end - - describe "updating the file" do - - let(:staging_file_path) { "/tmp/random-dir/staging-file.tmp" } - - let(:target_file_security_object) do - double "Securable Object for target file" - end - - let(:updated_target_security_object) do - double "Securable Object for target file after staging file deploy" - end - - before do - Chef::ReservedNames::Win32::Security::SecurableObject. - stub(:new). - with(target_file_path). - and_return(target_file_security_object, updated_target_security_object) - - end - - context "when run without adminstrator privileges" do - before do - target_file_security_object.should_receive(:security_descriptor).and_raise(Chef::Exceptions::Win32APIError) - end - - it "errors out with a WindowsNotAdmin error" do - lambda { content_deployer.deploy(staging_file_path, target_file_path)}.should raise_error(Chef::Exceptions::WindowsNotAdmin) - end - - end - - context "when run with administrator privileges" do - - let(:original_target_file_owner) { double("original target file owner") } - let(:original_target_file_group) { double("original target file group") } - - let(:target_file_security_descriptor) do - double "security descriptor for target file", - :group => original_target_file_group, - :owner => original_target_file_owner - end - - let(:updated_target_security_descriptor) do - double "security descriptor for target file" - end - - - before do - target_file_security_object.stub(:security_descriptor).and_return(target_file_security_descriptor) - - FileUtils.should_receive(:mv).with(staging_file_path, target_file_path) - - updated_target_security_object.should_receive(:group=).with(original_target_file_group) - updated_target_security_object.should_receive(:owner=).with(original_target_file_owner) - end - - context "and the target file has no dacl or sacl" do - - before do - target_file_security_descriptor.stub(:dacl_present?).and_return(false) - target_file_security_descriptor.stub(:sacl_present?).and_return(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) } - - let(:original_target_file_dacl) { [inherited_dacl_ace, not_inherited_dacl_ace] } - - let(:inherited_sacl_ace) { double("Windows sacl ace (inherited)", :inherited? => true) } - let(:not_inherited_sacl_ace) { double("Windows sacl ace (not inherited)", :inherited? => false) } - let(:original_target_file_sacl) { [inherited_sacl_ace, not_inherited_sacl_ace] } - - let(:custom_dacl) { double("Windows ACL for non-inherited dacl aces") } - let(:custom_sacl) { double("Windows ACL for non-inherited sacl aces") } - - before do - target_file_security_descriptor.stub(:dacl_present?).and_return(true) - target_file_security_descriptor.stub(:dacl_inherits?).and_return(dacl_inherits?) - - target_file_security_descriptor.stub(:dacl).and_return(original_target_file_dacl) - Chef::ReservedNames::Win32::Security::ACL. - should_receive(:create). - with([not_inherited_dacl_ace]). - and_return(custom_dacl) - - target_file_security_descriptor.stub(:sacl_present?).and_return(true) - target_file_security_descriptor.stub(:sacl_inherits?).and_return(sacl_inherits?) - - target_file_security_descriptor.stub(:sacl).and_return(original_target_file_sacl) - Chef::ReservedNames::Win32::Security::ACL. - should_receive(:create). - with([not_inherited_sacl_ace]). - and_return(custom_sacl) - - updated_target_security_object.should_receive(:set_dacl).with(custom_dacl, dacl_inherits?) - updated_target_security_object.should_receive(:set_sacl).with(custom_sacl, sacl_inherits?) - end - - context "and the dacl and sacl don't inherit" do - let(:dacl_inherits?) { false } - let(:sacl_inherits?) { false } - - 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 dacl and sacl inherit" do - let(:dacl_inherits?) { true } - let(:sacl_inherits?) { true } - - it "fixes up permissions and moves the file into place" do - content_deployer.deploy(staging_file_path, target_file_path) - end - end - - end - - end - - end -end - - diff --git a/spec/unit/formatters/base_spec.rb b/spec/unit/formatters/base_spec.rb deleted file mode 100644 index 6a843ea775..0000000000 --- a/spec/unit/formatters/base_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -# -# Author:: Lamont Granquist (<lamont@getchef.com>) -# -# Copyright:: Copyright (c) 2012 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) { double("out") } - let(:err) { double("err") } - let(:formatter) { Chef::Formatters::Base.new(out, err) } - - it "starts with an indentation of zero" do - expect(formatter.output.indent).to eql(0) - end - - it "increments it to two correctly" do - formatter.indent_by(2) - expect(formatter.output.indent).to eql(2) - end - - it "increments it and then decrements it corectly" do - formatter.indent_by(2) - formatter.indent_by(-2) - expect(formatter.output.indent).to eql(0) - end - - it "does not allow negative indentation" do - formatter.indent_by(-2) - expect(formatter.output.indent).to eql(0) - 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 deleted file mode 100644 index 95911689e4..0000000000 --- a/spec/unit/formatters/error_inspectors/compile_error_inspector_spec.rb +++ /dev/null @@ -1,202 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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' - -BAD_RECIPE=<<-E -# -# Cookbook Name:: syntax-err -# Recipe:: default -# -# Copyright 2012, YOUR_COMPANY_NAME -# -# All rights reserved - Do Not Redistribute -# - - -file "/tmp/explode-me" do - mode 0655 - owner "root" - this_is_not_a_valid_method -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 - - 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. - Chef::Config.stub(: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) - - @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'", - ] - @inspector.filtered_bt.should == @expected_filtered_trace - end - end - - describe "when explaining an error in the compile phase" do - before do - Chef::Config.stub(:cookbook_path).and_return([ "/var/chef/cache/cookbooks" ]) - recipe_lines = BAD_RECIPE.split("\n").map {|l| l << "\n" } - IO.should_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) - end - - it "finds the line number of the error from the stacktrace" do - @inspector.culprit_line.should == 14 - end - - it "prints a pretty message" do - @description.display(@outputter) - end - end - - describe "when explaining an error on windows" do - before do - Chef::Config.stub(:cookbook_path).and_return([ "C:/opscode/chef/var/cache/cookbooks" ]) - recipe_lines = BAD_RECIPE.split("\n").map {|l| l << "\n" } - IO.should_receive(:readlines).at_least(1).times.with(/:\/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 - - - describe "and examining the stack trace for a recipe" do - it "find the culprit recipe name when the drive letter is upper case" do - @inspector.culprit_file.should == "C:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb" - 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) - @inspector.culprit_file.should == "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 - @inspector.culprit_line.should == 14 - end - - it "prints a pretty message" do - @description.display(@outputter) - end - end - - describe "when explaining an error on windows, and the backtrace lowercases the drive letter" do - before do - Chef::Config.stub(:cookbook_path).and_return([ "C:/opscode/chef/var/cache/cookbooks" ]) - recipe_lines = BAD_RECIPE.split("\n").map {|l| l << "\n" } - IO.should_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 - - it "finds the culprit recipe name from the stacktrace" do - @inspector.culprit_file.should == "c:/opscode/chef/var/cache/cookbooks/foo/recipes/default.rb" - end - - it "finds the line number of the error from the stack trace" do - @inspector.culprit_line.should == 14 - end - - it "prints a pretty message" do - @description.display(@outputter) - 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 deleted file mode 100644 index 06d45472e4..0000000000 --- a/spec/unit/formatters/error_inspectors/cookbook_resolve_error_inspector_spec.rb +++ /dev/null @@ -1,129 +0,0 @@ -#-- -# Author:: Daniel DeLeo (<dan@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::Formatters::ErrorInspectors::CookbookResolveErrorInspector do - - before do - @expanded_run_list = Chef::RunList.new("recipe[annoyances]", "recipe[apache2]", "recipe[users]", "recipe[chef::client]") - - @description = Chef::Formatters::ErrorDescription.new("Error Resolving Cookbooks for Run List:") - @outputter_output = StringIO.new - @outputter = Chef::Formatters::IndentableOutputStream.new(@outputter_output, STDERR) - # @outputter = Chef::Formatters::IndentableOutputStream.new(STDOUT, STDERR) - end - - describe "when explaining a 403 error" do - before do - - @response_body = %Q({"error": [{"message": "gtfo"}]) - @response = Net::HTTPForbidden.new("1.1", "403", "(response) forbidden") - @response.stub(:body).and_return(@response_body) - @exception = Net::HTTPServerException.new("(exception) forbidden", @response) - - @inspector = Chef::Formatters::ErrorInspectors::CookbookResolveErrorInspector.new(@expanded_run_list, @exception) - @inspector.add_explanation(@description) - end - - it "prints a nice message" do - lambda { @description.display(@outputter) }.should_not raise_error - end - - end - - describe "when explaining a PreconditionFailed (412) error with current error message style" do - # Chef currently returns error messages with some fields as JSON strings, - # which must be re-parsed to get the actual data. - - before do - - @response_body = "{\"error\":[\"{\\\"non_existent_cookbooks\\\":[\\\"apache2\\\"],\\\"cookbooks_with_no_versions\\\":[\\\"users\\\"],\\\"message\\\":\\\"Run list contains invalid items: no such cookbook nope.\\\"}\"]}" - @response = Net::HTTPPreconditionFailed.new("1.1", "412", "(response) unauthorized") - @response.stub(:body).and_return(@response_body) - @exception = Net::HTTPServerException.new("(exception) precondition failed", @response) - - @inspector = Chef::Formatters::ErrorInspectors::CookbookResolveErrorInspector.new(@expanded_run_list, @exception) - @inspector.add_explanation(@description) - end - - it "prints a pretty message" do - @description.display(@outputter) - @outputter_output.rewind - observed_output = @outputter_output.read - observed_output.should include("apache2") - observed_output.should include("users") - observed_output.should_not include("Run list contains invalid items: no such cookbook nope.") - end - - end - - describe "when explaining a PreconditionFailed (412) error with current error message style without cookbook details" do - # Chef currently returns error messages with some fields as JSON strings, - # which must be re-parsed to get the actual data. - # In some cases the error message doesn't contain any cookbook - # details. But we should still print a pretty error message. - - before do - - @response_body = "{\"error\":[{\"non_existent_cookbooks\":[],\"cookbooks_with_no_versions\":[],\"message\":\"unable to solve dependencies in alotted time.\"}]}" - @response = Net::HTTPPreconditionFailed.new("1.1", "412", "(response) unauthorized") - @response.stub(:body).and_return(@response_body) - @exception = Net::HTTPServerException.new("(exception) precondition failed", @response) - - @inspector = Chef::Formatters::ErrorInspectors::CookbookResolveErrorInspector.new(@expanded_run_list, @exception) - @inspector.add_explanation(@description) - end - - it "prints a pretty message" do - @description.display(@outputter) - @outputter_output.rewind - @outputter_output.read.should include("unable to solve dependencies in alotted time.") - end - - end - - describe "when explaining a PreconditionFailed (412) error with single encoded JSON" do - # Chef currently returns error messages with some fields as JSON strings, - # which must be re-parsed to get the actual data. - - before do - - @response_body = "{\"error\":[{\"non_existent_cookbooks\":[\"apache2\"],\"cookbooks_with_no_versions\":[\"users\"],\"message\":\"Run list contains invalid items: no such cookbook nope.\"}]}" - @response = Net::HTTPPreconditionFailed.new("1.1", "412", "(response) unauthorized") - @response.stub(:body).and_return(@response_body) - @exception = Net::HTTPServerException.new("(exception) precondition failed", @response) - - @inspector = Chef::Formatters::ErrorInspectors::CookbookResolveErrorInspector.new(@expanded_run_list, @exception) - @inspector.add_explanation(@description) - end - - it "prints a pretty message" do - @description.display(@outputter) - @outputter_output.rewind - observed_output = @outputter_output.read - observed_output.should include("apache2") - observed_output.should include("users") - observed_output.should_not include("Run list contains invalid items: no such cookbook nope.") - end - - 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 deleted file mode 100644 index 87c3708ef1..0000000000 --- a/spec/unit/formatters/error_inspectors/cookbook_sync_error_inspector_spec.rb +++ /dev/null @@ -1,43 +0,0 @@ -#-- -# Author:: Daniel DeLeo (<dan@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::Formatters::ErrorInspectors::CookbookSyncErrorInspector do - before do - @description = Chef::Formatters::ErrorDescription.new("Error Expanding RunList:") - @outputter = Chef::Formatters::IndentableOutputStream.new(StringIO.new, STDERR) - #@outputter = Chef::Formatters::IndentableOutputStream.new(STDOUT, STDERR) - end - - describe "when explaining a 502 error" do - before do - @response_body = "sad trombone orchestra" - @response = Net::HTTPBadGateway.new("1.1", "502", "(response) bad gateway") - @response.stub(:body).and_return(@response_body) - @exception = Net::HTTPFatalError.new("(exception) bad gateway", @response) - @inspector = described_class.new({}, @exception) - @inspector.add_explanation(@description) - end - - it "prints a nice message" do - @description.display(@outputter) - end - - end -end 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 deleted file mode 100644 index d2bbffafee..0000000000 --- a/spec/unit/formatters/error_inspectors/node_load_error_inspector_spec.rb +++ /dev/null @@ -1,27 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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' - -# 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 deleted file mode 100644 index 4c21dadd82..0000000000 --- a/spec/unit/formatters/error_inspectors/registration_error_inspector_spec.rb +++ /dev/null @@ -1,27 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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' - -# 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 deleted file mode 100644 index 6691553ddd..0000000000 --- a/spec/unit/formatters/error_inspectors/resource_failure_inspector_spec.rb +++ /dev/null @@ -1,186 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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::Formatters::ErrorInspectors::ResourceFailureInspector do - include Chef::DSL::Recipe - - def run_context - node = Chef::Node.new - node.automatic_attrs[:platform] = "ubuntu" - node.automatic_attrs[:platform_version] = "10.04" - Chef::RunContext.new(node, {}, nil) - end - - def cookbook_name - "rspec-example" - end - - def recipe_name - "rspec-example-recipe" - end - - before do - @description = Chef::Formatters::ErrorDescription.new("Error Converging Resource:") - @stdout = StringIO.new - @outputter = Chef::Formatters::IndentableOutputStream.new(@stdout, STDERR) - #@outputter = Chef::Formatters::IndentableOutputStream.new(STDOUT, STDERR) - - Chef::Config.stub(:cookbook_path).and_return([ "/var/chef/cache" ]) - end - - describe "when explaining an error converging a resource" do - before do - @resource = package("non-existing-package") do - - only_if do - true - end - - not_if("/bin/false") - action :upgrade - end - - @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 = Chef::Exceptions::Package.new("No such package 'non-existing-package'") - @exception.set_backtrace(@trace) - @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @exception) - @inspector.add_explanation(@description) - end - - it "filters chef core code from the backtrace" do - @expected_filtered_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'", - ] - - @inspector.filtered_bt.should == @expected_filtered_trace - end - - it "prints a pretty message" do - @description.display(@outputter) - end - - describe "and the error is a template error" do - before do - @description = Chef::Formatters::ErrorDescription.new("Error Converging Resource:") - @template_class = Class.new { include Chef::Mixin::Template } - @template = @template_class.new - @context = Chef::Mixin::Template::TemplateContext.new({}) - @context[:chef] = "cool" - - @resource = template("/tmp/foo.txt") do - mode "0644" - end - - @error = begin - @context.render_template_from_string("foo\nbar\nbaz\n<%= this_is_not_defined %>\nquin\nqunx\ndunno") - rescue Chef::Mixin::Template::TemplateError => e - e - end - - @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @error) - @inspector.add_explanation(@description) - end - - it "includes contextual info from the template error in the output" do - @description.display(@outputter) - @stdout.string.should include(@error.source_listing) - end - - - end - - describe "recipe_snippet" do - before do - # fake code to run through #recipe_snippet - source_file = [ "if true", "var = non_existant", "end" ] - IO.stub(:readlines).and_return(source_file) - File.stub(:exists?).and_return(true) - end - - it "parses a Windows path" do - source_line = "C:/Users/btm/chef/chef/spec/unit/fake_file.rb:2: undefined local variable or method `non_existant' for main:Object (NameError)" - @resource.source_line = source_line - @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @exception) - @inspector.recipe_snippet.should match(/^# In C:\/Users\/btm/) - 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_existant' for main:Object (NameError)" - @resource.source_line = source_line - @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @exception) - @inspector.recipe_snippet.should match(/^# In \/home\/btm/) - end - - context "when the recipe file does not exist" do - before do - File.stub(:exists?).and_return(false) - IO.stub(:readlines).and_raise(Errno::ENOENT) - end - - it "does not try to parse a recipe in chef-shell/irb (CHEF-3411)" do - @resource.source_line = "(irb#1):1:in `irb_binding'" - @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @exception) - @inspector.recipe_snippet.should be_nil - end - - it "does not raise an exception trying to load a non-existant file (CHEF-3411)" do - @resource.source_line = "/somewhere/in/space" - @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @exception) - lambda { @inspector.recipe_snippet }.should_not raise_error - end - end - end - - describe "when examining a resource that confuses the parser" do - before do - angry_bash_recipe = File.expand_path("cookbooks/angrybash/recipes/default.rb", CHEF_SPEC_DATA) - source_line = "#{angry_bash_recipe}:1:in `<main>'" - - # source_line = caller(0)[0]; @resource = bash "go off the rails" do - # code <<-END - # for i in localhost 127.0.0.1 #{Socket.gethostname()} - # do - # echo "grant all on *.* to root@'$i' identified by 'a_password'; flush privileges;" | mysql -u root -h 127.0.0.1 - # done - # END - # end - @resource = eval(IO.read(angry_bash_recipe)) - @resource.source_line = source_line - @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @exception) - - @exception.set_backtrace(@trace) - @inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(@resource, :create, @exception) - end - - it "does not generate an error" do - lambda { @inspector.add_explanation(@description) }.should_not raise_error - @description.display(@outputter) - end - end - - 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 deleted file mode 100644 index 7f68c4fba4..0000000000 --- a/spec/unit/formatters/error_inspectors/run_list_expansion_error_inspector_spec.rb +++ /dev/null @@ -1,93 +0,0 @@ -#-- -# Author:: Daniel DeLeo (<dan@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::Formatters::ErrorInspectors::RunListExpansionErrorInspector do - before do - @node = Chef::Node.new.tap do |n| - n.name("unit-test.example.com") - n.run_list("role[base]") - end - - @description = Chef::Formatters::ErrorDescription.new("Error Expanding RunList:") - @outputter = Chef::Formatters::IndentableOutputStream.new(StringIO.new, STDERR) - #@outputter = Chef::Formatters::IndentableOutputStream.new(STDOUT, STDERR) - end - - describe "when explaining a missing role error" do - - before do - @run_list_expansion = Chef::RunList::RunListExpansion.new("_default", @node.run_list) - @run_list_expansion.missing_roles_with_including_role << [ "role[missing-role]", "role[base]" ] - @run_list_expansion.missing_roles_with_including_role << [ "role[another-missing-role]", "role[base]" ] - - @exception = Chef::Exceptions::MissingRole.new(@run_list_expansion) - - - @inspector = Chef::Formatters::ErrorInspectors::RunListExpansionErrorInspector.new(@node, @exception) - @inspector.add_explanation(@description) - end - - it "prints a pretty message" do - @description.display(@outputter) - end - - end - - describe "when explaining an HTTP 403 error" do - before do - - @response_body = "forbidden" - @response = Net::HTTPForbidden.new("1.1", "403", "(response) forbidden") - @response.stub(:body).and_return(@response_body) - @exception = Net::HTTPServerException.new("(exception) forbidden", @response) - @inspector = Chef::Formatters::ErrorInspectors::RunListExpansionErrorInspector.new(@node, @exception) - @inspector.stub(:config).and_return(:node_name => "unit-test.example.com") - - @inspector.add_explanation(@description) - end - - it "prints a pretty message" do - @description.display(@outputter) - end - - end - - describe "when explaining an HTTP 401 error" do - before do - @response_body = "check your key and node name" - @response = Net::HTTPUnauthorized.new("1.1", "401", "(response) unauthorized") - @response.stub(:body).and_return(@response_body) - @exception = Net::HTTPServerException.new("(exception) unauthorized", @response) - - @inspector = Chef::Formatters::ErrorInspectors::RunListExpansionErrorInspector.new(@node, @exception) - @inspector.stub(:config).and_return(:node_name => "unit-test.example.com", - :client_key => "/etc/chef/client.pem", - :chef_server_url => "http://chef.example.com") - - @inspector.add_explanation(@description) - end - - it "prints a pretty message" do - @description.display(@outputter) - end - end - -end - diff --git a/spec/unit/guard_interpreter/resource_guard_interpreter_spec.rb b/spec/unit/guard_interpreter/resource_guard_interpreter_spec.rb deleted file mode 100644 index a122ac5515..0000000000 --- a/spec/unit/guard_interpreter/resource_guard_interpreter_spec.rb +++ /dev/null @@ -1,57 +0,0 @@ -# -# Author:: Adam Edwards (<adamed@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' - -describe Chef::GuardInterpreter::ResourceGuardInterpreter do - let(:node) do - node = Chef::Node.new - - node.default["kernel"] = Hash.new - node.default["kernel"][:machine] = :x86_64.to_s - node - end - - let(:run_context) { Chef::RunContext.new(node, nil, nil) } - - let(:resource) do - resource = Chef::Resource.new("powershell_unit_test", run_context) - resource.stub(:run_action) - resource.stub(:updated).and_return(true) - resource - end - - - describe "get_interpreter_resource" do - it "allows the guard interpreter to be set to Chef::Resource::Script" do - resource.guard_interpreter(:script) - expect { Chef::GuardInterpreter::ResourceGuardInterpreter.new(resource, "echo hi", nil) }.not_to raise_error - end - - it "allows the guard interpreter to be set to Chef::Resource::PowershellScript derived indirectly from Chef::Resource::Script" do - resource.guard_interpreter(:powershell_script) - expect { Chef::GuardInterpreter::ResourceGuardInterpreter.new(resource, "echo hi", nil) }.not_to raise_error - end - - it "raises an exception if guard_interpreter is set to a resource not derived from Chef::Resource::Script" do - resource.guard_interpreter(:file) - expect { Chef::GuardInterpreter::ResourceGuardInterpreter.new(resource, "echo hi", nil) }.to raise_error(ArgumentError) - end - end -end - diff --git a/spec/unit/handler/json_file_spec.rb b/spec/unit/handler/json_file_spec.rb deleted file mode 100644 index 05270e4731..0000000000 --- a/spec/unit/handler/json_file_spec.rb +++ /dev/null @@ -1,64 +0,0 @@ -# -# Author:: Adam Jacob (<adam@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. -# - -require 'spec_helper' - -describe Chef::Handler::JsonFile do - before(:each) do - @handler = Chef::Handler::JsonFile.new(:the_sun => "will rise", :path => '/tmp/foobarbazqux') - end - - it "accepts arbitrary config options" do - @handler.config[:the_sun].should == "will rise" - end - - it "creates the directory where the reports will be saved" do - FileUtils.should_receive(:mkdir_p).with('/tmp/foobarbazqux') - File.should_receive(:chmod).with(00700, '/tmp/foobarbazqux') - @handler.build_report_dir - end - - describe "when reporting success" do - before(:each) do - @node = Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - @run_status = Chef::RunStatus.new(@node, @events) - @expected_time = Time.now - Time.stub(:now).and_return(@expected_time, @expected_time + 5) - @run_status.start_clock - @run_status.stop_clock - @run_context = Chef::RunContext.new(@node, {}, @events) - @run_status.run_context = @run_context - @run_status.exception = Exception.new("Boy howdy!") - @file_mock = StringIO.new - File.stub(:open).and_yield(@file_mock) - end - - - it "saves run status data to a file as JSON" do - @handler.should_receive(:build_report_dir) - @handler.run_report_unsafe(@run_status) - reported_data = Chef::JSONCompat.from_json(@file_mock.string) - reported_data['exception'].should == "Exception: Boy howdy!" - reported_data['start_time'].should == @expected_time.to_s - reported_data['end_time'].should == (@expected_time + 5).to_s - reported_data['elapsed_time'].should == 5 - end - - end -end diff --git a/spec/unit/handler_spec.rb b/spec/unit/handler_spec.rb deleted file mode 100644 index 3a7e046dd5..0000000000 --- a/spec/unit/handler_spec.rb +++ /dev/null @@ -1,215 +0,0 @@ -# -# Author:: Adam Jacob (<adam@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. -# - -require 'spec_helper' - -describe Chef::Handler do - before(:each) do - @handler = Chef::Handler.new - - @node = Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - @run_status = Chef::RunStatus.new(@node, @events) - - @handler.instance_variable_set(:@run_status, @run_status) - end - - describe "when accessing the run status" do - before do - @backtrace = caller - @exception = Exception.new("epic_fail") - @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.first.updated = true - @run_context.resource_collection.all_resources.replace(@all_resources) - @run_status.run_context = @run_context - @start_time = Time.now - @end_time = @start_time + 4.2 - Time.stub(:now).and_return(@start_time, @end_time) - @run_status.start_clock - @run_status.stop_clock - end - - it "has a shortcut for the exception" do - @handler.exception.should == @exception - end - - it "has a shortcut for the backtrace" do - @handler.backtrace.should == @backtrace - end - - it "has a shortcut for all resources" do - @handler.all_resources.should == @all_resources - end - - it "has a shortcut for just the updated resources" do - @handler.updated_resources.should == [@all_resources.first] - end - - it "has a shortcut for the start time" do - @handler.start_time.should == @start_time - end - - it "has a shortcut for the end time" do - @handler.end_time.should == @end_time - end - - it "has a shortcut for the elapsed time" do - @handler.elapsed_time.should == 4.2 - end - - it "has a shortcut for the node" do - @handler.node.should == @node - end - - it "has a shortcut for the run context" do - @handler.run_context.should == @run_context - end - - it "has a shortcut for the success? and failed? predicates" do - @handler.success?.should be_false # becuase there's an exception - @handler.failed?.should be_true - end - - it "has a shortcut to the hash representation of the run status" do - @handler.data.should == @run_status.to_hash - end - end - - describe "when running the report" do - it "does not fail if the report handler raises an exception" do - $report_ran = false - def @handler.report - $report_ran = true - raise Exception, "I died the deth" - end - lambda {@handler.run_report_safely(@run_status)}.should_not raise_error - $report_ran.should be_true - end - it "does not fail if the report handler does not raise an exception" do - $report_ran = false - def @handler.report - $report_ran = true - end - lambda {@handler.run_report_safely(@run_status)}.should_not raise_error - $report_ran.should be_true - end - end - - # Hmm, no tests for report handlers, looks like - 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.first.updated = true - @run_context.resource_collection.all_resources.replace(@all_resources) - @run_status.run_context = @run_context - @start_time = Time.now - @end_time = @start_time + 4.2 - Time.stub(:now).and_return(@start_time, @end_time) - @run_status.start_clock - @run_status.stop_clock - end - - it "has a shortcut for all resources" do - @handler.all_resources.should == @all_resources - end - - it "has a shortcut for just the updated resources" do - @handler.updated_resources.should == [@all_resources.first] - end - - it "has a shortcut for the start time" do - @handler.start_time.should == @start_time - end - - it "has a shortcut for the end time" do - @handler.end_time.should == @end_time - end - - it "has a shortcut for the elapsed time" do - @handler.elapsed_time.should == 4.2 - end - - it "has a shortcut for the node" do - @handler.node.should == @node - end - - it "has a shortcut for the run context" do - @handler.run_context.should == @run_context - end - - it "has a shortcut for the success? and failed? predicates" do - @handler.success?.should be_true - @handler.failed?.should be_false - end - - it "has a shortcut to the hash representation of the run status" do - @handler.data.should == @run_status.to_hash - end - end - - # and this would test the start handler - describe "when running a start handler" do - before do - @start_time = Time.now - Time.stub(:now).and_return(@start_time) - @run_status.start_clock - end - - it "should not have all resources" do - @handler.all_resources.should be_false - end - - it "should not have updated resources" do - @handler.updated_resources.should be_false - end - - it "has a shortcut for the start time" do - @handler.start_time.should == @start_time - end - - it "does not have a shortcut for the end time" do - @handler.end_time.should be_false - end - - it "does not have a shortcut for the elapsed time" do - @handler.elapsed_time.should be_false - end - - it "has a shortcut for the node" do - @handler.node.should == @node - end - - it "does not have a shortcut for the run context" do - @handler.run_context.should be_false - end - - it "has a shortcut for the success? and failed? predicates" do - @handler.success?.should be_true # for some reason this is true - @handler.failed?.should be_false - end - - it "has a shortcut to the hash representation of the run status" do - @handler.data.should == @run_status.to_hash - end - end - -end diff --git a/spec/unit/http/basic_client_spec.rb b/spec/unit/http/basic_client_spec.rb deleted file mode 100644 index cb1f2fd979..0000000000 --- a/spec/unit/http/basic_client_spec.rb +++ /dev/null @@ -1,76 +0,0 @@ -# -# Author:: Cameron Cope (<ccope@brightcove.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/http/basic_client' - -describe "HTTP Connection" do - - let(:uri) { URI("https://example.com:4443") } - subject { Chef::HTTP::BasicClient.new(uri) } - - describe ".new" do - it "creates an instance" do - subject - end - end - - describe "#build_http_client" do - it "should build an http client" do - subject.build_http_client - end - - it "should set an open timeout" do - subject.build_http_client.open_timeout.should_not be_nil - end - end - - describe "#proxy_uri" do - shared_examples_for "a proxy uri" do - let(:proxy_host) { "proxy.mycorp.com" } - let(:proxy_port) { 8080 } - let(:proxy) { "#{proxy_prefix}#{proxy_host}:#{proxy_port}" } - - before do - Chef::Config["#{uri.scheme}_proxy"] = proxy - Chef::Config[:no_proxy] = nil - end - - it "should contain the host" do - proxy_uri = subject.proxy_uri - proxy_uri.host.should == proxy_host - end - - it "should contain the port" do - proxy_uri = subject.proxy_uri - proxy_uri.port.should == proxy_port - end - end - - context "when the config setting is normalized (does not contain the scheme)" do - include_examples "a proxy uri" do - let(:proxy_prefix) { "" } - end - end - - context "when the config setting is not normalized (contains the scheme)" do - include_examples "a proxy uri" do - let(:proxy_prefix) { "#{uri.scheme}://" } - end - end - end -end diff --git a/spec/unit/http/http_request_spec.rb b/spec/unit/http/http_request_spec.rb deleted file mode 100644 index d573d4c5dc..0000000000 --- a/spec/unit/http/http_request_spec.rb +++ /dev/null @@ -1,91 +0,0 @@ -# -# Author:: Klaas Jan Wierenga (<k.j.wierenga@gmail.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' - -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.headers['Host'].should 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.headers['Host'].should 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.headers['Host'].should 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.headers['Host'].should 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.headers['Host'].should eql('yourhost.com:8888') - end - - end - - 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.headers['Host'].should 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.headers['Host'].should 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.headers['Host'].should 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.headers['Host'].should 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.headers['Host'].should eql('myhost.com:80') - end - -end diff --git a/spec/unit/http/json_input_spec.rb b/spec/unit/http/json_input_spec.rb deleted file mode 100644 index fbf8f22503..0000000000 --- a/spec/unit/http/json_input_spec.rb +++ /dev/null @@ -1,128 +0,0 @@ -#-- -# Author:: Daniel DeLeo (<dan@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 'chef/http/json_input' - -describe Chef::HTTP::JSONInput do - - let(:json_encoder) { described_class.new() } - - let(:url) { URI.parse("http://example.com") } - let(:headers) { {} } - - def handle_request - json_encoder.handle_request(http_method, url, headers, data) - end - - it "passes the response unmodified" do - http_response = double("Net::HTTPSuccess") - request = double("Chef::HTTP::HTTPRequest") - return_value = "response body" - - result = json_encoder.handle_response(http_response, request, return_value) - expect(result).to eq([http_response, request, return_value]) - end - - it "doesn't handle streaming responses" do - http_response = double("Net::HTTPSuccess") - expect(json_encoder.stream_response_handler(http_response)).to be nil - end - - it "does nothing for stream completion" do - http_response = double("Net::HTTPSuccess") - request = double("Chef::HTTP::HTTPRequest") - return_value = "response body" - - result = json_encoder.handle_response(http_response, request, return_value) - expect(result).to eq([http_response, request, return_value]) - end - - context "when handling a request with no body" do - - let(:http_method) { :get } - let(:data) { nil } - - it "passes the request unmodified" do - expect(handle_request).to eq([http_method, url, headers, data]) - end - end - - context "when the request should be serialized" do - - let(:http_method) { :put } - 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 - - it "serializes the body to json" do - # Headers Hash get mutated, so we start by asserting it's empty: - expect(headers).to be_empty - - expect(handle_request).to eq([http_method, url, headers, expected_data]) - - # Now the headers Hash should have json content type: - expect(headers).to have_key("Content-Type") - expect(headers["Content-Type"]).to eq("application/json") - end - end - - context "ant the request has an explicit content type of json" do - - it "serializes the body to json when content-type is all lowercase" do - headers["content-type"] = "application/json" - - expect(handle_request).to eq([http_method, url, headers, expected_data]) - - # Content-Type header should be normalized: - expect(headers.size).to eq(1) - expect(headers).to have_key("Content-Type") - expect(headers["Content-Type"]).to eq("application/json") - end - - end - - end - - context "when handling a request with an explicit content type other than json" do - - let(:http_method) { :put } - let(:data) { "some arbitrary bytes" } - - it "does not serialize the body to json when content type is given as lowercase" do - headers["content-type"] = "application/x-binary" - - expect(handle_request).to eq([http_method, url, headers, data]) - - # not normalized - 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 - headers["Content-Type"] = "application/x-binary" - - expect(handle_request).to eq([http_method, url, headers, data]) - - # not normalized - expect(headers).to eq({"Content-Type" => "application/x-binary"}) - end - - end - -end diff --git a/spec/unit/http/simple_spec.rb b/spec/unit/http/simple_spec.rb deleted file mode 100644 index b33ef1d553..0000000000 --- a/spec/unit/http/simple_spec.rb +++ /dev/null @@ -1,32 +0,0 @@ -# -# Author:: Serdar Sutay (<serdar@opscode.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' - -describe Chef::HTTP::Simple do - it "should have content length validation middleware after compressor middleware" do - client = Chef::HTTP::Simple.new("dummy.com") - middlewares = client.instance_variable_get(:@middlewares) - content_length = middlewares.find_index { |e| e.is_a? Chef::HTTP::ValidateContentLength } - decompressor = middlewares.find_index { |e| e.is_a? Chef::HTTP::Decompressor } - - content_length.should_not be_nil - decompressor.should_not be_nil - (decompressor < content_length).should be_true - end -end diff --git a/spec/unit/http/ssl_policies_spec.rb b/spec/unit/http/ssl_policies_spec.rb deleted file mode 100644 index b95e13a370..0000000000 --- a/spec/unit/http/ssl_policies_spec.rb +++ /dev/null @@ -1,170 +0,0 @@ -#-- -# Author:: Daniel DeLeo (<dan@opscode.com>) -# Copyright:: Copyright (c) 2009, 2010, 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' -require 'chef/http/ssl_policies' - -describe "HTTP SSL Policy" do - - before do - Chef::Config[:ssl_client_cert] = nil - Chef::Config[:ssl_client_key] = nil - Chef::Config[:ssl_ca_path] = nil - Chef::Config[:ssl_ca_file] = nil - end - - let(:unconfigured_http_client) { Net::HTTP.new("example.com", 443) } - let(:http_client) do - unconfigured_http_client.use_ssl = true - ssl_policy.apply - unconfigured_http_client - end - - describe Chef::HTTP::DefaultSSLPolicy do - - let(:ssl_policy) { Chef::HTTP::DefaultSSLPolicy.new(unconfigured_http_client) } - - describe "when configured with :ssl_verify_mode set to :verify peer" do - before do - Chef::Config[:ssl_verify_mode] = :verify_peer - end - - it "configures the HTTP client to use SSL when given a URL with the https protocol" do - http_client.use_ssl?.should be_true - end - - it "sets the OpenSSL verify mode to verify_peer" do - http_client.verify_mode.should == OpenSSL::SSL::VERIFY_PEER - end - - 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" - lambda {http_client}.should raise_error(Chef::Exceptions::ConfigurationError) - end - - it "should set the CA path if that is set in the configuration" do - Chef::Config[:ssl_ca_path] = File.join(CHEF_SPEC_DATA, "ssl") - http_client.ca_path.should == File.join(CHEF_SPEC_DATA, "ssl") - end - - 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" - lambda {http_client}.should 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' - http_client.ca_file.should == CHEF_SPEC_DATA + '/ssl/5e707473.0' - end - end - - describe "when configured with :ssl_verify_mode set to :verify peer" do - before do - @url = URI.parse("https://chef.example.com:4443/") - Chef::Config[:ssl_verify_mode] = :verify_none - end - - it "sets the OpenSSL verify mode to :verify_none" do - http_client.verify_mode.should == OpenSSL::SSL::VERIFY_NONE - end - end - - describe "when configured with a client certificate" do - 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' - lambda {http_client}.should 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_key] = "/dev/null/nothing_here" - lambda {http_client}.should 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 - lambda {http_client}.should 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' - http_client.cert.to_s.should == OpenSSL::X509::Certificate.new(IO.read(CHEF_SPEC_DATA + '/ssl/chef-rspec.cert')).to_s - http_client.key.to_s.should == IO.read(CHEF_SPEC_DATA + '/ssl/chef-rspec.key') - end - end - - context "when additional certs are located in the trusted_certs dir" do - let(:self_signed_crt_path) { File.join(CHEF_SPEC_DATA, "trusted_certs", "example.crt") } - let(:self_signed_crt) { OpenSSL::X509::Certificate.new(File.read(self_signed_crt_path)) } - - let(:additional_pem_path) { File.join(CHEF_SPEC_DATA, "trusted_certs", "opscode.pem") } - let(:additional_pem) { OpenSSL::X509::Certificate.new(File.read(additional_pem_path)) } - - before do - Chef::Config.trusted_certs_dir = File.join(CHEF_SPEC_DATA, "trusted_certs") - end - - it "enables verification of self-signed certificates" do - http_client.cert_store.verify(self_signed_crt).should be_true - end - - it "enables verification of cert chains" do - # This cert is signed by DigiCert so it would be valid in normal SSL usage. - # The chain goes: - # trusted root -> intermediate -> opscode.pem - # In this test, the intermediate has to be loaded and trusted in order - # for verification to work correctly. - # If the machine running the test doesn't have ruby SSL configured correctly, - # then the root cert also has to be loaded for the test to succeed. - # The system under test **SHOULD** do both of these things. - http_client.cert_store.verify(additional_pem).should be_true - end - - context "and some certs are duplicates" do - it "skips duplicate certs" do - # For whatever reason, OpenSSL errors out when adding a - # cert you already have to the certificate store. - ssl_policy.set_custom_certs - ssl_policy.set_custom_certs #should not raise an error - end - end - end - end - - describe Chef::HTTP::APISSLPolicy do - - let(:ssl_policy) { Chef::HTTP::APISSLPolicy.new(unconfigured_http_client) } - - context "when verify_api_cert is set" do - before do - Chef::Config[:verify_api_cert] = true - end - - it "sets the OpenSSL verify mode to verify_peer" do - http_client.verify_mode.should == OpenSSL::SSL::VERIFY_PEER - end - end - - end -end - diff --git a/spec/unit/http/validate_content_length_spec.rb b/spec/unit/http/validate_content_length_spec.rb deleted file mode 100644 index 091f2b0757..0000000000 --- a/spec/unit/http/validate_content_length_spec.rb +++ /dev/null @@ -1,187 +0,0 @@ -# -# Author:: Serdar Sutay (<serdar@opscode.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 'stringio' - -describe Chef::HTTP::ValidateContentLength do - class TestClient < Chef::HTTP - use Chef::HTTP::ValidateContentLength - end - - let(:method) { "GET" } - let(:url) { "http://dummy.com" } - let(:headers) { {} } - let(:data) { false } - - let(:request) { } - let(:return_value) { "200" } - - # Test Variables - let(:request_type) { :streaming } - let(:content_length_value) { 23 } - let(:streaming_length) { 23 } - let(:response_body) { "Thanks for checking in." } - let(:response_headers) { - { - "content-length" => content_length_value - } - } - - let(:response) { - m = double('HttpResponse', :body => response_body) - m.stub(:[]) do |key| - response_headers[key] - end - - m - } - - let(:middleware) { - client = TestClient.new(url) - client.middlewares[0] - } - - def run_content_length_validation - stream_handler = middleware.stream_response_handler(response) - middleware.handle_request(method, url, headers, data) - - case request_type - when :streaming - # First stream the data - data_length = streaming_length - while data_length > 0 - chunk_size = data_length > 10 ? 10 : data_length - stream_handler.handle_chunk(double("Chunk", :bytesize => chunk_size)) - data_length -= chunk_size - end - - # Finally call stream complete - middleware.handle_stream_complete(response, request, return_value) - when :direct - middleware.handle_response(response, request, return_value) - else - raise "Unknown request_type: #{request_type}" - end - end - - let(:debug_stream) { StringIO.new } - let(:debug_output) { debug_stream.string } - - before(:each) { - Chef::Log.level = :debug - Chef::Log.stub(:debug) do |message| - debug_stream.puts message - end - } - - describe "without response body" do - let(:request_type) { :direct } - let(:response_body) { "Thanks for checking in." } - - it "shouldn't raise error" do - lambda { run_content_length_validation }.should_not raise_error - end - end - - describe "without Content-Length header" do - let(:response_headers) { { } } - - [ "direct", "streaming" ].each do |req_type| - describe "when running #{req_type} request" do - let(:request_type) { req_type.to_sym } - - it "should skip validation and log for debug" do - run_content_length_validation - debug_output.should include("HTTP server did not include a Content-Length header in response") - end - end - end - end - - describe "with correct Content-Length header" do - [ "direct", "streaming" ].each do |req_type| - describe "when running #{req_type} request" do - let(:request_type) { req_type.to_sym } - - it "should validate correctly" do - run_content_length_validation - debug_output.should include("Content-Length validated correctly.") - end - end - end - end - - describe "with wrong Content-Length header" do - let(:content_length_value) { 25 } - [ "direct", "streaming" ].each do |req_type| - describe "when running #{req_type} request" do - let(:request_type) { req_type.to_sym } - - it "should raise ContentLengthMismatch error" do - lambda { run_content_length_validation }.should raise_error(Chef::Exceptions::ContentLengthMismatch) - end - end - end - end - - describe "when download is interrupted" do - let(:streaming_length) { 12 } - - it "should raise ContentLengthMismatch error" do - lambda { run_content_length_validation }.should raise_error(Chef::Exceptions::ContentLengthMismatch) - end - end - - describe "when Transfer-Encoding & Content-Length is set" do - let(:response_headers) { - { - "content-length" => content_length_value, - "transfer-encoding" => "chunked" - } - } - - [ "direct", "streaming" ].each do |req_type| - describe "when running #{req_type} request" do - let(:request_type) { req_type.to_sym } - - it "should skip validation and log for debug" do - run_content_length_validation - debug_output.should include("Transfer-Encoding header is set, skipping Content-Length check.") - end - end - end - end - - describe "when client is being reused" do - before do - run_content_length_validation - debug_output.should include("Content-Length validated correctly.") - end - - it "should reset internal counter" do - middleware.instance_variable_get(:@content_length_counter).should be_nil - end - - it "should validate correctly second time" do - run_content_length_validation - debug_output.should include("Content-Length validated correctly.") - end - end - -end diff --git a/spec/unit/http_spec.rb b/spec/unit/http_spec.rb deleted file mode 100644 index 1cd226b4ee..0000000000 --- a/spec/unit/http_spec.rb +++ /dev/null @@ -1,71 +0,0 @@ -# -# Author:: Xabier de Zuazo (xabier@onddo.com) -# Copyright:: Copyright (c) 2014 Onddo Labs, SL. -# 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' -require 'chef/http/basic_client' - -class Chef::HTTP - public :create_url -end - -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') - http.create_url('api/endpoint').should 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/') - http.create_url('/organization/org/api/endpoint/').should 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///') - http.create_url('///api/endpoint?url=http://foo.bar').should eql(URI.parse('http://www.getchef.com/organization/org/api/endpoint?url=http://foo.bar')) - end - - end # create_url - - describe "head" do - - it 'should return nil for a "200 Success" response (CHEF-4762)' do - resp = Net::HTTPOK.new("1.1", 200, "OK") - resp.should_receive(:read_body).and_return(nil) - http = Chef::HTTP.new("") - Chef::HTTP::BasicClient.any_instance.should_receive(:request).and_return(["request", resp]) - - http.head("http://www.getchef.com/").should eql(nil) - end - - it 'should return false for a "304 Not Modified" response (CHEF-4762)' do - resp = Net::HTTPNotModified.new("1.1", 304, "Not Modified") - resp.should_receive(:read_body).and_return(nil) - http = Chef::HTTP.new("") - Chef::HTTP::BasicClient.any_instance.should_receive(:request).and_return(["request", resp]) - - http.head("http://www.getchef.com/").should eql(false) - end - - end # head - -end diff --git a/spec/unit/json_compat_spec.rb b/spec/unit/json_compat_spec.rb deleted file mode 100644 index e355a47faa..0000000000 --- a/spec/unit/json_compat_spec.rb +++ /dev/null @@ -1,100 +0,0 @@ -# -# Author:: Juanje Ojeda (<juanje.ojeda@gmail.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 File.expand_path('../../spec_helper', __FILE__) -require 'chef/json_compat' - -describe Chef::JSONCompat do - - describe "#from_json with JSON containing an existing class" do - let(:json) { '{"json_class": "Chef::Role"}' } - - it "returns an instance of the class instead of a Hash" do - expect(Chef::JSONCompat.from_json(json).class).to eq Chef::Role - end - end - - describe "#from_json with JSON containing comments" do - let(:json) { %Q{{\n/* comment */\n// comment 2\n"json_class": "Chef::Role"}} } - - it "returns an instance of the class instead of a Hash" do - expect(Chef::JSONCompat.from_json(json).class).to eq Chef::Role - end - end - - describe "#parse with JSON containing comments" do - let(:json) { %Q{{\n/* comment */\n// comment 2\n"json_class": "Chef::Role"}} } - - it "returns a Hash" do - expect(Chef::JSONCompat.parse(json).class).to eq Hash - end - end - - describe 'with JSON containing "Chef::Sandbox" as a json_class value' do - 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"}) - end - end - - describe "when pretty printing an object that defines #to_json" do - class Foo - def to_json(*a) - {'foo' => 1234}.to_json(*a) - end - end - - it "should work" do - f = Foo.new - expect(Chef::JSONCompat.to_json_pretty(f)).to eql("{\n \"foo\": 1234\n}\n") - end - end - - describe "with a file with 300 or less nested entries" do - let(:json) { IO.read(File.join(CHEF_SPEC_DATA, 'big_json.json')) } - let(:hash) { Chef::JSONCompat.from_json(json) } - - describe "when a big json file is loaded" do - it "should create a Hash from the file" do - expect(hash).to be_kind_of(Hash) - end - - it "should has 'test' as a 300th 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']['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']['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']['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']['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']).to eq('test') - end - end - end - - describe "with a file with more than 300 nested entries" do - let(:json) { IO.read(File.join(CHEF_SPEC_DATA, 'big_json_plus_one.json')) } - let(:hash) { Chef::JSONCompat.from_json(json, {:max_nesting => 301}) } - - describe "when a big json file is loaded" do - it "should create a Hash from the file" do - expect(hash).to be_kind_of(Hash) - end - - it "should has 'test' as a 301st 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']['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']['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']['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']['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']).to eq('test') - end - end - end -end diff --git a/spec/unit/knife/bootstrap_spec.rb b/spec/unit/knife/bootstrap_spec.rb deleted file mode 100644 index 70cdd20f35..0000000000 --- a/spec/unit/knife/bootstrap_spec.rb +++ /dev/null @@ -1,527 +0,0 @@ -# -# Author:: Ian Meyer (<ianmmeyer@gmail.com>) -# Copyright:: Copyright (c) 2010 Ian Meyer -# 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::Bootstrap.load_deps -require 'net/ssh' - -describe Chef::Knife::Bootstrap do - before do - Chef::Platform.stub(:windows?) { false } - end - let(:knife) do - Chef::Log.logger = Logger.new(StringIO.new) - Chef::Config[:knife][:bootstrap_template] = bootstrap_template unless bootstrap_template.nil? - - k = Chef::Knife::Bootstrap.new - k.merge_configs - - k.ui.stub(:stderr).and_return(stderr) - allow(k).to receive(:encryption_secret_provided_ignore_encrypt_flag?).and_return(false) - k - end - - let(:stderr) { StringIO.new } - - let(:bootstrap_template) { nil } - - it "should use chef-full as default template" do - knife.bootstrap_template.should be_a_kind_of(String) - File.basename(knife.bootstrap_template).should eq("chef-full") - end - - context "when finding templates" do - context "when :bootstrap_template config is set to a file" do - context "that doesn't exist" do - let(:bootstrap_template) { "/opt/blah/not/exists/template.erb" } - - it "raises an error" do - lambda { knife.find_template }.should raise_error - end - end - - context "that exists" do - let(:bootstrap_template) { File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "test.erb")) } - - it "loads the given file as the template" do - Chef::Log.should_receive(:debug) - knife.find_template.should eq(File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "test.erb"))) - end - end - end - - 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', "example.erb"))} - - let(:chef_config_dir_template_path) { "/knife/chef/config/bootstrap/example.erb" } - - let(:env_home_template_path) { "/env/home/.chef/bootstrap/example.erb" } - - let(:gem_files_template_path) { "/Users/schisamo/.rvm/gems/ruby-1.9.2-p180@chef-0.10/gems/knife-windows-0.5.4/lib/chef/knife/bootstrap/fake-bootstrap-template.erb" } - - def configure_chef_config_dir - Chef::Knife.stub(:chef_config_dir).and_return("/knife/chef/config") - end - - def configure_env_home - ENV['HOME'] = "/env/home" - end - - def configure_gem_files - Gem.stub(:find_files).and_return([ gem_files_template_path ]) - end - - before(:each) do - @original_home = ENV['HOME'] - ENV['HOME'] = nil - File.should_receive(:exists?).with(bootstrap_template).and_return(false) - end - - after(:each) do - ENV['HOME'] = @original_home - end - - context "when file is available everywhere" do - before do - configure_chef_config_dir - configure_env_home - configure_gem_files - - File.should_receive(:exists?).with(builtin_template_path).and_return(true) - end - - it "should load the template from built-in templates" do - knife.find_template.should eq(builtin_template_path) - end - end - - context "when file is available in chef_config_dir" do - before do - configure_chef_config_dir - configure_env_home - configure_gem_files - - File.should_receive(:exists?).with(builtin_template_path).and_return(false) - File.should_receive(:exists?).with(chef_config_dir_template_path).and_return(true) - - it "should load the template from chef_config_dir" do - knife.find_template.should eq(chef_config_dir_template_path) - end - end - end - - context "when file is available in ENV['HOME']" do - before do - configure_chef_config_dir - configure_env_home - configure_gem_files - - File.should_receive(:exists?).with(builtin_template_path).and_return(false) - File.should_receive(:exists?).with(chef_config_dir_template_path).and_return(false) - File.should_receive(:exists?).with(env_home_template_path).and_return(true) - end - - it "should load the template from chef_config_dir" do - knife.find_template.should eq(env_home_template_path) - end - end - - context "when file is available in Gem files" do - before do - configure_chef_config_dir - configure_gem_files - - File.should_receive(:exists?).with(builtin_template_path).and_return(false) - File.should_receive(:exists?).with(chef_config_dir_template_path).and_return(false) - File.should_receive(:exists?).with(gem_files_template_path).and_return(true) - end - - it "should load the template from Gem files" do - knife.find_template.should eq(gem_files_template_path) - end - end - end - end - - ["-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.merge_configs - knife.bootstrap_template.should eq("blahblah") - end - end - end - - context "with run_list template" do - let(:bootstrap_template) { File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "test.erb")) } - - it "should return an empty run_list" do - knife.render_template.should == '{"run_list":[]}' - end - - it "should have role[base] in the run_list" do - knife.parse_options(["-r","role[base]"]) - knife.merge_configs - knife.render_template.should == '{"run_list":["role[base]"]}' - end - - it "should have role[base] and recipe[cupcakes] in the run_list" do - knife.parse_options(["-r", "role[base],recipe[cupcakes]"]) - knife.merge_configs - knife.render_template.should == '{"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) - actual_hash.should == expected_hash - end - end - - context "with hints template" do - let(:bootstrap_template) { File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "test-hints.erb")) } - - it "should create a hint file when told to" do - knife.parse_options(["--hint", "openstack"]) - knife.merge_configs - knife.render_template.should match /\/etc\/chef\/ohai\/hints\/openstack.json/ - end - - it "should populate a hint file with JSON when given a file to read" do - ::File.stub(:read).and_return('{ "foo" : "bar" }') - knife.parse_options(["--hint", "openstack=hints/openstack.json"]) - knife.merge_configs - knife.render_template.should match /\{\"foo\":\"bar\"\}/ - end - end - - describe "specifying no_proxy with various entries" do - subject(:knife) do - k = described_class.new - Chef::Config[:knife][:bootstrap_template] = template_file - k.parse_options(options) - k.merge_configs - k - end - - 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 - end - - context "via --bootstrap-no-proxy" do - let(:setting) { "api.opscode.com" } - - it "renders the client.rb with a single FQDN no_proxy entry" do - rendered_template.should match(%r{.*no_proxy\s*"api.opscode.com".*}) - end - end - - context "via --bootstrap-no-proxy multiple" do - let(:setting) { "api.opscode.com,172.16.10.*" } - - it "renders the client.rb with comma-separated FQDN and wildcard IP address no_proxy entries" do - rendered_template.should match(%r{.*no_proxy\s*"api.opscode.com,172.16.10.\*".*}) - end - end - - context "via --ssl-verify-mode none" do - let(:options) { ["--node-ssl-verify-mode", "none"] } - - it "renders the client.rb with ssl_verify_mode set to :verify_none" do - rendered_template.should match(/ssl_verify_mode :verify_none/) - end - end - - context "via --node-ssl-verify-mode peer" do - let(:options) { ["--node-ssl-verify-mode", "peer"] } - - it "renders the client.rb with ssl_verify_mode set to :verify_peer" do - rendered_template.should match(/ssl_verify_mode :verify_peer/) - end - end - - context "via --node-ssl-verify-mode all" do - let(:options) { ["--node-ssl-verify-mode", "all"] } - - it "raises error" do - lambda{ rendered_template }.should raise_error - end - end - - context "via --node-verify-api-cert" do - let(:options) { ["--node-verify-api-cert"] } - - it "renders the client.rb with verify_api_cert set to true" do - rendered_template.should match(/verify_api_cert true/) - end - end - - context "via --no-node-verify-api-cert" do - let(:options) { ["--no-node-verify-api-cert"] } - - it "renders the client.rb with verify_api_cert set to false" do - rendered_template.should match(/verify_api_cert false/) - end - end - end - - describe "specifying the encrypted data bag secret key" do - let(:secret) { "supersekret" } - let(:options) { [] } - let(:bootstrap_template) { File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "secret.erb")) } - let(:rendered_template) do - knife.parse_options(options) - knife.merge_configs - knife.render_template - end - - it "creates a secret file" do - expect(knife).to receive(:encryption_secret_provided_ignore_encrypt_flag?).and_return(true) - expect(knife).to receive(:read_secret).and_return(secret) - rendered_template.should match(%r{#{secret}}) - end - - it "renders the client.rb with an encrypted_data_bag_secret entry" do - expect(knife).to receive(:encryption_secret_provided_ignore_encrypt_flag?).and_return(true) - expect(knife).to receive(:read_secret).and_return(secret) - rendered_template.should match(%r{encrypted_data_bag_secret\s*"/etc/chef/encrypted_data_bag_secret"}) - end - - end - - describe "when transferring trusted certificates" do - let(:trusted_certs_dir) { Chef::Util::PathHelper.cleanpath(File.join(File.dirname(__FILE__), '../../data/trusted_certs')) } - - let(:rendered_template) do - knife.merge_configs - knife.render_template - end - - before do - Chef::Config[:trusted_certs_dir] = trusted_certs_dir - IO.stub(:read).and_call_original - IO.stub(:read).with(File.expand_path(Chef::Config[:validation_key])).and_return("") - end - - def certificates - Dir[File.join(trusted_certs_dir, "*.{crt,pem}")] - end - - it "creates /etc/chef/trusted_certs" do - rendered_template.should match(%r{mkdir -p /etc/chef/trusted_certs}) - end - - it "copies the certificates in the directory" do - certificates.each do |cert| - IO.should_receive(:read).with(File.expand_path(cert)) - end - - certificates.each do |cert| - rendered_template.should match(%r{cat > /etc/chef/trusted_certs/#{File.basename(cert)} <<'EOP'}) - end - end - - it "doesn't create /etc/chef/trusted_certs if :trusted_certs_dir is empty" do - Dir.should_receive(:glob).with(File.join(trusted_certs_dir, "*.{crt,pem}")).and_return([]) - rendered_template.should_not match(%r{mkdir -p /etc/chef/trusted_certs}) - end - end - - describe "when configuring the underlying knife ssh command" do - context "from the command line" do - let(:knife_ssh) do - knife.name_args = ["foo.example.com"] - knife.config[:ssh_user] = "rooty" - knife.config[:ssh_port] = "4001" - knife.config[:ssh_password] = "open_sesame" - 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.stub(:render_template).and_return("") - knife.knife_ssh - end - - it "configures the hostname" do - knife_ssh.name_args.first.should == "foo.example.com" - end - - it "configures the ssh user" do - knife_ssh.config[:ssh_user].should == 'rooty' - end - - it "configures the ssh password" do - knife_ssh.config[:ssh_password].should == 'open_sesame' - end - - it "configures the ssh port" do - knife_ssh.config[:ssh_port].should == '4001' - end - - it "configures the ssh agent forwarding" do - knife_ssh.config[:forward_agent].should == true - end - - it "configures the ssh identity file" do - knife_ssh.config[:identity_file].should == '~/.ssh/me.rsa' - end - end - - context "validating use_sudo_password" do - before do - knife.config[:ssh_password] = "password" - knife.stub(:render_template).and_return("") - end - - it "use_sudo_password contains description and long params for help" do - knife.options.should have_key(:use_sudo_password) \ - and knife.options[:use_sudo_password][:description].to_s.should_not == ''\ - and knife.options[:use_sudo_password][:long].to_s.should_not == '' - end - - it "uses the password from --ssh-password for sudo when --use-sudo-password is set" do - knife.config[:use_sudo] = true - knife.config[:use_sudo_password] = true - knife.ssh_command.should include("echo \'#{knife.config[:ssh_password]}\' | sudo -S") - end - - it "should not honor --use-sudo-password when --use-sudo is not set" do - knife.config[:use_sudo] = false - knife.config[:use_sudo_password] = true - knife.ssh_command.should_not include("echo #{knife.config[:ssh_password]} | sudo -S") - end - end - - context "from the knife config file" do - let(:knife_ssh) do - knife.name_args = ["config.example.com"] - knife.config[:ssh_user] = nil - knife.config[:ssh_port] = nil - knife.config[:ssh_gateway] = nil - knife.config[:forward_agent] = nil - knife.config[:identity_file] = nil - knife.config[:host_key_verify] = nil - 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_gateway] = "towel.blinkenlights.nl" - Chef::Config[:knife][:host_key_verify] = true - knife.stub(:render_template).and_return("") - knife.knife_ssh - end - - it "configures the ssh user" do - knife_ssh.config[:ssh_user].should == 'curiosity' - end - - it "configures the ssh port" do - knife_ssh.config[:ssh_port].should == '2430' - end - - it "configures the ssh agent forwarding" do - knife_ssh.config[:forward_agent].should == true - end - - it "configures the ssh identity file" do - knife_ssh.config[:identity_file].should == '~/.ssh/you.rsa' - end - - it "configures the ssh gateway" do - knife_ssh.config[:ssh_gateway].should == 'towel.blinkenlights.nl' - end - - it "configures the host key verify mode" do - knife_ssh.config[:host_key_verify].should == true - end - end - - 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.stub(:render_template).and_return("") - k = knife.knife_ssh - k.stub(:get_password).and_return('typed_in_password') - knife.stub(:knife_ssh).and_return(k) - knife.knife_ssh_with_password_auth - end - - it "prompts the user for a password " do - knife_ssh_with_password_auth.config[:ssh_password].should == 'typed_in_password' - end - - it "configures knife not to use the identity file that didn't work previously" do - knife_ssh_with_password_auth.config[:identity_file].should be_nil - end - end - end - - it "verifies that a server to bootstrap was given as a command line arg" do - knife.name_args = nil - lambda { knife.run }.should raise_error(SystemExit) - stderr.string.should 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.stub(:render_template).and_return("") - knife_ssh = knife.knife_ssh - knife.stub(:knife_ssh).and_return(knife_ssh) - knife_ssh - end - - it "configures the underlying ssh command and then runs it" do - knife_ssh.should_receive(:run) - knife.run - end - - it "falls back to password based auth when auth fails the first time" do - knife.stub(:puts) - - fallback_knife_ssh = knife_ssh.dup - knife_ssh.should_receive(:run).and_raise(Net::SSH::AuthenticationFailed.new("no ssh for you")) - knife.stub(:knife_ssh_with_password_auth).and_return(fallback_knife_ssh) - fallback_knife_ssh.should_receive(:run) - knife.run - end - - it "raises the exception if config[:ssh_password] is set and an authentication exception is raised" do - knife.config[:ssh_password] = "password" - knife_ssh.should_receive(:run).and_raise(Net::SSH::AuthenticationFailed) - lambda { knife.run }.should raise_error(Net::SSH::AuthenticationFailed) - end - end - - 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 deleted file mode 100644 index d5cfda9885..0000000000 --- a/spec/unit/knife/client_bulk_delete_spec.rb +++ /dev/null @@ -1,166 +0,0 @@ -# -# Author:: Stephen Delano (<stephen@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. -# - -require 'spec_helper' - -describe Chef::Knife::ClientBulkDelete do - let(:stdout_io) { StringIO.new } - let(:stdout) {stdout_io.string} - let(:stderr_io) { StringIO.new } - let(:stderr) { stderr_io.string } - - let(:knife) { - k = Chef::Knife::ClientBulkDelete.new - k.name_args = name_args - k.config = option_args - k.ui.stub(:stdout).and_return(stdout_io) - k.ui.stub(:stderr).and_return(stderr_io) - k.ui.stub(:confirm).and_return(knife_confirm) - k.ui.stub(:confirm_without_exit).and_return(knife_confirm) - k - } - - let(:name_args) { [ "." ] } - let(:option_args) { {} } - - let(:knife_confirm) { true } - - let(:nonvalidator_client_names) { %w{tim dan stephen} } - let(:nonvalidator_clients) { - clients = Hash.new - - nonvalidator_client_names.each do |client_name| - client = Chef::ApiClient.new() - client.name(client_name) - client.stub(:destroy).and_return(true) - clients[client_name] = client - end - - clients - } - - let(:validator_client_names) { %w{myorg-validator} } - let(:validator_clients) { - clients = Hash.new - - validator_client_names.each do |validator_client_name| - validator_client = Chef::ApiClient.new() - validator_client.name(validator_client_name) - validator_client.stub(:validator).and_return(true) - validator_client.stub(:destroy).and_return(true) - clients[validator_client_name] = validator_client - end - - clients - } - - let(:client_names) { nonvalidator_client_names + validator_client_names} - let(:clients) { - nonvalidator_clients.merge(validator_clients) - } - - before(:each) do - Chef::ApiClient.stub(:list).and_return(clients) - end - - describe "run" do - describe "without a regex" do - let(:name_args) { [ ] } - - it "should exit if the regex is not provided" do - lambda { knife.run }.should raise_error(SystemExit) - end - end - - describe "with any clients" do - it "should get the list of the clients" do - Chef::ApiClient.should_receive(:list) - knife.run - end - - it "should print the name of the clients" do - knife.run - client_names.each do |client_name| - stdout.should include(client_name) - end - end - - it "should confirm you really want to delete them" do - knife.ui.should_receive(:confirm) - knife.run - end - - describe "without --delete-validators" do - it "should mention that validator clients wont be deleted" do - knife.run - stdout.should include("Following clients are validators and will not be deleted.") - info = stdout.index "Following clients are validators and will not be deleted." - val = stdout.index "myorg-validator" - (val > info).should be_true - end - - it "should only delete nonvalidator clients" do - nonvalidator_clients.each_value do |c| - c.should_receive(:destroy) - end - - validator_clients.each_value do |c| - c.should_not_receive(:destroy) - end - - knife.run - end - end - - describe "with --delete-validators" do - let(:option_args) { {:delete_validators => true} } - - it "should mention that validator clients will be deleted" do - knife.run - stdout.should include("The following validators will be deleted") - end - - it "should confirm twice" do - knife.ui.should_receive(:confirm).once - knife.ui.should_receive(:confirm_without_exit).once - knife.run - end - - it "should delete all clients" do - clients.each_value do |c| - c.should_receive(:destroy) - end - - knife.run - end - end - end - - describe "with some clients" do - let(:name_args) { [ "^ti" ] } - - it "should only delete clients that match the regex" do - clients["tim"].should_receive(:destroy) - clients["stephen"].should_not_receive(:destroy) - clients["dan"].should_not_receive(:destroy) - clients["myorg-validator"].should_not_receive(:destroy) - knife.run - end - end - end -end diff --git a/spec/unit/knife/client_create_spec.rb b/spec/unit/knife/client_create_spec.rb deleted file mode 100644 index 59238d69ec..0000000000 --- a/spec/unit/knife/client_create_spec.rb +++ /dev/null @@ -1,102 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -Chef::Knife::ClientCreate.load_deps - -describe Chef::Knife::ClientCreate do - before(:each) do - Chef::Config[:node_name] = "webmonkey.example.com" - @knife = Chef::Knife::ClientCreate.new - @knife.config = { - :file => nil, - :admin => false, - :validator => false - } - @knife.name_args = [ "adam" ] - @client = Chef::ApiClient.new - @client.stub(:save).and_return({ 'private_key' => '' }) - @knife.stub(:edit_data).and_return(@client) - @knife.stub(:puts) - Chef::ApiClient.stub(:new).and_return(@client) - @stderr = StringIO.new - @knife.ui.stub(:stderr).and_return(@stderr) - end - - describe "run" do - it "should create a new Client" do - Chef::ApiClient.should_receive(:new).and_return(@client) - @knife.run - @stderr.string.should match /created client.+adam/i - end - - it "should set the Client name" do - @client.should_receive(:name).with("adam") - @knife.run - end - - it "by default it is not an admin" do - @client.should_receive(:admin).with(false) - @knife.run - end - - it "by default it is not a validator" do - @client.should_receive(:validator).with(false) - @knife.run - end - - it "should allow you to edit the data" do - @knife.should_receive(:edit_data).with(@client) - @knife.run - end - - it "should save the Client" do - @client.should_receive(:save) - @knife.run - end - - describe "with -f or --file" do - it "should write the private key to a file" do - @knife.config[:file] = "/tmp/monkeypants" - @client.stub(:save).and_return({ 'private_key' => "woot" }) - filehandle = double("Filehandle") - filehandle.should_receive(:print).with('woot') - File.should_receive(:open).with("/tmp/monkeypants", "w").and_yield(filehandle) - @knife.run - end - end - - describe "with -a or --admin" do - it "should create an admin client" do - @knife.config[:admin] = true - @client.should_receive(:admin).with(true) - @knife.run - end - end - - describe "with --validator" do - it "should create an validator client" do - @knife.config[:validator] = true - @client.should_receive(:validator).with(true) - @knife.run - end - end - - end -end diff --git a/spec/unit/knife/client_delete_spec.rb b/spec/unit/knife/client_delete_spec.rb deleted file mode 100644 index c7908a0934..0000000000 --- a/spec/unit/knife/client_delete_spec.rb +++ /dev/null @@ -1,83 +0,0 @@ -# -# Author:: Thomas Bishop (<bishop.thomas@gmail.com>) -# Copyright:: Copyright (c) 2011 Thomas Bishop -# 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::ClientDelete do - before(:each) do - @knife = Chef::Knife::ClientDelete.new - # defaults - @knife.config = { - :delete_validators => false - } - @knife.name_args = [ 'adam' ] - end - - describe 'run' do - it 'should delete the client' do - @knife.should_receive(:delete_object).with(Chef::ApiClient, 'adam', 'client') - @knife.run - end - - it 'should print usage and exit when a client name is not provided' do - @knife.name_args = [] - @knife.should_receive(:show_usage) - @knife.ui.should_receive(:fatal) - lambda { @knife.run }.should raise_error(SystemExit) - end - end - - describe 'with a validator' do - before(:each) do - Chef::Knife::UI.stub(:confirm).and_return(true) - @knife.stub(:confirm).and_return(true) - @client = Chef::ApiClient.new - Chef::ApiClient.should_receive(:load).and_return(@client) - end - - it 'should delete non-validator client if --delete-validators is not set' do - @knife.config[:delete_validators] = false - @client.should_receive(:destroy).and_return(@client) - @knife.should_receive(:msg) - - @knife.run - end - - it 'should delete non-validator client if --delete-validators is set' do - @knife.config[:delete_validators] = true - @client.should_receive(:destroy).and_return(@client) - @knife.should_receive(:msg) - - @knife.run - end - - it 'should not delete validator client if --delete-validators is not set' do - @client.validator(true) - @knife.ui.should_receive(:fatal) - lambda { @knife.run}.should raise_error(SystemExit) - end - - it 'should delete validator client if --delete-validators is set' do - @knife.config[:delete_validators] = true - @client.should_receive(:destroy).and_return(@client) - @knife.should_receive(:msg) - - @knife.run - end - end -end diff --git a/spec/unit/knife/client_edit_spec.rb b/spec/unit/knife/client_edit_spec.rb deleted file mode 100644 index 1d7049be30..0000000000 --- a/spec/unit/knife/client_edit_spec.rb +++ /dev/null @@ -1,40 +0,0 @@ -# -# Author:: Thomas Bishop (<bishop.thomas@gmail.com>) -# Copyright:: Copyright (c) 2011 Thomas Bishop -# 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::ClientEdit do - before(:each) do - @knife = Chef::Knife::ClientEdit.new - @knife.name_args = [ 'adam' ] - end - - describe 'run' do - it 'should edit the client' do - @knife.should_receive(:edit_object).with(Chef::ApiClient, 'adam') - @knife.run - end - - it 'should print usage and exit when a client name is not provided' do - @knife.name_args = [] - @knife.should_receive(:show_usage) - @knife.ui.should_receive(:fatal) - lambda { @knife.run }.should raise_error(SystemExit) - end - end -end diff --git a/spec/unit/knife/client_list_spec.rb b/spec/unit/knife/client_list_spec.rb deleted file mode 100644 index c4834ad8d1..0000000000 --- a/spec/unit/knife/client_list_spec.rb +++ /dev/null @@ -1,34 +0,0 @@ -# -# Author:: Thomas Bishop (<bishop.thomas@gmail.com>) -# Copyright:: Copyright (c) 2011 Thomas Bishop -# 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::ClientList do - before(:each) do - @knife = Chef::Knife::ClientList.new - @knife.name_args = [ 'adam' ] - end - - describe 'run' do - it 'should list the clients' do - Chef::ApiClient.should_receive(:list) - @knife.should_receive(:format_list_for_display) - @knife.run - end - end -end diff --git a/spec/unit/knife/client_reregister_spec.rb b/spec/unit/knife/client_reregister_spec.rb deleted file mode 100644 index daf18d5d25..0000000000 --- a/spec/unit/knife/client_reregister_spec.rb +++ /dev/null @@ -1,62 +0,0 @@ -# -# Author:: Thomas Bishop (<bishop.thomas@gmail.com>) -# Copyright:: Copyright (c) 2011 Thomas Bishop -# 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::ClientReregister do - before(:each) do - @knife = Chef::Knife::ClientReregister.new - @knife.name_args = [ 'adam' ] - @client_mock = double('client_mock', :private_key => "foo_key") - @stdout = StringIO.new - @knife.ui.stub(:stdout).and_return(@stdout) - end - - context "when no client name is given on the command line" do - before do - @knife.name_args = [] - end - - it 'should print usage and exit when a client name is not provided' do - @knife.should_receive(:show_usage) - @knife.ui.should_receive(:fatal) - lambda { @knife.run }.should raise_error(SystemExit) - end - end - - context 'when not configured for file output' do - it 'reregisters the client and prints the key' do - Chef::ApiClient.should_receive(:reregister).with('adam').and_return(@client_mock) - @knife.run - @stdout.string.should match( /foo_key/ ) - end - end - - context 'when configured for file output' do - it 'should write the private key to a file' do - Chef::ApiClient.should_receive(:reregister).with('adam').and_return(@client_mock) - - @knife.config[:file] = '/tmp/monkeypants' - filehandle = StringIO.new - File.should_receive(:open).with('/tmp/monkeypants', 'w').and_yield(filehandle) - @knife.run - filehandle.string.should == "foo_key" - end - end - -end diff --git a/spec/unit/knife/client_show_spec.rb b/spec/unit/knife/client_show_spec.rb deleted file mode 100644 index 8404e8d019..0000000000 --- a/spec/unit/knife/client_show_spec.rb +++ /dev/null @@ -1,52 +0,0 @@ -# -# Author:: Thomas Bishop (<bishop.thomas@gmail.com>) -# Copyright:: Copyright (c) 2011 Thomas Bishop -# 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::ClientShow do - before(:each) do - @knife = Chef::Knife::ClientShow.new - @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) - expect(@knife).to receive(:format_for_display).with(@client_mock) - @knife.run - end - - 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) - @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 - @knife.name_args = [] - expect(@knife).to receive(:show_usage) - expect(@knife.ui).to receive(:fatal) - expect { @knife.run }.to raise_error(SystemExit) - end - end -end diff --git a/spec/unit/knife/configure_client_spec.rb b/spec/unit/knife/configure_client_spec.rb deleted file mode 100644 index de2a5a41e5..0000000000 --- a/spec/unit/knife/configure_client_spec.rb +++ /dev/null @@ -1,84 +0,0 @@ -# -# Author:: Thomas Bishop (<bishop.thomas@gmail.com>) -# Copyright:: Copyright (c) 2011 Thomas Bishop -# 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::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' - - @stderr = StringIO.new - @knife.ui.stub(:stderr).and_return(@stderr) - end - - describe 'run' do - it 'should print usage and exit when a directory is not provided' do - @knife.should_receive(:show_usage) - @knife.ui.should_receive(:fatal).with(/must provide the directory/) - lambda { - @knife.run - }.should raise_error SystemExit - end - - describe 'when specifing a directory' do - before do - @knife.name_args = ['/home/bob/.chef'] - @client_file = StringIO.new - @validation_file = StringIO.new - File.should_receive(:open).with('/home/bob/.chef/client.rb', 'w'). - and_yield(@client_file) - File.should_receive(:open).with('/home/bob/.chef/validation.pem', 'w'). - and_yield(@validation_file) - IO.should_receive(:read).and_return('foo_bar_baz') - end - - it 'should recursively create the directory' do - FileUtils.should_receive(:mkdir_p).with('/home/bob/.chef') - @knife.run - end - - it 'should write out the config file' do - FileUtils.stub(:mkdir_p) - @knife.run - @client_file.string.should match /log_level\s+\:info/ - @client_file.string.should match /log_location\s+STDOUT/ - @client_file.string.should match /chef_server_url\s+'https\:\/\/chef\.example\.com'/ - @client_file.string.should match /validation_client_name\s+'chef-validator'/ - end - - it 'should write out the validation.pem file' do - FileUtils.stub(:mkdir_p) - @knife.run - @validation_file.string.should match /foo_bar_baz/ - end - - it 'should print information on what is being configured' do - FileUtils.stub(:mkdir_p) - @knife.run - @stderr.string.should match /creating client configuration/i - @stderr.string.should match /writing client\.rb/i - @stderr.string.should match /writing validation\.pem/i - end - end - end - -end - diff --git a/spec/unit/knife/configure_spec.rb b/spec/unit/knife/configure_spec.rb deleted file mode 100644 index c16019dcf7..0000000000 --- a/spec/unit/knife/configure_spec.rb +++ /dev/null @@ -1,243 +0,0 @@ -require 'spec_helper' - -describe Chef::Knife::Configure do - before do - Chef::Log.logger = Logger.new(StringIO.new) - - Chef::Config[:node_name] = "webmonkey.example.com" - @knife = Chef::Knife::Configure.new - @rest_client = double("null rest client", :post_rest => { :result => :true }) - @knife.stub(:rest).and_return(@rest_client) - - @out = StringIO.new - @knife.ui.stub(:stdout).and_return(@out) - @knife.config[:config_file] = '/home/you/.chef/knife.rb' - - @in = StringIO.new("\n" * 7) - @knife.ui.stub(:stdin).and_return(@in) - - @err = StringIO.new - @knife.ui.stub(:stderr).and_return(@err) - - Ohai::System.stub(:new).and_return(ohai) - end - - - let(:fqdn) { "foo.example.org" } - - let(:ohai) do - o = {} - o.stub(:require_plugin) - o.stub(:load_plugins) - o[:fqdn] = fqdn - o - end - - let(:default_admin_key) { "/etc/chef-server/admin.pem" } - let(:default_admin_key_win32) { File.expand_path(default_admin_key) } - - let(:default_validator_key) { "/etc/chef-server/chef-validator.pem" } - let(:default_validator_key_win32) { File.expand_path(default_validator_key) } - - let(:default_server_url) { "https://#{fqdn}:443" } - - - it "asks the user for the URL of the chef server" do - @knife.ask_user_for_config - @out.string.should match(Regexp.escape("Please enter the chef server URL: [#{default_server_url}]")) - @knife.chef_server.should == default_server_url - end - - it "asks the user for the clientname they want for the new client if -i is specified" do - @knife.config[:initial] = true - Etc.stub(:getlogin).and_return("a-new-user") - @knife.ask_user_for_config - @out.string.should match(Regexp.escape("Please enter a name for the new user: [a-new-user]")) - @knife.new_client_name.should == Etc.getlogin - end - - 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' - Etc.stub(:getlogin).and_return("a-new-user") - @knife.ask_user_for_config - @out.string.should_not match(Regexp.escape("Please enter a name for the new user")) - @knife.new_client_name.should == 'testnode' - end - - it "asks the user for the existing API username or clientname if -i is not specified" do - Etc.stub(:getlogin).and_return("a-new-user") - @knife.ask_user_for_config - @out.string.should match(Regexp.escape("Please enter an existing username or clientname for the API: [a-new-user]")) - @knife.new_client_name.should == Etc.getlogin - end - - it "asks the user for the existing admin client's name if -i is specified" do - @knife.config[:initial] = true - @knife.ask_user_for_config - @out.string.should match(Regexp.escape("Please enter the existing admin name: [admin]")) - @knife.admin_client_name.should == '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.ask_user_for_config - @out.string.should_not match(Regexp.escape("Please enter the existing admin:")) - @knife.admin_client_name.should == '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 - @out.string.should_not match(Regexp.escape("Please enter the existing admin: [admin]")) - @knife.admin_client_name.should_not == 'admin' - end - - it "asks the user for the location of the existing admin key if -i is specified" do - @knife.config[:initial] = true - @knife.ask_user_for_config - @out.string.should match(Regexp.escape("Please enter the location of the existing admin's private key: [#{default_admin_key}]")) - if windows? - @knife.admin_client_key.capitalize.should == default_admin_key_win32.capitalize - else - @knife.admin_client_key.should == default_admin_key - end - end - - 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.ask_user_for_config - @out.string.should_not match(Regexp.escape("Please enter the location of the existing admin client's private key:")) - if windows? - @knife.admin_client_key.should match %r{^[A-Za-z]:/home/you/\.chef/my-webui\.pem$} - else - @knife.admin_client_key.should == '/home/you/.chef/my-webui.pem' - end - end - - it "should not ask the user for the location of the existing admin key if -i is not specified" do - @knife.ask_user_for_config - @out.string.should_not match(Regexp.escape("Please enter the location of the existing admin client's private key: [#{default_admin_key}]")) - if windows? - @knife.admin_client_key.should_not == default_admin_key_win32 - else - @knife.admin_client_key.should_not == default_admin_key - end - end - - it "asks the user for the location of a chef repo" do - @knife.ask_user_for_config - @out.string.should match(Regexp.escape("Please enter the path to a chef repository (or leave blank):")) - @knife.chef_repo.should == '' - end - - it "asks the users for the name of the validation client" do - @knife.ask_user_for_config - @out.string.should match(Regexp.escape("Please enter the validation clientname: [chef-validator]")) - @knife.validation_client_name.should == '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.ask_user_for_config - @out.string.should_not match(Regexp.escape("Please enter the validation clientname:")) - @knife.validation_client_name.should == 'my-validator' - end - - it "asks the users for the location of the validation key" do - @knife.ask_user_for_config - @out.string.should match(Regexp.escape("Please enter the location of the validation key: [#{default_validator_key}]")) - if windows? - @knife.validation_key.capitalize.should == default_validator_key_win32.capitalize - else - @knife.validation_key.should == default_validator_key - end - 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.ask_user_for_config - @out.string.should_not match(Regexp.escape("Please enter the location of the validation key:")) - if windows? - @knife.validation_key.should match %r{^[A-Za-z]:/home/you/\.chef/my-validation\.pem$} - else - @knife.validation_key.should == '/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' - Etc.stub(:getlogin).and_return('a-new-user') - - @knife.ask_user_for_config - @out.string.should match(/\s*/) - - @knife.new_client_name.should == 'testnode' - @knife.chef_server.should == 'http://localhost:5000' - @knife.admin_client_name.should == 'my-webui' - if windows? - @knife.admin_client_key.should match %r{^[A-Za-z]:/home/you/\.chef/my-webui\.pem$} - @knife.validation_key.should match %r{^[A-Za-z]:/home/you/\.chef/my-validation\.pem$} - @knife.new_client_key.should match %r{^[A-Za-z]:/home/you/a-new-user\.pem$} - else - @knife.admin_client_key.should == '/home/you/.chef/my-webui.pem' - @knife.validation_key.should == '/home/you/.chef/my-validation.pem' - @knife.new_client_key.should == '/home/you/a-new-user.pem' - end - @knife.validation_client_name.should == 'my-validator' - @knife.chef_repo.should == '' - end - - it "writes the new data to a config file" do - File.stub(:expand_path).with("/home/you/.chef/knife.rb").and_return("/home/you/.chef/knife.rb") - File.stub(:expand_path).with("/home/you/.chef/#{Etc.getlogin}.pem").and_return("/home/you/.chef/#{Etc.getlogin}.pem") - File.stub(:expand_path).with(default_validator_key).and_return(default_validator_key) - File.stub(:expand_path).with(default_admin_key).and_return(default_admin_key) - FileUtils.should_receive(:mkdir_p).with("/home/you/.chef") - config_file = StringIO.new - ::File.should_receive(:open).with("/home/you/.chef/knife.rb", "w").and_yield config_file - @knife.config[:repository] = '/home/you/chef-repo' - @knife.run - config_file.string.should match(/^node_name[\s]+'#{Etc.getlogin}'$/) - config_file.string.should match(%r{^client_key[\s]+'/home/you/.chef/#{Etc.getlogin}.pem'$}) - config_file.string.should match(/^validation_client_name\s+'chef-validator'$/) - config_file.string.should match(%r{^validation_key\s+'#{default_validator_key}'$}) - config_file.string.should match(%r{^chef_server_url\s+'#{default_server_url}'$}) - config_file.string.should match(%r{cookbook_path\s+\[ '/home/you/chef-repo/cookbooks' \]}) - end - - it "creates a new client when given the --initial option" do - File.should_receive(:expand_path).with("/home/you/.chef/knife.rb").and_return("/home/you/.chef/knife.rb") - File.should_receive(:expand_path).with("/home/you/.chef/a-new-user.pem").and_return("/home/you/.chef/a-new-user.pem") - File.should_receive(:expand_path).with(default_validator_key).and_return(default_validator_key) - File.should_receive(:expand_path).with(default_admin_key).and_return(default_admin_key) - Chef::Config[:node_name] = "webmonkey.example.com" - - user_command = Chef::Knife::UserCreate.new - user_command.should_receive(:run) - - Etc.stub(:getlogin).and_return("a-new-user") - - Chef::Knife::UserCreate.stub(:new).and_return(user_command) - FileUtils.should_receive(:mkdir_p).with("/home/you/.chef") - ::File.should_receive(:open).with("/home/you/.chef/knife.rb", "w") - @knife.config[:initial] = true - @knife.config[:user_password] = "blah" - @knife.run - user_command.name_args.should == Array("a-new-user") - user_command.config[:user_password].should == "blah" - user_command.config[:admin].should be_true - user_command.config[:file].should == "/home/you/.chef/a-new-user.pem" - user_command.config[:yes].should be_true - user_command.config[:disable_editing].should be_true - end -end diff --git a/spec/unit/knife/cookbook_bulk_delete_spec.rb b/spec/unit/knife/cookbook_bulk_delete_spec.rb deleted file mode 100644 index fb4b1d1484..0000000000 --- a/spec/unit/knife/cookbook_bulk_delete_spec.rb +++ /dev/null @@ -1,89 +0,0 @@ -# -# Author:: Stephen Delano (<stephen@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. -# - -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" - @knife = Chef::Knife::CookbookBulkDelete.new - @knife.config = {:print_after => nil} - @knife.name_args = ["."] - @stdout = StringIO.new - @stderr = StringIO.new - @knife.ui.stub(:stdout).and_return(@stdout) - @knife.ui.stub(:stderr).and_return(@stderr) - @knife.ui.stub(:confirm).and_return(true) - @cookbooks = Hash.new - %w{cheezburger pizza lasagna}.each do |cookbook_name| - cookbook = Chef::CookbookVersion.new(cookbook_name) - @cookbooks[cookbook_name] = cookbook - end - @rest = double("Chef::REST") - @rest.stub(:get_rest).and_return(@cookbooks) - @rest.stub(:delete_rest).and_return(true) - @knife.stub(:rest).and_return(@rest) - Chef::CookbookVersion.stub(: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"}]}} - @rest.stub(:get_rest).with('cookbooks/cheezburger').and_return(@cheezburger) - @pizza = {'pizza' => {"url" => "file:///dev/null", "versions" => [{"url" => "file:///dev/null-pizza", "version" => "2.0.0"}]}} - @rest.stub(:get_rest).with('cookbooks/pizza').and_return(@pizza) - @lasagna = {'lasagna' => {"url" => "file:///dev/null", "versions" => [{"url" => "file:///dev/null-lasagna", "version" => "3.0.0"}]}} - @rest.stub(:get_rest).with('cookbooks/lasagna').and_return(@lasagna) - end - - it "should print the cookbooks you are about to delete" do - expected = @knife.ui.list(@cookbooks.keys.sort, :columns_down) - @knife.run - @stdout.string.should match(/#{expected}/) - end - - it "should confirm you really want to delete them" do - @knife.ui.should_receive(:confirm) - @knife.run - end - - it "should delete each cookbook" do - {"cheezburger" => "1.0.0", "pizza" => "2.0.0", "lasagna" => '3.0.0'}.each do |cookbook_name, version| - @rest.should_receive(:delete_rest).with("cookbooks/#{cookbook_name}/#{version}") - end - @knife.run - end - - it "should only delete cookbooks that match the regex" do - @knife.name_args = ["cheezburger"] - @rest.should_receive(:delete_rest).with('cookbooks/cheezburger/1.0.0') - @knife.run - end - end - - it "should exit if the regex is not provided" do - @knife.name_args = [] - lambda { @knife.run }.should raise_error(SystemExit) - end - -end diff --git a/spec/unit/knife/cookbook_create_spec.rb b/spec/unit/knife/cookbook_create_spec.rb deleted file mode 100644 index 06475d3ac9..0000000000 --- a/spec/unit/knife/cookbook_create_spec.rb +++ /dev/null @@ -1,260 +0,0 @@ -# -# Author:: Nuo Yan (<nuo@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. -# - -require 'spec_helper' -require 'tmpdir' - -describe Chef::Knife::CookbookCreate do - before(:each) do - Chef::Config[:node_name] = "webmonkey.example.com" - @knife = Chef::Knife::CookbookCreate.new - @knife.config = {} - @knife.name_args = ["foobar"] - @stdout = StringIO.new - @knife.stub(:stdout).and_return(@stdout) - end - - describe "run" do - - # Fixes CHEF-2579 - it "should expand the path of the cookbook directory" do - File.should_receive(:expand_path).with("~/tmp/monkeypants") - @knife.config = {:cookbook_path => "~/tmp/monkeypants"} - @knife.stub(:create_cookbook) - @knife.stub(:create_readme) - @knife.stub(:create_changelog) - @knife.stub(:create_metadata) - @knife.run - end - - 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.should_receive(:create_cookbook).with(@dir, @knife.name_args.first, "YOUR_COMPANY_NAME", "none") - @knife.should_receive(:create_readme).with(@dir, @knife.name_args.first, "md") - @knife.should_receive(:create_changelog).with(@dir, @knife.name_args.first) - @knife.should_receive(:create_metadata).with(@dir, @knife.name_args.first, "YOUR_COMPANY_NAME", "YOUR_EMAIL", "none", "md") - @knife.run - end - - it "should create a new cookbook with specified company name in the copyright section if one is specified" do - @dir = Dir.tmpdir - @knife.config = { - :cookbook_path => @dir, - :cookbook_copyright => "Opscode, Inc" - } - @knife.name_args=["foobar"] - @knife.should_receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "none") - @knife.should_receive(:create_readme).with(@dir, @knife.name_args.first, "md") - @knife.should_receive(:create_changelog).with(@dir, @knife.name_args.first) - @knife.should_receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "YOUR_EMAIL", "none", "md") - @knife.run - end - - it "should create a new cookbook with specified copyright name and email if they are specified" do - @dir = Dir.tmpdir - @knife.config = { - :cookbook_path => @dir, - :cookbook_copyright => "Opscode, Inc", - :cookbook_email => "nuo@opscode.com" - } - @knife.name_args=["foobar"] - @knife.should_receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "none") - @knife.should_receive(:create_readme).with(@dir, @knife.name_args.first, "md") - @knife.should_receive(:create_changelog).with(@dir, @knife.name_args.first) - @knife.should_receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "none", "md") - @knife.run - end - - it "should create a new cookbook with specified copyright name and email and license information (true) if they are specified" do - @dir = Dir.tmpdir - @knife.config = { - :cookbook_path => @dir, - :cookbook_copyright => "Opscode, Inc", - :cookbook_email => "nuo@opscode.com", - :cookbook_license => "apachev2" - } - @knife.name_args=["foobar"] - @knife.should_receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "apachev2") - @knife.should_receive(:create_readme).with(@dir, @knife.name_args.first, "md") - @knife.should_receive(:create_changelog).with(@dir, @knife.name_args.first) - @knife.should_receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "apachev2", "md") - @knife.run - end - - it "should create a new cookbook with specified copyright name and email and license information (false) if they are specified" do - @dir = Dir.tmpdir - @knife.config = { - :cookbook_path => @dir, - :cookbook_copyright => "Opscode, Inc", - :cookbook_email => "nuo@opscode.com", - :cookbook_license => false - } - @knife.name_args=["foobar"] - @knife.should_receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "none") - @knife.should_receive(:create_readme).with(@dir, @knife.name_args.first, "md") - @knife.should_receive(:create_changelog).with(@dir, @knife.name_args.first) - @knife.should_receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "none", "md") - @knife.run - end - - it "should create a new cookbook with specified copyright name and email and license information ('false' as string) if they are specified" do - @dir = Dir.tmpdir - @knife.config = { - :cookbook_path => @dir, - :cookbook_copyright => "Opscode, Inc", - :cookbook_email => "nuo@opscode.com", - :cookbook_license => "false" - } - @knife.name_args=["foobar"] - @knife.should_receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "none") - @knife.should_receive(:create_readme).with(@dir, @knife.name_args.first, "md") - @knife.should_receive(:create_changelog).with(@dir, @knife.name_args.first) - @knife.should_receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "none", "md") - @knife.run - end - - it "should allow specifying a gpl2 license" do - @dir = Dir.tmpdir - @knife.config = { - :cookbook_path => @dir, - :cookbook_copyright => "Opscode, Inc", - :cookbook_email => "nuo@opscode.com", - :cookbook_license => "gplv2" - } - @knife.name_args=["foobar"] - @knife.should_receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "gplv2") - @knife.should_receive(:create_readme).with(@dir, @knife.name_args.first, "md") - @knife.should_receive(:create_changelog).with(@dir, @knife.name_args.first) - @knife.should_receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "gplv2", "md") - @knife.run - end - - it "should allow specifying a gplv3 license" do - @dir = Dir.tmpdir - @knife.config = { - :cookbook_path => @dir, - :cookbook_copyright => "Opscode, Inc", - :cookbook_email => "nuo@opscode.com", - :cookbook_license => "gplv3" - } - @knife.name_args=["foobar"] - @knife.should_receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "gplv3") - @knife.should_receive(:create_readme).with(@dir, @knife.name_args.first, "md") - @knife.should_receive(:create_changelog).with(@dir, @knife.name_args.first) - @knife.should_receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "gplv3", "md") - @knife.run - end - - it "should allow specifying the mit license" do - @dir = Dir.tmpdir - @knife.config = { - :cookbook_path => @dir, - :cookbook_copyright => "Opscode, Inc", - :cookbook_email => "nuo@opscode.com", - :cookbook_license => "mit" - } - @knife.name_args=["foobar"] - @knife.should_receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "mit") - @knife.should_receive(:create_readme).with(@dir, @knife.name_args.first, "md") - @knife.should_receive(:create_changelog).with(@dir, @knife.name_args.first) - @knife.should_receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "mit", "md") - @knife.run - end - - it "should allow specifying the rdoc readme format" do - @dir = Dir.tmpdir - @knife.config = { - :cookbook_path => @dir, - :cookbook_copyright => "Opscode, Inc", - :cookbook_email => "nuo@opscode.com", - :cookbook_license => "mit", - :readme_format => "rdoc" - } - @knife.name_args=["foobar"] - @knife.should_receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "mit") - @knife.should_receive(:create_readme).with(@dir, @knife.name_args.first, "rdoc") - @knife.should_receive(:create_changelog).with(@dir, @knife.name_args.first) - @knife.should_receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "mit", "rdoc") - @knife.run - end - - it "should allow specifying the mkd readme format" do - @dir = Dir.tmpdir - @knife.config = { - :cookbook_path => @dir, - :cookbook_copyright => "Opscode, Inc", - :cookbook_email => "nuo@opscode.com", - :cookbook_license => "mit", - :readme_format => "mkd" - } - @knife.name_args=["foobar"] - @knife.should_receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "mit") - @knife.should_receive(:create_readme).with(@dir, @knife.name_args.first, "mkd") - @knife.should_receive(:create_changelog).with(@dir, @knife.name_args.first) - @knife.should_receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "mit", "mkd") - @knife.run - end - - it "should allow specifying the txt readme format" do - @dir = Dir.tmpdir - @knife.config = { - :cookbook_path => @dir, - :cookbook_copyright => "Opscode, Inc", - :cookbook_email => "nuo@opscode.com", - :cookbook_license => "mit", - :readme_format => "txt" - } - @knife.name_args=["foobar"] - @knife.should_receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "mit") - @knife.should_receive(:create_readme).with(@dir, @knife.name_args.first, "txt") - @knife.should_receive(:create_changelog).with(@dir, @knife.name_args.first) - @knife.should_receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "mit", "txt") - @knife.run - end - - it "should allow specifying an arbitrary readme format" do - @dir = Dir.tmpdir - @knife.config = { - :cookbook_path => @dir, - :cookbook_copyright => "Opscode, Inc", - :cookbook_email => "nuo@opscode.com", - :cookbook_license => "mit", - :readme_format => "foo" - } - @knife.name_args=["foobar"] - @knife.should_receive(:create_cookbook).with(@dir, @knife.name_args.first, "Opscode, Inc", "mit") - @knife.should_receive(:create_readme).with(@dir, @knife.name_args.first, "foo") - @knife.should_receive(:create_changelog).with(@dir, @knife.name_args.first) - @knife.should_receive(:create_metadata).with(@dir, @knife.name_args.first, "Opscode, Inc", "nuo@opscode.com", "mit", "foo") - @knife.run - end - - context "when the cookbooks path is set to nil" do - before do - Chef::Config[:cookbook_path] = nil - end - - it "should throw an argument error" do - @dir = Dir.tmpdir - lambda{@knife.run}.should raise_error(ArgumentError) - end - end - - end -end diff --git a/spec/unit/knife/cookbook_delete_spec.rb b/spec/unit/knife/cookbook_delete_spec.rb deleted file mode 100644 index 53b120be71..0000000000 --- a/spec/unit/knife/cookbook_delete_spec.rb +++ /dev/null @@ -1,239 +0,0 @@ -# -# Author:: Thomas Bishop (<bishop.thomas@gmail.com>) -# Copyright:: Copyright (c) 2011 Thomas Bishop -# 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::CookbookDelete do - before(:each) do - @knife = Chef::Knife::CookbookDelete.new - @knife.name_args = ['foobar'] - @knife.cookbook_name = 'foobar' - @stdout = StringIO.new - @knife.ui.stub(:stdout).and_return(@stdout) - @stderr = StringIO.new - @knife.ui.stub(:stderr).and_return(@stderr) - end - - describe 'run' do - it 'should print usage and exit when a cookbook name is not provided' do - @knife.name_args = [] - @knife.should_receive(:show_usage) - @knife.ui.should_receive(:fatal) - lambda { @knife.run }.should raise_error(SystemExit) - end - - describe 'when specifying a cookbook name' do - it 'should delete the cookbook without a specific version' do - @knife.should_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' - @knife.should_receive(:delete_explicit_version) - @knife.run - end - end - - describe 'with -a or --all' do - it 'should delete all versions of the cookbook' do - @knife.config[:all] = true - @knife.should_receive(:delete_all_versions) - @knife.run - end - end - - describe 'with -p or --purge' do - it 'should prompt to purge the files' do - @knife.config[:purge] = true - @knife.should_receive(:confirm). - with(/.+Are you sure you want to purge files.+/) - @knife.should_receive(:delete_without_explicit_version) - @knife.run - end - end - end - end - - describe 'delete_explicit_version' do - it 'should delete the specific cookbook version' do - @knife.cookbook_name = 'foobar' - @knife.version = '1.0.0' - @knife.should_receive(:delete_object).with(Chef::CookbookVersion, - 'foobar version 1.0.0', - 'cookbook').and_yield() - @knife.should_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' - @knife.should_receive(:confirm).with('Do you really want to delete all versions of foobar') - @knife.should_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'] - @knife.should_receive(:available_versions).and_return(versions) - versions.each do |v| - @knife.should_receive(:delete_version_without_confirmation).with(v) - end - @knife.delete_all_without_confirmation - end - end - - describe 'delete_without_explicit_version' do - it 'should exit if there are no available versions' do - @knife.should_receive(:available_versions).and_return(nil) - lambda { @knife.delete_without_explicit_version }.should raise_error(SystemExit) - end - - it 'should delete the version if only one is found' do - @knife.should_receive(:available_versions).at_least(:once).and_return(['1.0.0']) - @knife.should_receive(:delete_explicit_version) - @knife.delete_without_explicit_version - end - - it 'should ask which version(s) to delete if multiple are found' do - @knife.should_receive(:available_versions).at_least(:once).and_return(['1.0.0', '1.1.0']) - @knife.should_receive(:ask_which_versions_to_delete).and_return(['1.0.0', '1.1.0']) - @knife.should_receive(:delete_versions_without_confirmation).with(['1.0.0', '1.1.0']) - @knife.delete_without_explicit_version - end - end - - describe 'available_versions' do - before(:each) do - @rest_mock = double('rest') - @knife.should_receive(:rest).and_return(@rest_mock) - @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 - @rest_mock.should_receive(:get_rest).with('cookbooks/foobar').and_return(@cookbook_data) - @knife.available_versions.should == ['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') - @rest_mock.should_receive(:get_rest).and_raise(exception) - lambda { @knife.available_versions }.should raise_error Net::HTTPServerException - end - - describe "if the cookbook can't be found" do - before(:each) do - @rest_mock.should_receive(:get_rest). - and_raise(Net::HTTPServerException.new('404 Not Found', '404')) - end - - it 'should print an error' do - @knife.available_versions - @stderr.string.should match /error.+cannot find a cookbook named foobar/i - end - - it 'should return nil' do - @knife.available_versions.should == nil - end - end - end - - describe 'ask_which_version_to_delete' do - before(:each) do - @knife.stub(:available_versions).and_return(['1.0.0', '1.1.0', '2.0.0']) - end - - 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 - @knife.should_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 - @knife.should_receive(:ask_question).and_return('') - @knife.ui.should_receive(:error).with(/no versions specified/i) - lambda { @knife.ask_which_versions_to_delete }.should raise_error(SystemExit) - end - - it 'should print an error if an invalid choice was selected' do - @knife.should_receive(:ask_question).and_return('100') - @knife.ui.should_receive(:error).with(/100 is not a valid choice/i) - @knife.ask_which_versions_to_delete - end - - it 'should return the selected versions' do - @knife.should_receive(:ask_question).and_return('1, 3') - @knife.ask_which_versions_to_delete.should == ['1.0.0', '2.0.0'] - end - - it "should return all of the versions if 'all' was selected" do - @knife.should_receive(:ask_question).and_return('4') - @knife.ask_which_versions_to_delete.should == [:all] - end - end - - describe 'delete_version_without_confirmation' do - it 'should delete the cookbook version' do - @knife.should_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 - @knife.stub(:delete_request) - @knife.delete_version_without_confirmation('1.0.0') - @stderr.string.should match /deleted cookbook\[foobar\]\[1.0.0\]/im - end - - describe 'with --print-after' do - it 'should display the cookbook data' do - object = '' - @knife.config[:print_after] = true - @knife.stub(:delete_request).and_return(object) - @knife.should_receive(:format_for_display).with(object) - @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'] - versions.each do |v| - @knife.should_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 - versions = [:all] - @knife.should_receive(:delete_all_without_confirmation) - @knife.delete_versions_without_confirmation(versions) - end - end - end - -end diff --git a/spec/unit/knife/cookbook_download_spec.rb b/spec/unit/knife/cookbook_download_spec.rb deleted file mode 100644 index 6f40a3396b..0000000000 --- a/spec/unit/knife/cookbook_download_spec.rb +++ /dev/null @@ -1,238 +0,0 @@ -# -# Author:: Thomas Bishop (<bishop.thomas@gmail.com>) -# Copyright:: Copyright (c) 2011 Thomas Bishop -# 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::CookbookDownload do - before(:each) do - @knife = Chef::Knife::CookbookDownload.new - @stderr = StringIO.new - @knife.ui.stub(:stderr).and_return(@stderr) - end - - describe 'run' do - it 'should print usage and exit when a cookbook name is not provided' do - @knife.name_args = [] - @knife.should_receive(:show_usage) - @knife.ui.should_receive(:fatal).with(/must specify a cookbook name/) - lambda { @knife.run }.should 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] - @knife.should_receive(:determine_version).and_return(nil) - @knife.ui.should_receive(:fatal).with('No such cookbook found') - lambda { @knife.run }.should raise_error(SystemExit) - end - - 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.stub(: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'} - ], - :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'} - ], - :attributes => [ - {'path' => 'attributes/default.rb', - 'url' => 'http://example.org/files/default.rb'} - ] - } - - @cookbook_mock = double('cookbook') - @cookbook_mock.stub(:version).and_return('1.0.0') - @cookbook_mock.stub(:manifest).and_return(@manifest_data) - @rest_mock.should_receive(:get_rest).with('cookbooks/foobar/1.0.0'). - and_return(@cookbook_mock) - end - - it 'should determine which version if one was not explicitly specified'do - @cookbook_mock.stub(:manifest).and_return({}) - @knife.should_receive(:determine_version).and_return('1.0.0') - File.should_receive(:exists?).with('/var/tmp/chef/foobar-1.0.0').and_return(false) - Chef::CookbookVersion.stub(:COOKBOOK_SEGEMENTS).and_return([]) - @knife.run - end - - 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 - @files_mocks = {} - @files.map { |f| File.basename(f) }.flatten.uniq.each do |f| - @files_mocks[f] = double("#{f}_mock") - @files_mocks[f].stub(:path).and_return("/var/tmp/#{f}") - end - end - - it 'should print an error and exit if the cookbook download directory already exists' do - File.should_receive(:exists?).with('/var/tmp/chef/foobar-1.0.0').and_return(true) - @knife.ui.should_receive(:fatal).with(/\/var\/tmp\/chef\/foobar-1\.0\.0 exists/i) - lambda { @knife.run }.should raise_error(SystemExit) - end - - describe 'when downloading the cookbook' do - before(:each) do - @files.map { |f| File.dirname(f) }.flatten.uniq.each do |dir| - FileUtils.should_receive(:mkdir_p).with("/var/tmp/chef/foobar-1.0.0/#{dir}"). - at_least(:once) - end - - @files_mocks.each_pair do |file, mock| - @rest_mock.should_receive(:get_rest).with("http://example.org/files/#{file}", true). - and_return(mock) - end - - @rest_mock.should_receive(:sign_on_redirect=).with(false).at_least(:once) - @files.each do |f| - FileUtils.should_receive(:mv). - 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 - File.should_receive(:exists?).with('/var/tmp/chef/foobar-1.0.0').and_return(false) - @knife.run - ['attributes', 'recipes', 'templates'].each do |segment| - @stderr.string.should match /downloading #{segment}/im - end - @stderr.string.should match /downloading foobar cookbook version 1\.0\.0/im - @stderr.string.should 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 - @knife.config[:force] = true - File.should_receive(:exists?).with('/var/tmp/chef/foobar-1.0.0').and_return(true) - FileUtils.should_receive(:rm_rf).with('/var/tmp/chef/foobar-1.0.0') - @knife.run - end - end - end - - end - end - - end - - describe 'determine_version' do - - it 'should return nil if there are no versions' do - @knife.should_receive(:available_versions).and_return(nil) - @knife.determine_version.should == nil - @knife.version.should == nil - end - - it 'should return and set the version if there is only one version' do - @knife.should_receive(:available_versions).at_least(:once).and_return(['1.0.0']) - @knife.determine_version.should == '1.0.0' - @knife.version.should == '1.0.0' - end - - it 'should ask which version to download and return it if there is more than one' do - @knife.should_receive(:available_versions).at_least(:once).and_return(['1.0.0', '2.0.0']) - @knife.should_receive(:ask_which_version).and_return('1.0.0') - @knife.determine_version.should == '1.0.0' - end - - describe 'with -N or --latest' do - it 'should return and set the version to the latest version' do - @knife.config[:latest] = true - @knife.should_receive(:available_versions).at_least(:once). - and_return(['1.0.0', '1.1.0', '2.0.0']) - @knife.determine_version - @knife.version.to_s.should == '2.0.0' - end - end - end - - describe 'available_versions' do - before(:each) do - @knife.cookbook_name = 'foobar' - end - - it 'should return nil if there are no versions' do - Chef::CookbookVersion.should_receive(:available_versions). - with('foobar'). - and_return(nil) - @knife.available_versions.should == nil - end - - it 'should return the available versions' do - Chef::CookbookVersion.should_receive(:available_versions). - with('foobar'). - and_return(['1.1.0', '2.0.0', '1.0.0']) - @knife.available_versions.should == [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 - Chef::CookbookVersion.should_receive(:available_versions). - 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 - before(:each) do - @knife.cookbook_name = 'foobar' - @knife.stub(:available_versions).and_return(['1.0.0', '1.1.0', '2.0.0']) - end - - 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 - @knife.should_receive(:ask_question).with(prompt).and_return('1') - @knife.ask_which_version - end - - it "should set the version to the user's selection" do - @knife.should_receive(:ask_question).and_return('1') - @knife.ask_which_version - @knife.version.should == '1.0.0' - end - - it "should print an error and exit if a version wasn't specified" do - @knife.should_receive(:ask_question).and_return('') - @knife.ui.should_receive(:error).with(/is not a valid value/i) - lambda { @knife.ask_which_version }.should raise_error(SystemExit) - end - - it 'should print an error if an invalid choice was selected' do - @knife.should_receive(:ask_question).and_return('100') - @knife.ui.should_receive(:error).with(/'100' is not a valid value/i) - lambda { @knife.ask_which_version }.should raise_error(SystemExit) - end - end - -end diff --git a/spec/unit/knife/cookbook_list_spec.rb b/spec/unit/knife/cookbook_list_spec.rb deleted file mode 100644 index 9ff16edb37..0000000000 --- a/spec/unit/knife/cookbook_list_spec.rb +++ /dev/null @@ -1,88 +0,0 @@ -# -# Author:: Thomas Bishop (<bishop.thomas@gmail.com>) -# Copyright:: Copyright (c) 2011 Thomas Bishop -# 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::CookbookList do - before do - @knife = Chef::Knife::CookbookList.new - @rest_mock = double('rest') - @knife.stub(:rest).and_return(@rest_mock) - @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"}]} - end - @stdout = StringIO.new - @knife.ui.stub(:stdout).and_return(@stdout) - end - - describe 'run' do - it 'should display the latest version of the cookbooks' do - @rest_mock.should_receive(:get_rest).with('/cookbooks?num_versions=1'). - and_return(@cookbook_data) - @knife.run - @cookbook_names.each do |item| - @stdout.string.should match /#{item}\s+1\.0\.1/ - end - end - - it 'should query cookbooks for the configured environment' do - @knife.config[:environment] = 'production' - @rest_mock.should_receive(:get_rest). - 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 - @knife.config[:with_uri] = true - @rest_mock.stub(:get_rest).and_return(@cookbook_data) - @knife.run - @cookbook_names.each do |item| - pattern = /#{Regexp.escape(@cookbook_data[item]['versions'].first['url'])}/ - @stdout.string.should match pattern - end - end - end - - 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"} - end - end - - it 'should display all versions of the cookbooks' do - @knife.config[:all_versions] = true - @rest_mock.should_receive(:get_rest).with('/cookbooks?num_versions=all'). - and_return(@cookbook_data) - @knife.run - @cookbook_names.each do |item| - @stdout.string.should match /#{item}\s+1\.0\.1\s+1\.0\.0/ - end - end - end - - end -end diff --git a/spec/unit/knife/cookbook_metadata_from_file_spec.rb b/spec/unit/knife/cookbook_metadata_from_file_spec.rb deleted file mode 100644 index 68ab6740ab..0000000000 --- a/spec/unit/knife/cookbook_metadata_from_file_spec.rb +++ /dev/null @@ -1,65 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: Matthew Kent (<mkent@magoazul.com>) -# Copyright:: Copyright (c) 2008 Opscode, Inc. -# 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. -# - -require 'spec_helper' - -describe Chef::Knife::CookbookMetadataFromFile do - before(:each) do - 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 - @knife.name_args = [ @src ] - @knife.stub(:to_json_pretty).and_return(true) - @md = Chef::Cookbook::Metadata.new - Chef::Cookbook::Metadata.stub(:new).and_return(@md) - $stdout.stub(:write) - end - - after do - if File.exists?(@tgt) - File.unlink(@tgt) - end - end - - describe "run" do - it "should determine cookbook name from path" do - @md.should_receive(:name).with() - @md.should_receive(:name).with("quick_start") - @knife.run - end - - it "should load the metadata source" do - @md.should_receive(:from_file).with(@src) - @knife.run - end - - it "should write out the metadata to the correct location" do - File.should_receive(:open).with(@tgt, "w") - @knife.run - end - - it "should generate json from the metadata" do - Chef::JSONCompat.should_receive(:to_json_pretty).with(@md) - @knife.run - end - - end -end diff --git a/spec/unit/knife/cookbook_metadata_spec.rb b/spec/unit/knife/cookbook_metadata_spec.rb deleted file mode 100644 index 1d6568739c..0000000000 --- a/spec/unit/knife/cookbook_metadata_spec.rb +++ /dev/null @@ -1,179 +0,0 @@ -# -# Author:: Thomas Bishop (<bishop.thomas@gmail.com>) -# Copyright:: Copyright (c) 2011 Thomas Bishop -# 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::CookbookMetadata do - before(:each) do - @knife = Chef::Knife::CookbookMetadata.new - @knife.name_args = ['foobar'] - @cookbook_dir = Dir.mktmpdir - @json_data = '{ "version": "1.0.0" }' - @stdout = StringIO.new - @stderr = StringIO.new - @knife.ui.stub(:stdout).and_return(@stdout) - @knife.ui.stub(:stderr).and_return(@stderr) - end - - describe 'run' do - it 'should print an error and exit if a cookbook name was not provided' do - @knife.name_args = [] - @knife.ui.should_receive(:error).with(/you must specify the cookbook.+use the --all/i) - lambda { @knife.run }.should raise_error(SystemExit) - end - - it 'should print an error and exit if an empty cookbook name was provided' do - @knife.name_args = [''] - @knife.ui.should_receive(:error).with(/you must specify the cookbook.+use the --all/i) - lambda { @knife.run }.should raise_error(SystemExit) - end - - it 'should generate the metadata for the cookbook' do - @knife.should_receive(:generate_metadata).with('foobar') - @knife.run - end - - 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' - @cookbook_loader = { - "foo" => @foo, - "bar" => @bar - } - @cookbook_loader.should_receive(:load_cookbooks).and_return(@cookbook_loader) - @knife.should_receive(:generate_metadata).with('foo') - @knife.should_receive(:generate_metadata).with('bar') - end - - it 'should generate the metadata for each cookbook' do - Chef::Config[:cookbook_path] = @cookbook_dir - Chef::CookbookLoader.should_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' - Chef::CookbookLoader.should_receive(:new).with('/opt/chef/cookbooks').and_return(@cookbook_loader) - @knife.run - end - end - end - - end - - describe 'generate_metadata' do - before(:each) do - @knife.config[:cookbook_path] = @cookbook_dir - File.stub(:expand_path).with("#{@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 - File.should_receive(:exists?).with("#{@cookbook_dir}/foobar/metadata.rb"). - and_return(true) - @knife.should_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 - File.should_receive(:exists?).with("#{@cookbook_dir}/foobar/metadata.rb"). - and_return(false) - @knife.should_receive(:validate_metadata_json).with(@cookbook_dir, 'foobar') - @knife.run - end - end - - describe 'generate_metadata_from_file' do - before(:each) do - @metadata_mock = double('metadata') - @json_file_mock = double('json_file') - end - - it 'should generate the metatdata json from metatdata.rb' do - Chef::Cookbook::Metadata.stub(:new).and_return(@metadata_mock) - @metadata_mock.should_receive(:name).with('foobar') - @metadata_mock.should_receive(:from_file).with("#{@cookbook_dir}/foobar/metadata.rb") - File.should_receive(:open).with("#{@cookbook_dir}/foobar/metadata.json", 'w'). - and_yield(@json_file_mock) - @json_file_mock.should_receive(:write).with(@json_data) - Chef::JSONCompat.should_receive(:to_json_pretty).with(@metadata_mock). - and_return(@json_data) - @knife.generate_metadata_from_file('foobar', "#{@cookbook_dir}/foobar/metadata.rb") - @stderr.string.should match /generating metadata for foobar from #{@cookbook_dir}\/foobar\/metadata\.rb/im - end - - { 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") - Chef::Cookbook::Metadata.stub(:new).and_raise(exception) - lambda { - @knife.generate_metadata_from_file('foobar', "#{@cookbook_dir}/foobar/metadata.rb") - }.should raise_error(SystemExit) - @stderr.string.should match /error: the cookbook 'foobar' contains invalid or obsolete metadata syntax/im - @stderr.string.should match /in #{@cookbook_dir}\/foobar\/metadata\.rb/im - @stderr.string.should match /#{description} blah/im - end - end - end - - describe 'validate_metadata_json' do - it 'should validate the metadata json' do - File.should_receive(:exist?).with("#{@cookbook_dir}/foobar/metadata.json"). - and_return(true) - IO.should_receive(:read).with("#{@cookbook_dir}/foobar/metadata.json"). - and_return(@json_data) - Chef::Cookbook::Metadata.should_receive(:validate_json).with(@json_data) - @knife.validate_metadata_json(@cookbook_dir, 'foobar') - end - - it 'should not try to validate the metadata json if the file does not exist' do - File.should_receive(:exist?).with("#{@cookbook_dir}/foobar/metadata.json"). - and_return(false) - IO.should_not_receive(:read) - Chef::Cookbook::Metadata.should_not_receive(:validate_json) - @knife.validate_metadata_json(@cookbook_dir, 'foobar') - end - - { 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 - File.should_receive(:exist?).with("#{@cookbook_dir}/foobar/metadata.json"). - and_return(true) - IO.should_receive(:read).with("#{@cookbook_dir}/foobar/metadata.json"). - and_return(@json_data) - exception = klass.new("#{description} blah") - Chef::Cookbook::Metadata.stub(:validate_json).and_raise(exception) - lambda { - @knife.validate_metadata_json(@cookbook_dir, 'foobar') - }.should raise_error(SystemExit) - @stderr.string.should match /error: the cookbook 'foobar' contains invalid or obsolete metadata syntax/im - @stderr.string.should match /in #{@cookbook_dir}\/foobar\/metadata\.json/im - @stderr.string.should match /#{description} blah/im - end - end - end - -end diff --git a/spec/unit/knife/cookbook_show_spec.rb b/spec/unit/knife/cookbook_show_spec.rb deleted file mode 100644 index b862c3154c..0000000000 --- a/spec/unit/knife/cookbook_show_spec.rb +++ /dev/null @@ -1,223 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Copyright:: Copyright (c) 2008 Opscode, Inc. -# License:: Apache License, eersion 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. -# - -# rename to cookbook not coookbook -require 'spec_helper' - -describe Chef::Knife::CookbookShow do - before(:each) do - Chef::Config[:node_name] = "webmonkey.example.com" - @knife = Chef::Knife::CookbookShow.new - @knife.config = { } - @knife.name_args = [ "cookbook_name" ] - @rest = double(Chef::REST) - @knife.stub(:rest).and_return(@rest) - @knife.stub(:pretty_print).and_return(true) - @knife.stub(:output).and_return(true) - end - - describe "run" do - describe "with 0 arguments: help" do - it 'should should print usage and exit when given no arguments' do - @knife.name_args = [] - @knife.should_receive(:show_usage) - @knife.ui.should_receive(:fatal) - lambda { @knife.run }.should raise_error(SystemExit) - end - end - - describe "with 1 argument: versions" do - before(:each) do - @response = { - "cookbook_name" => { - "url" => "http://url/cookbooks/cookbook_name", - "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" } - ] - } - } - end - - it "should show the raw cookbook data" do - @rest.should_receive(:get_rest).with("cookbooks/cookbook_name").and_return(@response) - @knife.should_receive(:format_cookbook_list_for_display).with(@response) - @knife.run - end - - it "should respect the user-supplied environment" do - @knife.config[:environment] = "foo" - @rest.should_receive(:get_rest).with("environments/foo/cookbooks/cookbook_name").and_return(@response) - @knife.should_receive(:format_cookbook_list_for_display).with(@response) - @knife.run - end - end - - describe "with 2 arguments: name and version" do - before(:each) do - @knife.name_args << "0.1.0" - @response = { "0.1.0" => { "recipes" => {"default.rb" => ""} } } - end - - it "should show the specific part of a cookbook" do - @rest.should_receive(:get_rest).with("cookbooks/cookbook_name/0.1.0").and_return(@response) - @knife.should_receive(:output).with(@response) - @knife.run - end - end - - describe "with 3 arguments: name, version, and segment" do - before(:each) do - @knife.name_args = [ "cookbook_name", "0.1.0", "recipes" ] - @cookbook_response = Chef::CookbookVersion.new("cookbook_name") - @manifest = { - "recipes" => [ - { - :name => "default.rb", - :path => "recipes/default.rb", - :checksum => "1234", - :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"} - end - - it "should print the json of the part" do - @rest.should_receive(:get_rest).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response) - @knife.should_receive(:output).with(@cookbook_response.manifest["recipes"]) - @knife.run - end - end - - describe "with 4 arguments: name, version, segment and filename" do - before(:each) do - @knife.name_args = [ "cookbook_name", "0.1.0", "recipes", "default.rb" ] - @cookbook_response = Chef::CookbookVersion.new("cookbook_name") - @cookbook_response.manifest = { - "recipes" => [ - { - :name => "default.rb", - :path => "recipes/default.rb", - :checksum => "1234", - :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 - @rest.should_receive(:get_rest).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response) - @rest.should_receive(:get_rest).with("http://example.org/files/default.rb", true).and_return(StringIO.new(@response)) - @knife.should_receive(:pretty_print).with(@response) - @knife.run - end - end - - describe "with 4 arguments: name, version, segment and filename -- with specificity" do - before(:each) do - @knife.name_args = [ "cookbook_name", "0.1.0", "files", "afile.rb" ] - @cookbook_response = Chef::CookbookVersion.new("cookbook_name") - @cookbook_response.manifest = { - "files" => [ - { - :name => "afile.rb", - :path => "files/host-examplehost.example.org/afile.rb", - :checksum => "1111", - :specificity => "host-examplehost.example.org", - :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" - }, - { - :name => "afile.rb", - :path => "files/ubuntu/afile.rb", - :checksum => "3333", - :specificity => "ubuntu", - :url => "http://example.org/files/3333" - }, - { - :name => "afile.rb", - :path => "files/default/afile.rb", - :checksum => "4444", - :specificity => "default", - :url => "http://example.org/files/4444" - }, - ] - } - - @response = "Example recipe text" - end - - describe "with --fqdn" do - it "should pass the fqdn" do - @knife.config[:platform] = "example_platform" - @knife.config[:platform_version] = "1.0" - @knife.config[:fqdn] = "examplehost.example.org" - @rest.should_receive(:get_rest).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response) - @rest.should_receive(:get_rest).with("http://example.org/files/1111", true).and_return(StringIO.new(@response)) - @knife.should_receive(:pretty_print).with(@response) - @knife.run - end - end - - describe "and --platform" do - it "should pass the platform" do - @knife.config[:platform] = "ubuntu" - @knife.config[:platform_version] = "1.0" - @knife.config[:fqdn] = "differenthost.example.org" - @rest.should_receive(:get_rest).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response) - @rest.should_receive(:get_rest).with("http://example.org/files/3333", true).and_return(StringIO.new(@response)) - @knife.should_receive(:pretty_print).with(@response) - @knife.run - end - end - - describe "and --platform-version" do - it "should pass the platform" do - @knife.config[:platform] = "ubuntu" - @knife.config[:platform_version] = "9.10" - @knife.config[:fqdn] = "differenthost.example.org" - @rest.should_receive(:get_rest).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response) - @rest.should_receive(:get_rest).with("http://example.org/files/2222", true).and_return(StringIO.new(@response)) - @knife.should_receive(:pretty_print).with(@response) - @knife.run - end - end - - describe "with none of the arguments, it should use the default" do - it "should pass them all" do - @rest.should_receive(:get_rest).with("cookbooks/cookbook_name/0.1.0").and_return(@cookbook_response) - @rest.should_receive(:get_rest).with("http://example.org/files/4444", true).and_return(StringIO.new(@response)) - @knife.should_receive(:pretty_print).with(@response) - @knife.run - end - end - - end - end -end - diff --git a/spec/unit/knife/cookbook_site_download_spec.rb b/spec/unit/knife/cookbook_site_download_spec.rb deleted file mode 100644 index 76ce6508d7..0000000000 --- a/spec/unit/knife/cookbook_site_download_spec.rb +++ /dev/null @@ -1,151 +0,0 @@ -# -# Author:: Thomas Bishop (<bishop.thomas@gmail.com>) -# Copyright:: Copyright (c) 2012 Thomas Bishop -# 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 File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') - -describe Chef::Knife::CookbookSiteDownload do - - describe 'run' do - before do - @knife = Chef::Knife::CookbookSiteDownload.new - @knife.name_args = ['apache2'] - @noauth_rest = double('no auth rest') - @stderr = StringIO.new - @cookbook_api_url = 'https://supermarket.getchef.com/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' } - - @knife.ui.stub(:stderr).and_return(@stderr) - @knife.stub(:noauth_rest).and_return(@noauth_rest) - @noauth_rest.should_receive(:get_rest). - with("#{@cookbook_api_url}/apache2"). - and_return(@current_data) - end - - context 'when the cookbook is deprecated and not forced' do - before do - @current_data['deprecated'] = true - end - - it 'should warn with info about the replacement' do - @knife.ui.should_receive(:warn). - with(/.+deprecated.+replaced by other_apache2.+/i) - @knife.ui.should_receive(:warn). - with(/use --force.+download.+/i) - @knife.run - end - end - - 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" ) - @file = File.join(Dir.pwd, "apache2-#{@version}.tar.gz") - - @noauth_rest.should_receive(:sign_on_redirect=).with(false) - end - - context 'downloading the latest version' do - before do - @noauth_rest.should_receive(:get_rest). - with(@current_data['latest_version']). - and_return(@cookbook_data) - @noauth_rest.should_receive(:get_rest). - with(@cookbook_data['file'], true). - and_return(@temp_file) - end - - context 'and it is deprecated and with --force' do - before do - @current_data['deprecated'] = true - @knife.config[:force] = true - end - - it 'should download the latest version' do - @knife.ui.should_receive(:warn). - with(/.+deprecated.+replaced by other_apache2.+/i) - FileUtils.should_receive(:cp).with(@temp_file.path, @file) - @knife.run - @stderr.string.should match /downloading apache2.+version.+#{Regexp.escape(@version)}/i - @stderr.string.should match /cookbook save.+#{Regexp.escape(@file)}/i - end - - end - - it 'should download the latest version' do - FileUtils.should_receive(:cp).with(@temp_file.path, @file) - @knife.run - @stderr.string.should match /downloading apache2.+version.+#{Regexp.escape(@version)}/i - @stderr.string.should match /cookbook save.+#{Regexp.escape(@file)}/i - end - - context 'with -f or --file' do - before do - @file = '/opt/chef/cookbooks/apache2.tar.gz' - @knife.config[:file] = @file - FileUtils.should_receive(:cp).with(@temp_file.path, @file) - end - - it 'should download the cookbook to the desired file' do - @knife.run - @stderr.string.should match /downloading apache2.+version.+#{Regexp.escape(@version)}/i - @stderr.string.should match /cookbook save.+#{Regexp.escape(@file)}/i - end - end - - it 'should provide an accessor to the version' do - FileUtils.stub(:cp).and_return(true) - @knife.version.should == @version - @knife.run - end - end - - 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" } - @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 - @noauth_rest.should_receive(:get_rest). - with("#{@cookbook_api_url}/apache2/versions/#{@version_us}"). - and_return(@cookbook_data) - @noauth_rest.should_receive(:get_rest). - with(@cookbook_data['file'], true). - and_return(@temp_file) - FileUtils.should_receive(:cp).with(@temp_file.path, @file) - @knife.run - @stderr.string.should match /downloading apache2.+version.+#{Regexp.escape(@version)}/i - @stderr.string.should match /cookbook save.+#{Regexp.escape(@file)}/i - end - end - - end - - end - -end diff --git a/spec/unit/knife/cookbook_site_install_spec.rb b/spec/unit/knife/cookbook_site_install_spec.rb deleted file mode 100644 index ff87a81b49..0000000000 --- a/spec/unit/knife/cookbook_site_install_spec.rb +++ /dev/null @@ -1,150 +0,0 @@ -# -# Author:: Steven Danna (<steve@opscode.com>) -# Copyright:: Copyright (c) 2011 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 File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper")) - -describe Chef::Knife::CookbookSiteInstall do - before(:each) do - require 'chef/knife/core/cookbook_scm_repo' - @stdout = StringIO.new - @knife = Chef::Knife::CookbookSiteInstall.new - @knife.ui.stub(:stdout).and_return(@stdout) - @knife.config = {} - if Chef::Platform.windows? - @install_path = 'C:/tmp/chef' - else - @install_path = '/var/tmp/chef' - end - @knife.config[:cookbook_path] = [ @install_path ] - - @stdout = StringIO.new - @stderr = StringIO.new - @knife.stub(:stderr).and_return(@stdout) - @knife.stub(:stdout).and_return(@stdout) - - #Assume all external commands would have succeed. :( - File.stub(:unlink) - File.stub(:rmtree) - @knife.stub(:shell_out!).and_return(true) - - #CookbookSiteDownload Stup - @downloader = {} - @knife.stub(:download_cookbook_to).and_return(@downloader) - @downloader.stub(:version).and_return do - if @knife.name_args.size == 2 - @knife.name_args[1] - else - "0.3.0" - end - end - - #Stubs for CookbookSCMRepo - @repo = double(:sanity_check => true, :reset_to_default_state => true, - :prepare_to_import => true, :finalize_updates_to => true, - :merge_updates_from => true) - Chef::Knife::CookbookSCMRepo.stub(:new).and_return(@repo) - end - - - describe "run" do - it "should return an error if a cookbook name is not provided" do - @knife.name_args = [] - @knife.ui.should_receive(:error).with("Please specify a cookbook to download and install.") - lambda { @knife.run }.should raise_error(SystemExit) - end - - it "should return an error if more than two arguments are given" do - @knife.name_args = ["foo", "bar", "baz"] - @knife.ui.should_receive(:error).with("Installing multiple cookbooks at once is not supported.") - lambda { @knife.run }.should raise_error(SystemExit) - end - - it "should return an error if the second argument is not a version" do - @knife.name_args = ["getting-started", "1pass"] - @knife.ui.should_receive(:error).with("Installing multiple cookbooks at once is not supported.") - lambda { @knife.run }.should raise_error(SystemExit) - end - - it "should return an error if the second argument is a four-digit version" do - @knife.name_args = ["getting-started", "0.0.0.1"] - @knife.ui.should_receive(:error).with("Installing multiple cookbooks at once is not supported.") - lambda { @knife.run }.should raise_error(SystemExit) - end - - it "should return an error if the second argument is a one-digit version" do - @knife.name_args = ["getting-started", "1"] - @knife.ui.should_receive(:error).with("Installing multiple cookbooks at once is not supported.") - lambda { @knife.run }.should raise_error(SystemExit) - end - - it "should install the specified version if second argument is a three-digit version" do - @knife.name_args = ["getting-started", "0.1.0"] - @knife.config[:no_deps] = true - upstream_file = File.join(@install_path, "getting-started.tar.gz") - @knife.should_receive(:download_cookbook_to).with(upstream_file) - @knife.should_receive(:extract_cookbook).with(upstream_file, "0.1.0") - @knife.should_receive(:clear_existing_files).with(File.join(@install_path, "getting-started")) - @repo.should_receive(:merge_updates_from).with("getting-started", "0.1.0") - @knife.run - end - - it "should install the specified version if second argument is a two-digit version" do - @knife.name_args = ["getting-started", "0.1"] - @knife.config[:no_deps] = true - upstream_file = File.join(@install_path, "getting-started.tar.gz") - @knife.should_receive(:download_cookbook_to).with(upstream_file) - @knife.should_receive(:extract_cookbook).with(upstream_file, "0.1") - @knife.should_receive(:clear_existing_files).with(File.join(@install_path, "getting-started")) - @repo.should_receive(:merge_updates_from).with("getting-started", "0.1") - @knife.run - end - - it "should install the latest version if only a cookbook name is given" do - @knife.name_args = ["getting-started"] - @knife.config[:no_deps] = true - upstream_file = File.join(@install_path, "getting-started.tar.gz") - @knife.should_receive(:download_cookbook_to).with(upstream_file) - @knife.should_receive(:extract_cookbook).with(upstream_file, "0.3.0") - @knife.should_receive(:clear_existing_files).with(File.join(@install_path, "getting-started")) - @repo.should_receive(:merge_updates_from).with("getting-started", "0.3.0") - @knife.run - end - - it "should not create/reset git branches if use_current_branch is set" do - @knife.name_args = ["getting-started"] - @knife.config[:use_current_branch] = true - @knife.config[:no_deps] = true - upstream_file = File.join(@install_path, "getting-started.tar.gz") - @repo.should_not_receive(:prepare_to_import) - @repo.should_not_receive(:reset_to_default_state) - @knife.run - end - - it "should not raise an error if cookbook_path is a string" do - @knife.config[:cookbook_path] = @install_path - @knife.config[:no_deps] = true - @knife.name_args = ["getting-started"] - upstream_file = File.join(@install_path, "getting-started.tar.gz") - @knife.should_receive(:download_cookbook_to).with(upstream_file) - @knife.should_receive(:extract_cookbook).with(upstream_file, "0.3.0") - @knife.should_receive(:clear_existing_files).with(File.join(@install_path, "getting-started")) - @repo.should_receive(:merge_updates_from).with("getting-started", "0.3.0") - lambda { @knife.run }.should_not raise_error - end - end -end diff --git a/spec/unit/knife/cookbook_site_share_spec.rb b/spec/unit/knife/cookbook_site_share_spec.rb deleted file mode 100644 index 902e5f6115..0000000000 --- a/spec/unit/knife/cookbook_site_share_spec.rb +++ /dev/null @@ -1,146 +0,0 @@ -# -# Author:: Stephen Delano (<stephen@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. -# - -require 'spec_helper' - -require 'chef/cookbook_uploader' -require 'chef/cookbook_site_streaming_uploader' - -describe Chef::Knife::CookbookSiteShare do - - before(:each) do - @knife = Chef::Knife::CookbookSiteShare.new - @knife.name_args = ['cookbook_name', 'AwesomeSausage'] - - @cookbook = Chef::CookbookVersion.new('cookbook_name') - - @cookbook_loader = double('Chef::CookbookLoader') - @cookbook_loader.stub(:cookbook_exists?).and_return(true) - @cookbook_loader.stub(:[]).and_return(@cookbook) - Chef::CookbookLoader.stub(:new).and_return(@cookbook_loader) - - @cookbook_uploader = Chef::CookbookUploader.new('herpderp', :rest => "norest") - Chef::CookbookUploader.stub(:new).and_return(@cookbook_uploader) - @cookbook_uploader.stub(:validate_cookbooks).and_return(true) - Chef::CookbookSiteStreamingUploader.stub(:create_build_dir).and_return(Dir.mktmpdir) - - @knife.stub(:shell_out!).and_return(true) - @stdout = StringIO.new - @knife.ui.stub(:stdout).and_return(@stdout) - end - - describe 'run' do - - before(:each) do - @knife.stub(:do_upload).and_return(true) - end - - it 'should should print usage and exit when given no arguments' do - @knife.name_args = [] - @knife.should_receive(:show_usage) - @knife.ui.should_receive(:fatal) - lambda { @knife.run }.should raise_error(SystemExit) - end - - it 'should print usage and exit when given only 1 argument' do - @knife.name_args = ['cookbook_name'] - @knife.should_receive(:show_usage) - @knife.ui.should_receive(:fatal) - lambda { @knife.run }.should raise_error(SystemExit) - end - - it 'should check if the cookbook exists' do - @cookbook_loader.should_receive(:cookbook_exists?) - @knife.run - end - - it "should exit and log to error if the cookbook doesn't exist" do - @cookbook_loader.stub(:cookbook_exists?).and_return(false) - @knife.ui.should_receive(:error) - lambda { @knife.run }.should raise_error(SystemExit) - end - - it 'should make a tarball of the cookbook' do - @knife.should_receive(:shell_out!) do |args| - args.to_s.should match(/tar -czf/) - end - @knife.run - end - - it 'should exit and log to error when the tarball creation fails' do - @knife.stub(:shell_out!).and_raise(Chef::Exceptions::Exec) - @knife.ui.should_receive(:error) - lambda { @knife.run }.should raise_error(SystemExit) - end - - it 'should upload the cookbook and clean up the tarball' do - @knife.should_receive(:do_upload) - FileUtils.should_receive(:rm_rf) - @knife.run - end - end - - describe 'do_upload' do - - before(:each) do - @upload_response = double('Net::HTTPResponse') - Chef::CookbookSiteStreamingUploader.stub(:post).and_return(@upload_response) - - @stdout = StringIO.new - @stderr = StringIO.new - @knife.ui.stub(:stdout).and_return(@stdout) - @knife.ui.stub(:stderr).and_return(@stderr) - File.stub(:open).and_return(true) - end - - it 'should post the cookbook to "https://supermarket.getchef.com"' do - response_text = {:uri => 'https://supermarket.getchef.com/cookbooks/cookbook_name'}.to_json - @upload_response.stub(:body).and_return(response_text) - @upload_response.stub(:code).and_return(201) - Chef::CookbookSiteStreamingUploader.should_receive(:post).with(/supermarket\.getchef\.com/, anything(), anything(), anything()) - @knife.run - end - - it 'should alert the user when a version already exists' do - response_text = {:error_messages => ['Version already exists']}.to_json - @upload_response.stub(:body).and_return(response_text) - @upload_response.stub(:code).and_return(409) - lambda { @knife.run }.should raise_error(SystemExit) - @stderr.string.should match(/ERROR(.+)cookbook already exists/) - end - - it 'should pass any errors on to the user' do - response_text = {:error_messages => ["You're holding it wrong"]}.to_json - @upload_response.stub(:body).and_return(response_text) - @upload_response.stub(:code).and_return(403) - lambda { @knife.run }.should raise_error(SystemExit) - @stderr.string.should match("ERROR(.*)You're holding it wrong") - end - - it 'should print the body if no errors are exposed on failure' do - response_text = {:system_error => "Your call was dropped", :reason => "There's a map for that"}.to_json - @upload_response.stub(:body).and_return(response_text) - @upload_response.stub(:code).and_return(500) - @knife.ui.should_receive(:error).with(/#{Regexp.escape(response_text)}/)#.ordered - @knife.ui.should_receive(:error).with(/Unknown error/)#.ordered - lambda { @knife.run }.should raise_error(SystemExit) - end - - end - -end diff --git a/spec/unit/knife/cookbook_site_unshare_spec.rb b/spec/unit/knife/cookbook_site_unshare_spec.rb deleted file mode 100644 index 14cda65b43..0000000000 --- a/spec/unit/knife/cookbook_site_unshare_spec.rb +++ /dev/null @@ -1,77 +0,0 @@ -# -# Author:: Stephen Delano (<stephen@opscode.com>) -# Author:: Tim Hinderliter (<tim@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. -# - -require 'spec_helper' - -describe Chef::Knife::CookbookSiteUnshare do - - before(:each) do - @knife = Chef::Knife::CookbookSiteUnshare.new - @knife.name_args = ['cookbook_name'] - @knife.stub(:confirm).and_return(true) - - @rest = double('Chef::REST') - @rest.stub(:delete_rest).and_return(true) - @knife.stub(:rest).and_return(@rest) - @stdout = StringIO.new - @knife.ui.stub(:stdout).and_return(@stdout) - end - - describe 'run' do - - describe 'with no cookbook argument' do - it 'should print the usage and exit' do - @knife.name_args = [] - @knife.ui.should_receive(:fatal) - @knife.should_receive(:show_usage) - lambda { @knife.run }.should raise_error(SystemExit) - end - end - - it 'should confirm you want to unshare the cookbook' do - @knife.should_receive(:confirm) - @knife.run - end - - it 'should send a delete request to the cookbook site' do - @rest.should_receive(:delete_rest) - @knife.run - end - - it 'should log an error and exit when forbidden' do - exception = double('403 "Forbidden"', :code => '403') - @rest.stub(:delete_rest).and_raise(Net::HTTPServerException.new('403 "Forbidden"', exception)) - @knife.ui.should_receive(:error) - lambda { @knife.run }.should raise_error(SystemExit) - end - - it 'should re-raise any non-forbidden errors on delete_rest' do - exception = double('500 "Application Error"', :code => '500') - @rest.stub(:delete_rest).and_raise(Net::HTTPServerException.new('500 "Application Error"', exception)) - lambda { @knife.run }.should raise_error(Net::HTTPServerException) - end - - it 'should log a success message' do - @knife.ui.should_receive(:info) - @knife.run - end - - end - -end diff --git a/spec/unit/knife/cookbook_test_spec.rb b/spec/unit/knife/cookbook_test_spec.rb deleted file mode 100644 index 0e261c02a4..0000000000 --- a/spec/unit/knife/cookbook_test_spec.rb +++ /dev/null @@ -1,84 +0,0 @@ -# -# Author:: Stephen Delano (<stephen@opscode.com>)$ -# Author:: Matthew Kent (<mkent@magoazul.com>) -# Copyright:: Copyright (c) 2010 Opscode, Inc.$ -# Copyright:: Copyright (c) 2010 Matthew Kent -# 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::CookbookTest.load_deps - -describe Chef::Knife::CookbookTest do - before(:each) do - Chef::Config[:node_name] = "webmonkey.example.com" - @knife = Chef::Knife::CookbookTest.new - @knife.config[:cookbook_path] = File.join(CHEF_SPEC_DATA,'cookbooks') - @knife.cookbook_loader.stub(:cookbook_exists?).and_return(true) - @cookbooks = [] - %w{tats central_market jimmy_johns pho}.each do |cookbook_name| - @cookbooks << Chef::CookbookVersion.new(cookbook_name) - end - @stdout = StringIO.new - @knife.ui.stub(:stdout).and_return(@stdout) - end - - describe "run" do - it "should test the cookbook" do - @knife.stub(:test_cookbook).and_return(true) - @knife.name_args = ["italian"] - @knife.should_receive(:test_cookbook).with("italian") - @knife.run - end - - it "should test multiple cookbooks when provided" do - @knife.stub(:test_cookbook).and_return(true) - @knife.name_args = ["tats", "jimmy_johns"] - @knife.should_receive(:test_cookbook).with("tats") - @knife.should_receive(:test_cookbook).with("jimmy_johns") - @knife.should_not_receive(:test_cookbook).with("central_market") - @knife.should_not_receive(:test_cookbook).with("pho") - @knife.run - end - - it "should test both ruby and templates" do - @knife.name_args = ["example"] - @knife.config[:cookbook_path].should_not be_empty - Array(@knife.config[:cookbook_path]).reverse.each do |path| - @knife.should_receive(:test_ruby).with(an_instance_of(Chef::Cookbook::SyntaxCheck)) - @knife.should_receive(:test_templates).with(an_instance_of(Chef::Cookbook::SyntaxCheck)) - end - @knife.run - end - - describe "with -a or --all" do - it "should test all of the cookbooks" do - @knife.stub(:test_cookbook).and_return(true) - @knife.config[:all] = true - @loader = {} - @loader.stub(:load_cookbooks).and_return(@loader) - @cookbooks.each do |cookbook| - @loader[cookbook.name] = cookbook - end - @knife.stub(:cookbook_loader).and_return(@loader) - @loader.each do |key, cookbook| - @knife.should_receive(:test_cookbook).with(cookbook.name) - end - @knife.run - end - end - - end -end diff --git a/spec/unit/knife/cookbook_upload_spec.rb b/spec/unit/knife/cookbook_upload_spec.rb deleted file mode 100644 index e5c9a40cf1..0000000000 --- a/spec/unit/knife/cookbook_upload_spec.rb +++ /dev/null @@ -1,295 +0,0 @@ -# -# Author:: Matthew Kent (<mkent@magoazul.com>) -# Author:: Steven Danna (<steve@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 File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper")) - -require 'chef/cookbook_uploader' -require 'timeout' - -describe Chef::Knife::CookbookUpload do - let(:cookbook) { Chef::CookbookVersion.new('test_cookbook', '/tmp/blah.txt') } - - let(:cookbooks_by_name) do - {cookbook.name => cookbook} - end - - let(:cookbook_loader) do - cookbook_loader = cookbooks_by_name.dup - cookbook_loader.stub(:merged_cookbooks).and_return([]) - cookbook_loader.stub(:load_cookbooks).and_return(cookbook_loader) - cookbook_loader - end - - let(:cookbook_uploader) { double(:upload_cookbooks => nil) } - - let(:output) { StringIO.new } - - let(:name_args) { ['test_cookbook'] } - - let(:knife) do - k = Chef::Knife::CookbookUpload.new - k.name_args = name_args - k.ui.stub(:stdout).and_return(output) - k.ui.stub(:stderr).and_return(output) - k - end - - before(:each) do - Chef::CookbookLoader.stub(:new).and_return(cookbook_loader) - end - - describe 'with --concurrency' do - it 'should upload cookbooks with predefined concurrency' do - Chef::CookbookVersion.stub(:list_all_versions).and_return({}) - knife.config[:concurrency] = 3 - test_cookbook = Chef::CookbookVersion.new('test_cookbook', '/tmp/blah') - cookbook_loader.stub(:each).and_yield("test_cookbook", test_cookbook) - cookbook_loader.stub(:cookbook_names).and_return(["test_cookbook"]) - Chef::CookbookUploader.should_receive(:new). - with( kind_of(Array), { :force => nil, :concurrency => 3}). - and_return(double("Chef::CookbookUploader", :upload_cookbooks=> true)) - knife.run - end - end - - describe 'run' do - before(:each) do - Chef::CookbookUploader.stub(:new => cookbook_uploader) - Chef::CookbookVersion.stub(:list_all_versions).and_return({}) - end - - it 'should print usage and exit when a cookbook name is not provided' do - knife.name_args = [] - knife.should_receive(:show_usage) - knife.ui.should_receive(:fatal) - lambda { knife.run }.should raise_error(SystemExit) - end - - describe 'when specifying a cookbook name' do - it 'should upload the cookbook' do - knife.should_receive(:upload).once - knife.run - end - - it 'should report on success' do - knife.should_receive(:upload).once - knife.ui.should_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'] - knife.should_receive(:upload).once - knife.run - end - end - - context "when uploading a cookbook that uses deprecated overlays" do - - before do - cookbook_loader.stub(:merged_cookbooks).and_return(['test_cookbook']) - cookbook_loader.stub(:merged_cookbook_paths). - and_return({'test_cookbook' => %w{/path/one/test_cookbook /path/two/test_cookbook}}) - end - - it "emits a warning" do - knife.run - 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. - -IMPORTANT: In a future version of Chef, this behavior will be removed and you will no longer -be able to have the same version of a cookbook in multiple places in your cookbook_path. -WARNING: The affected cookbooks are located: -test_cookbook: - /path/one/test_cookbook - /path/two/test_cookbook -E - output.string.should include(expected_message) - end - end - - 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') - } - end - - it "should read only one cookbook" do - cookbook_loader.should_receive(:[]).once.with('test_cookbook1').and_call_original - knife.run - end - - it "should not read all cookbooks" do - cookbook_loader.should_not_receive(:load_cookbooks) - knife.run - end - - it "should upload only one cookbook" do - knife.should_receive(:upload).exactly(1).times - knife.run - end - end - - # This is testing too much. We should break it up. - describe 'when specifying a cookbook name with dependencies' do - let(:name_args) { ["test_cookbook2"] } - - let(:cookbooks_by_name) do - { "test_cookbook1" => test_cookbook1, - "test_cookbook2" => test_cookbook2, - "test_cookbook3" => test_cookbook3 } - end - - let(:test_cookbook1) { Chef::CookbookVersion.new('test_cookbook1', '/tmp/blah') } - - let(:test_cookbook2) do - c = Chef::CookbookVersion.new('test_cookbook2') - c.metadata.depends("test_cookbook3") - c - end - - let(:test_cookbook3) do - c = Chef::CookbookVersion.new('test_cookbook3') - c.metadata.depends("test_cookbook1") - c.metadata.depends("test_cookbook2") - c - end - - it "should upload all dependencies once" do - knife.config[:depends] = true - knife.stub(:cookbook_names).and_return(["test_cookbook1", "test_cookbook2", "test_cookbook3"]) - knife.should_receive(:upload).exactly(3).times - lambda do - Timeout::timeout(5) do - knife.run - end - end.should_not raise_error - end - end - - 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") - cookbook_loader.stub(:[]) do |ckbk| - { "test_cookbook" => cookbook, - "dependency" => cookbook_dependency}[ckbk] - end - knife.stub(: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 - cookbook_loader.should_receive(:[]).once.with('test_cookbook') - cookbook_loader.should_not_receive(:load_cookbooks) - cookbook_uploader.should_not_receive(:upload_cookbooks) - 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) - @stderr.string.should include('Cookbook test_cookbook depends on cookbooks which are not currently') - @stderr.string.should include('being uploaded and cannot be found on the server.') - @stderr.string.should 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') - cookbook.metadata.depends("dependency2") - cookbook_loader.stub(:[]) do |ckbk| - { "test_cookbook" => cookbook, - "dependency" => cookbook_dependency, - "dependency2" => cookbook_dependency2}[ckbk] - end - knife.stub(:cookbook_names).and_return(["dependency", "dependency2", "test_cookbook"]) - expect {knife.run}.to raise_error(SystemExit) - @stderr.string.should include('Cookbook test_cookbook depends on cookbooks which are not currently') - @stderr.string.should include('being uploaded and cannot be found on the server.') - @stderr.string.should include("The missing cookbook(s) are:") - @stderr.string.should include("'dependency' version '>= 0.0.0'") - @stderr.string.should include("'dependency2' version '>= 0.0.0'") - end - end - - it "should freeze the version of the cookbooks if --freeze is specified" do - knife.config[:freeze] = true - cookbook.should_receive(:freeze_version).once - knife.run - end - - describe 'with -a or --all' do - before(:each) do - knife.config[:all] = true - @test_cookbook1 = Chef::CookbookVersion.new('test_cookbook1', '/tmp/blah') - @test_cookbook2 = Chef::CookbookVersion.new('test_cookbook2', '/tmp/blah') - cookbook_loader.stub(:each).and_yield("test_cookbook1", @test_cookbook1).and_yield("test_cookbook2", @test_cookbook2) - cookbook_loader.stub(:cookbook_names).and_return(["test_cookbook1", "test_cookbook2"]) - end - - it 'should upload all cookbooks' do - knife.should_receive(:upload).once - knife.run - end - - it 'should report on success' do - knife.should_receive(:upload).once - knife.ui.should_receive(:info).with(/Uploaded all cookbooks/) - knife.run - end - - it 'should update the version constraints for an environment' do - knife.stub(:assert_environment_valid!).and_return(true) - knife.config[:environment] = "production" - knife.should_receive(:update_version_constraints).once - knife.run - end - end - - describe 'when a frozen cookbook exists on the server' do - it 'should fail to replace it' do - exception = Chef::Exceptions::CookbookFrozen.new - cookbook_uploader.should_receive(:upload_cookbooks). - and_raise(exception) - knife.ui.stub(:error) - knife.ui.should_receive(:error).with(exception) - lambda { knife.run }.should raise_error(SystemExit) - end - - it 'should not update the version constraints for an environment' do - knife.stub(:assert_environment_valid!).and_return(true) - knife.config[:environment] = "production" - knife.stub(:upload).and_raise(Chef::Exceptions::CookbookFrozen) - knife.ui.should_receive(:error).with(/Failed to upload 1 cookbook/) - knife.ui.should_receive(:warn).with(/Not updating version constraints/) - knife.should_not_receive(:update_version_constraints) - lambda { knife.run }.should raise_error(SystemExit) - end - end - end # run -end diff --git a/spec/unit/knife/core/bootstrap_context_spec.rb b/spec/unit/knife/core/bootstrap_context_spec.rb deleted file mode 100644 index 266991a7dd..0000000000 --- a/spec/unit/knife/core/bootstrap_context_spec.rb +++ /dev/null @@ -1,208 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@opscode.com>) -# Copyright:: Copyright (c) 2011 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/knife/core/bootstrap_context' - -describe Chef::Knife::Core::BootstrapContext do - let(:config) { {:foo => :bar} } - 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' - } - end - - let(:secret) { nil } - - subject(:bootstrap_context) { described_class.new(config, run_list, chef_config, secret) } - - it "runs chef with the first-boot.json in the _default environment" do - bootstrap_context.start_chef.should eq "chef-client -j /etc/chef/first-boot.json -E _default" - end - - describe "when in verbosity mode" do - let(:config) { {:verbosity => 2} } - it "adds '-l debug' when verbosity is >= 2" do - bootstrap_context.start_chef.should eq "chef-client -j /etc/chef/first-boot.json -l debug -E _default" - end - end - - it "reads the validation key" do - bootstrap_context.validation_key.should eq IO.read(File.join(CHEF_SPEC_DATA, 'ssl', 'private_key.pem')) - end - - it "generates the config file data" do - expected=<<-EXPECTED -log_location STDOUT -chef_server_url "http://chef.example.com:4444" -validation_client_name "chef-validator-testing" -# Using default node name (fqdn) -EXPECTED - bootstrap_context.config_content.should eq expected - end - - it "does not set a default log_level" do - expect(bootstrap_context.config_content).not_to match(/log_level/) - end - - describe "alternate chef-client path" do - let(:chef_config){ {:chef_client_path => '/usr/local/bin/chef-client'} } - it "runs chef-client from another path when specified" do - bootstrap_context.start_chef.should eq "/usr/local/bin/chef-client -j /etc/chef/first-boot.json -E _default" - end - end - - describe "validation key path that contains a ~" do - let(:chef_config){ {:validation_key => '~/my.key'} } - it "reads the validation key when it contains a ~" do - IO.should_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' }} - it "sets the node name in the client.rb" do - bootstrap_context.config_content.should match(/node_name "foobar\.example\.com"/) - end - end - - describe "when bootstrapping into a specific environment" do - let(:chef_config){ {:environment => "prodtastic"} } - it "starts chef in the configured environment" do - bootstrap_context.start_chef.should == 'chef-client -j /etc/chef/first-boot.json -E prodtastic' - end - end - - describe "when JSON attributes are given" do - let(:config) { {:first_boot_attributes => {:baz => :quux}} } - it "adds the attributes to first_boot" do - bootstrap_context.first_boot.to_json.should eq({:baz => :quux, :run_list => run_list}.to_json) - end - end - - describe "when JSON attributes are NOT given" do - it "sets first_boot equal to run_list" do - bootstrap_context.first_boot.to_json.should eq({:run_list => run_list}.to_json) - end - end - - describe "when an encrypted_data_bag_secret is provided" do - let(:secret) { "supersekret" } - it "reads the encrypted_data_bag_secret" do - bootstrap_context.encrypted_data_bag_secret.should eq "supersekret" - end - end - - describe "to support compatibility with existing templates" do - it "sets the @config instance variable" do - bootstrap_context.instance_variable_get(:@config).should eq config - end - - it "sets the @run_list instance variable" do - bootstrap_context.instance_variable_get(:@run_list).should eq run_list - end - end - - describe "when a bootstrap_version is specified" do - let(:chef_config) do - { - :knife => {:bootstrap_version => "11.12.4" } - } - end - - it "should send the full version to the installer" do - bootstrap_context.latest_current_chef_version_string.should eq("-v 11.12.4") - end - end - - describe "when a pre-release bootstrap_version is specified" do - let(:chef_config) do - { - :knife => {:bootstrap_version => "11.12.4.rc.0" } - } - end - - it "should send the full version to the installer and set the pre-release flag" do - bootstrap_context.latest_current_chef_version_string.should eq("-v 11.12.4.rc.0 -p") - end - end - - describe "when a bootstrap_version is not specified" do - it "should send the latest current to the installer" do - # Intentionally hard coded in order not to replicate the logic. - bootstrap_context.latest_current_chef_version_string.should eq("-v #{Chef::VERSION.to_i}") - end - end - - describe "ssl_verify_mode" do - it "isn't set in the config_content by default" do - bootstrap_context.config_content.should_not include("ssl_verify_mode") - end - - describe "when configured in config" do - let(:chef_config) do - { - :knife => {:ssl_verify_mode => :verify_peer} - } - end - - it "uses the config value" do - bootstrap_context.config_content.should include("ssl_verify_mode :verify_peer") - end - - describe "when configured via CLI" do - let(:config) {{:node_ssl_verify_mode => "none"}} - - it "uses CLI value" do - bootstrap_context.config_content.should include("ssl_verify_mode :verify_none") - end - end - end - end - - describe "verify_api_cert" do - it "isn't set in the config_content by default" do - bootstrap_context.config_content.should_not include("verify_api_cert") - end - - describe "when configured in config" do - let(:chef_config) do - { - :knife => {:verify_api_cert => :false} - } - end - - it "uses the config value" do - bootstrap_context.config_content.should include("verify_api_cert false") - end - - describe "when configured via CLI" do - let(:config) {{:node_verify_api_cert => true}} - - it "uses CLI value" do - bootstrap_context.config_content.should include("verify_api_cert true") - end - end - end - end - -end diff --git a/spec/unit/knife/core/cookbook_scm_repo_spec.rb b/spec/unit/knife/core/cookbook_scm_repo_spec.rb deleted file mode 100644 index 69da5400b0..0000000000 --- a/spec/unit/knife/core/cookbook_scm_repo_spec.rb +++ /dev/null @@ -1,187 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@opscode.com>) -# Copyright:: Copyright (c) 2011 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/knife/core/cookbook_scm_repo' - -describe Chef::Knife::CookbookSCMRepo do - before do - @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') - - @branch_list = Mixlib::ShellOut.new - @branch_list.stdout.replace(<<-BRANCHES) - chef-vendor-apache2 - chef-vendor-build-essential - chef-vendor-dynomite - chef-vendor-ganglia - chef-vendor-graphite - chef-vendor-python - chef-vendor-absent-new -BRANCHES - end - - it "has a path to the cookbook repo" do - @cookbook_repo.repo_path.should == @repo_path - end - - it "has a default branch" do - @cookbook_repo.default_branch.should == 'master' - end - - describe "when sanity checking the repo" do - it "exits when the directory does not exist" do - ::File.should_receive(:directory?).with(@repo_path).and_return(false) - lambda {@cookbook_repo.sanity_check}.should raise_error(SystemExit) - end - - describe "and the repo dir exists" do - before do - ::File.stub(:directory?).with(@repo_path).and_return(true) - end - - it "exits when there is no git repo" do - ::File.stub(:directory?).with(/.*\.git/).and_return(false) - lambda {@cookbook_repo.sanity_check}.should raise_error(SystemExit) - end - - describe "and the repo is a git repo" do - before do - ::File.stub(: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"} - @cookbook_repo.should_receive(:shell_out!).with('git branch --no-color', :cwd => @repo_path).and_return(@nobranches) - lambda {@cookbook_repo.sanity_check}.should raise_error(SystemExit) - end - - describe "and the default branch exists" do - before do - @master_branch = Mixlib::ShellOut.new - @master_branch.stdout.replace "* master\n" - @cookbook_repo.should_receive(:shell_out!).with("git branch --no-color", :cwd => @repo_path).and_return(@master_branch) - end - - it "exits when the git repo is dirty" do - @dirty_status = Mixlib::ShellOut.new - @dirty_status.stdout.replace(<<-DIRTY) - M chef/lib/chef/knife/cookbook_site_vendor.rb -DIRTY - @cookbook_repo.should_receive(:shell_out!).with('git status --porcelain', :cwd => @repo_path).and_return(@dirty_status) - lambda {@cookbook_repo.sanity_check}.should raise_error(SystemExit) - end - - describe "and the repo is clean" do - before do - @clean_status = Mixlib::ShellOut.new.tap {|s| s.stdout.replace("\n")} - @cookbook_repo.stub(:shell_out!).with('git status --porcelain', :cwd => @repo_path).and_return(@clean_status) - end - - it "passes the sanity check" do - @cookbook_repo.sanity_check - end - - end - end - end - end - end - - it "resets to default state by checking out the default branch" do - @cookbook_repo.should_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 - @cookbook_repo.should_receive(:shell_out!).with('git branch --no-color', :cwd => @repo_path).and_return(@branch_list) - @cookbook_repo.branch_exists?("chef-vendor-apache2").should be_true - @cookbook_repo.should_receive(:shell_out!).with('git branch --no-color', :cwd => @repo_path).and_return(@branch_list) - @cookbook_repo.branch_exists?("chef-vendor-nginx").should be_false - end - - it "determines if a the branch not exists correctly without substring search" do - @cookbook_repo.should_receive(:shell_out!).twice.with('git branch --no-color', :cwd => @repo_path).and_return(@branch_list) - @cookbook_repo.should_not be_branch_exists("chef-vendor-absent") - @cookbook_repo.should 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 - @cookbook_repo.should_receive(:shell_out!).with('git branch --no-color', :cwd => @repo_path).and_return(@branch_list) - @cookbook_repo.should_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 - @cookbook_repo.should_receive(:shell_out!).with('git branch --no-color', :cwd => @repo_path).and_return(@branch_list) - @cookbook_repo.should_receive(:shell_out!).with('git checkout chef-vendor-apache2', :cwd => @repo_path) - @cookbook_repo.prepare_to_import("apache2") - end - end - - describe "when the pristine copy branch was not updated by the changes" do - before do - @updates = Mixlib::ShellOut.new - @updates.stdout.replace("\n") - @cookbook_repo.stub(:shell_out!).with('git status --porcelain -- apache2', :cwd => @repo_path).and_return(@updates) - end - - it "shows no changes in the pristine copy" do - @cookbook_repo.updated?('apache2').should be_false - end - - it "does nothing to finalize the updates" do - @cookbook_repo.finalize_updates_to('apache2', '1.2.3').should be_false - end - end - - describe "when the pristine copy branch was updated by the changes" do - before do - @updates = Mixlib::ShellOut.new - @updates.stdout.replace(" M cookbooks/apache2/recipes/default.rb\n") - @cookbook_repo.stub(:shell_out!).with('git status --porcelain -- apache2', :cwd => @repo_path).and_return(@updates) - end - - it "shows changes in the pristine copy" do - @cookbook_repo.updated?('apache2').should be_true - end - - it "commits the changes to the repo and tags the commit" do - @cookbook_repo.should_receive(:shell_out!).with("git add apache2", :cwd => @repo_path) - @cookbook_repo.should_receive(:shell_out!).with("git commit -m \"Import apache2 version 1.2.3\" -- apache2", :cwd => @repo_path) - @cookbook_repo.should_receive(:shell_out!).with("git tag -f cookbook-site-imported-apache2-1.2.3", :cwd => @repo_path) - @cookbook_repo.finalize_updates_to("apache2", "1.2.3").should be_true - end - end - - describe "when a custom default branch is specified" do - before do - @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 - @cookbook_repo.should_receive(:shell_out!).with('git checkout develop', :cwd => @repo_path) - @cookbook_repo.reset_to_default_state - end - end -end diff --git a/spec/unit/knife/core/object_loader_spec.rb b/spec/unit/knife/core/object_loader_spec.rb deleted file mode 100644 index 53a538da91..0000000000 --- a/spec/unit/knife/core/object_loader_spec.rb +++ /dev/null @@ -1,81 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@opscode.com>) -# Author:: Juanje Ojeda (<juanje.ojeda@gmail.com>) -# Copyright:: Copyright (c) 2011-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/knife/core/object_loader' - -describe Chef::Knife::Core::ObjectLoader do - before(:each) do - @knife = Chef::Knife.new - @stdout = StringIO.new - @knife.ui.stub(:stdout).and_return(@stdout) - Dir.chdir(File.join(CHEF_SPEC_DATA, 'object_loader')) - end - - shared_examples_for "Chef object" do |chef_class| - it "should create a #{chef_class} object" do - @object.should be_a_kind_of(chef_class) - end - - it "should has a attribute 'name'" do - @object.name.should eql('test') - end - end - - { - 'nodes' => Chef::Node, - 'roles' => Chef::Role, - 'environments' => Chef::Environment - }.each do |repo_location, chef_class| - - describe "when the file is a #{chef_class}" do - before do - @loader = Chef::Knife::Core::ObjectLoader.new(chef_class, @knife.ui) - end - - describe "when the file is a Ruby" do - before do - @object = @loader.load_from(repo_location, 'test.rb') - end - - it_behaves_like "Chef object", chef_class - end - - #NOTE: This is check for the bug described at CHEF-2352 - 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') - end - - it_behaves_like "Chef object", chef_class - end - - describe "and it has not defined 'json_class'" do - before do - @object = @loader.load_from(repo_location, 'test.json') - end - - it_behaves_like "Chef object", chef_class - end - end - end - end - -end diff --git a/spec/unit/knife/core/subcommand_loader_spec.rb b/spec/unit/knife/core/subcommand_loader_spec.rb deleted file mode 100644 index 53664cb528..0000000000 --- a/spec/unit/knife/core/subcommand_loader_spec.rb +++ /dev/null @@ -1,150 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@opscode.com>) -# Copyright:: Copyright (c) 2011 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::Knife::SubcommandLoader do - before do - Chef::Platform.stub(:windows?) { false } - @home = File.join(CHEF_SPEC_DATA, 'knife-home') - @env = {'HOME' => @home} - @loader = Chef::Knife::SubcommandLoader.new(File.join(CHEF_SPEC_DATA, 'knife-site-subcommands'), @env) - end - - it "builds a list of the core subcommand file require paths" do - @loader.subcommand_files.should_not be_empty - @loader.subcommand_files.each do |require_path| - require_path.should match(/chef\/knife\/.*|plugins\/knife\/.*/) - end - end - - it "finds files installed via rubygems" do - @loader.find_subcommands_via_rubygems.should include('chef/knife/node_create') - @loader.find_subcommands_via_rubygems.each {|rel_path, abs_path| abs_path.should 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' - ] - $LOAD_PATH.should_receive(:map).and_return([]) - if Gem::Specification.respond_to? :latest_specs - Gem::Specification.should_receive(:latest_specs).with(true).and_return(gems) - gems[0].should_receive(:matches_for_glob).with(/chef\/knife\/\*\.rb\{(.*),\.rb,(.*)\}/).and_return(gem_files) - else - Gem.source_index.should_receive(:latest_specs).with(true).and_return(gems) - gems[0].should_receive(:require_paths).twice.and_return(['lib']) - gems[0].should_receive(:full_gem_path).and_return('/usr/lib/ruby/gems/knife-ec2-0.5.12') - Dir.should_receive(:[]).with('/usr/lib/ruby/gems/knife-ec2-0.5.12/lib/chef/knife/*.rb').and_return(gem_files) - end - @loader.should_receive(:find_subcommands_via_dirglob).and_return({}) - @loader.find_subcommands_via_rubygems.values.select { |file| file =~ /knife-ec2/ }.sort.should == gem_files - end - - it "finds files using a dirglob when rubygems is not available" do - @loader.find_subcommands_via_dirglob.should include('chef/knife/node_create') - @loader.find_subcommands_via_dirglob.each {|rel_path, abs_path| abs_path.should 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') - @loader.site_subcommands.should 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') - @loader.site_subcommands.should include(expected_command) - 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 - ENV.stub(:[]).and_return { |key| env_dup[key] } - ENV.stub(:[]).with("HOME").and_return(env_home) - end - - context "when there is not a ~/.chef/plugin_manifest.json file" do - before do - File.stub(:exist?).with(manifest_path).and_return(false) - end - - it "searches rubygems for plugins" do - if Gem::Specification.respond_to?(:latest_specs) - Gem::Specification.should_receive(:latest_specs).and_call_original - else - Gem.source_index.should_receive(:latest_specs).and_call_original - end - @loader.subcommand_files.each do |require_path| - require_path.should match(/chef\/knife\/.*|plugins\/knife\/.*/) - end - end - - context "and HOME environment variable is not set" do - before do - ENV.stub(:[]).with("HOME").and_return(nil) - end - - it "searches rubygems for plugins" do - if Gem::Specification.respond_to?(:latest_specs) - Gem::Specification.should_receive(:latest_specs).and_call_original - else - Gem.source_index.should_receive(:latest_specs).and_call_original - end - @loader.subcommand_files.each do |require_path| - require_path.should match(/chef\/knife\/.*|plugins\/knife\/.*/) - end - end - 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) } - - before do - File.stub(:exist?).with(manifest_path).and_return(true) - File.stub(:read).with(manifest_path).and_return(manifest_json) - end - - it "uses paths from the manifest instead of searching gems" do - Gem::Specification.should_not_receive(:latest_specs).and_call_original - @loader.subcommand_files.should include(ec2_server_create_plugin) - end - - end - end - -end diff --git a/spec/unit/knife/core/ui_spec.rb b/spec/unit/knife/core/ui_spec.rb deleted file mode 100644 index 9044bc2f2f..0000000000 --- a/spec/unit/knife/core/ui_spec.rb +++ /dev/null @@ -1,537 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: Tim Hinderliter (<tim@opscode.com>) -# Author:: Daniel DeLeo (<dan@opscode.com>) -# Author:: John Keiser (<jkeiser@opscode.com>) -# Copyright:: Copyright (c) 2008, 2011, 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::Knife::UI do - before do - @out, @err, @in = StringIO.new, StringIO.new, StringIO.new - @config = { - :verbosity => 0, - :yes => nil, - :format => "summary", - } - @ui = Chef::Knife::UI.new(@out, @err, @in, @config) - end - - describe "edit" do - ruby_for_json = { 'foo' => 'bar' } - json_from_ruby = "{\n \"foo\": \"bar\"\n}" - json_from_editor = "{\n \"bar\": \"foo\"\n}" - ruby_from_editor = { 'bar' => 'foo' } - my_editor = "veeeye" - temp_path = "/tmp/bar/baz" - - let(:subject) { @ui.edit_data(ruby_for_json, parse_output) } - let(:parse_output) { false } - - context "when editing is disabled" do - before do - @ui.config[:disable_editing] = true - stub_const("Tempfile", double) # Tempfiles should never be invoked - end - context "when parse_output is false" do - it "returns pretty json string" do - expect(subject).to eql(json_from_ruby) - end - end - context "when parse_output is true" do - let(:parse_output) { true } - it "returns a ruby object" do - expect(subject).to eql(ruby_for_json) - end - end - - end - - context "when editing is enabled" do - before do - @ui.config[:disable_editing] = false - @ui.config[:editor] = my_editor - @mock = double('Tempfile') - @mock.should_receive(:sync=).with(true) - @mock.should_receive(:puts).with(json_from_ruby) - @mock.should_receive(:close) - @mock.should_receive(:path).at_least(:once).and_return(temp_path) - Tempfile.should_receive(:open).with([ 'knife-edit-', '.json' ]).and_yield(@mock) - end - context "and the editor works" do - before do - @ui.should_receive(:system).with("#{my_editor} #{temp_path}").and_return(true) - IO.should_receive(:read).with(temp_path).and_return(json_from_editor) - end - - context "when parse_output is false" do - it "returns an edited pretty json string" do - expect(subject).to eql(json_from_editor) - end - end - context "when parse_output is true" do - let(:parse_output) { true } - it "returns an edited ruby object" do - expect(subject).to eql(ruby_from_editor) - end - end - end - context "when running the editor fails with nil" do - before do - @ui.should_receive(:system).with("#{my_editor} #{temp_path}").and_return(nil) - IO.should_not_receive(:read) - end - it "throws an exception" do - expect{ subject }.to raise_error(RuntimeError) - end - end - context "when running the editor fails with false" do - before do - @ui.should_receive(:system).with("#{my_editor} #{temp_path}").and_return(false) - IO.should_not_receive(:read) - end - it "throws an exception" do - expect{ subject }.to raise_error(RuntimeError) - end - end - end - context "when editing and not stubbing Tempfile (semi-functional test)" do - before do - @ui.config[:disable_editing] = false - @ui.config[:editor] = my_editor - @tempfile = Tempfile.new([ 'knife-edit-', '.json' ]) - Tempfile.should_receive(:open).with([ 'knife-edit-', '.json' ]).and_yield(@tempfile) - end - - context "and the editor works" do - before do - @ui.should_receive(:system).with("#{my_editor} #{@tempfile.path}").and_return(true) - IO.should_receive(:read).with(@tempfile.path).and_return(json_from_editor) - end - - context "when parse_output is false" do - it "returns an edited pretty json string" do - expect(subject).to eql(json_from_editor) - end - it "the tempfile should have mode 0600", :unix_only do - # XXX: this looks odd because we're really testing Tempfile.new here - expect(File.stat(@tempfile.path).mode & 0777).to eql(0600) - expect(subject).to eql(json_from_editor) - end - end - - context "when parse_output is true" do - let(:parse_output) { true } - it "returns an edited ruby object" do - expect(subject).to eql(ruby_from_editor) - end - it "the tempfile should have mode 0600", :unix_only do - # XXX: this looks odd because we're really testing Tempfile.new here - expect(File.stat(@tempfile.path).mode & 0777).to eql(0600) - expect(subject).to eql(ruby_from_editor) - end - end - end - end - end - - describe "format_list_for_display" do - it "should print the full hash if --with-uri is true" do - @ui.config[:with_uri] = true - @ui.format_list_for_display({ :marcy => :playground }).should == { :marcy => :playground } - end - - it "should print only the keys if --with-uri is false" do - @ui.config[:with_uri] = false - @ui.format_list_for_display({ :marcy => :playground }).should == [ :marcy ] - end - end - - shared_examples "an output mehthod handling IO exceptions" do |method| - it "should throw Errno::EIO exceptions" do - @out.stub(:puts).and_raise(Errno::EIO) - @err.stub(:puts).and_raise(Errno::EIO) - lambda {@ui.send(method, "hi")}.should raise_error(Errno::EIO) - end - - it "should ignore Errno::EPIPE exceptions (CHEF-3516)" do - @out.stub(:puts).and_raise(Errno::EPIPE) - @err.stub(:puts).and_raise(Errno::EPIPE) - lambda {@ui.send(method, "hi")}.should raise_error(SystemExit) - end - - it "should throw Errno::EPIPE exceptions with -VV (CHEF-3516)" do - @config[:verbosity] = 2 - @out.stub(:puts).and_raise(Errno::EPIPE) - @err.stub(:puts).and_raise(Errno::EPIPE) - lambda {@ui.send(method, "hi")}.should raise_error(Errno::EPIPE) - end - end - - describe "output" do - it_behaves_like "an output mehthod handling IO exceptions", :output - - it "formats strings appropriately" do - @ui.output("hi") - @out.string.should == "hi\n" - end - - it "formats hashes appropriately" do - @ui.output({'hi' => 'a', 'lo' => 'b' }) - @out.string.should == <<EOM -hi: a -lo: b -EOM - end - - it "formats empty hashes appropriately" do - @ui.output({}) - @out.string.should == "\n" - end - - it "formats arrays appropriately" do - @ui.output([ 'a', 'b' ]) - @out.string.should == <<EOM -a -b -EOM - end - - it "formats empty arrays appropriately" do - @ui.output([ ]) - @out.string.should == "\n" - end - - it "formats single-member arrays appropriately" do - @ui.output([ 'a' ]) - @out.string.should == "a\n" - end - - it "formats nested single-member arrays appropriately" do - @ui.output([ [ 'a' ] ]) - @out.string.should == "a\n" - end - - it "formats nested arrays appropriately" do - @ui.output([ [ 'a', 'b' ], [ 'c', 'd' ]]) - @out.string.should == <<EOM -a -b - -c -d -EOM - end - - it "formats nested arrays with single- and empty subarrays appropriately" do - @ui.output([ [ 'a', 'b' ], [ 'c' ], [], [ 'd', 'e' ]]) - @out.string.should == <<EOM -a -b - -c - - -d -e -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' }]) - @out.string.should == <<EOM -a: b -c: d - -x: y - -m: n -o: p -EOM - end - - it "formats hashes with empty array members appropriately" do - @ui.output({ 'a' => [], 'b' => 'c' }) - @out.string.should == <<EOM -a: -b: c -EOM - end - - it "formats hashes with single-member array values appropriately" do - @ui.output({ 'a' => [ 'foo' ], 'b' => 'c' }) - @out.string.should == <<EOM -a: foo -b: c -EOM - end - - it "formats hashes with array members appropriately" do - @ui.output({ 'a' => [ 'foo', 'bar' ], 'b' => 'c' }) - @out.string.should == <<EOM -a: - foo - bar -b: c -EOM - end - - it "formats hashes with single-member nested array values appropriately" do - @ui.output({ 'a' => [ [ 'foo' ] ], 'b' => 'c' }) - @out.string.should == <<EOM -a: - foo -b: c -EOM - end - - it "formats hashes with nested array values appropriately" do - @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. - @out.string.should == "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' }) - @out.string.should == <<EOM -a: - aa: bb - cc: dd -b: c -EOM - end - - it "formats hashes with empty hash values appropriately" do - @ui.output({ 'a' => { }, 'b' => 'c' }) - @out.string.should == <<EOM -a: -b: c -EOM - end - end - - describe "warn" do - it_behaves_like "an output mehthod handling IO exceptions", :warn - end - - describe "error" do - it_behaves_like "an output mehthod handling IO exceptions", :warn - end - - describe "fatal" do - it_behaves_like "an output mehthod handling IO exceptions", :warn - end - - describe "format_for_display" do - it "should return the raw data" do - input = { :gi => :go } - @ui.format_for_display(input).should == input - end - - describe "with --attribute passed" do - it "should return the deeply nested attribute" do - input = { "gi" => { "go" => "ge" }, "id" => "sample-data-bag-item" } - @ui.config[:attribute] = "gi.go" - @ui.format_for_display(input).should == { "sample-data-bag-item" => { "gi.go" => "ge" } } - end - - it "should return multiple attributes" do - input = { "gi" => "go", "hi" => "ho", "id" => "sample-data-bag-item" } - @ui.config[:attribute] = ["gi", "hi"] - @ui.format_for_display(input).should == { "sample-data-bag-item" => { "gi" => "go", "hi"=> "ho" } } - end - end - - describe "with --run-list passed" do - it "should return the run list" do - input = Chef::Node.new - input.name("sample-node") - input.run_list("role[monkey]", "role[churchmouse]") - @ui.config[:run_list] = true - response = @ui.format_for_display(input) - response["sample-node"]["run_list"][0].should == "role[monkey]" - response["sample-node"]["run_list"][1].should == "role[churchmouse]" - end - end - end - - describe "format_cookbook_list_for_display" do - before(:each) do - @item = { - "cookbook_name" => { - "url" => "http://url/cookbooks/cookbook", - "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" } - ] - } - } - end - - it "should return an array of the cookbooks with versions" do - expected_response = [ "cookbook_name 3.0.0 2.0.0 1.0.0" ] - response = @ui.format_cookbook_list_for_display(@item) - response.should == expected_response - end - - describe "with --with-uri" do - it "should return the URIs" do - response = { - "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"} - } - @ui.config[:with_uri] = true - @ui.format_cookbook_list_for_display(@item).should == response - end - end - end - - describe "confirm" do - let(:stdout) {StringIO.new} - let(:output) {stdout.string} - - let(:question) { "monkeys rule" } - let(:answer) { 'y' } - - let(:default_choice) { nil } - let(:append_instructions) { true } - - def run_confirm - @ui.stub(:stdout).and_return(stdout) - @ui.stdin.stub(:readline).and_return(answer) - @ui.confirm(question, append_instructions, default_choice) - end - - def run_confirm_without_exit - @ui.stub(:stdout).and_return(stdout) - @ui.stdin.stub(:readline).and_return(answer) - @ui.confirm_without_exit(question, append_instructions, default_choice) - end - - shared_examples_for "confirm with positive answer" do - it "confirm should return true" do - run_confirm.should be_true - end - - it "confirm_without_exit should return true" do - run_confirm_without_exit.should be_true - end - end - - shared_examples_for "confirm with negative answer" do - it "confirm should exit 3" do - lambda { - run_confirm - }.should raise_error(SystemExit) { |e| e.status.should == 3 } - end - - it "confirm_without_exit should return false" do - run_confirm_without_exit.should be_false - end - end - - describe "with default choice set to true" do - let(:default_choice) { true } - - it "should show 'Y/n' in the instructions" do - run_confirm - output.should include("Y/n") - end - - describe "with empty answer" do - let(:answer) { "" } - - it_behaves_like "confirm with positive answer" - end - - describe "with answer N " do - let(:answer) { "N" } - - it_behaves_like "confirm with negative answer" - end - end - - describe "with default choice set to false" do - let(:default_choice) { false } - - it "should show 'y/N' in the instructions" do - run_confirm - output.should include("y/N") - end - - describe "with empty answer" do - let(:answer) { "" } - - it_behaves_like "confirm with negative answer" - end - - describe "with answer N " do - let(:answer) { "Y" } - - it_behaves_like "confirm with positive answer" - end - end - - ["Y", "y"].each do |answer| - describe "with answer #{answer}" do - let(:answer) { answer } - - it_behaves_like "confirm with positive answer" - end - end - - ["N", "n"].each do |answer| - describe "with answer #{answer}" do - let(:answer) { answer } - - it_behaves_like "confirm with negative answer" - end - end - - describe "with --y or --yes passed" do - it "should return true" do - @ui.config[:yes] = true - run_confirm.should be_true - output.should eq("") - end - end - end - - describe "when asking for free-form user input" do - it "asks a question and returns the answer provided by the user" do - out = StringIO.new - @ui.stub(:stdout).and_return(out) - @ui.stub(:stdin).and_return(StringIO.new("http://mychefserver.example.com\n")) - @ui.ask_question("your chef server URL?").should == "http://mychefserver.example.com" - out.string.should == "your chef server URL?" - end - - it "suggests a default setting and returns the default when the user's response only contains whitespace" do - out = StringIO.new - @ui.stub(:stdout).and_return(out) - @ui.stub(:stdin).and_return(StringIO.new(" \n")) - @ui.ask_question("your chef server URL? ", :default => 'http://localhost:4000').should == "http://localhost:4000" - out.string.should == "your chef server URL? [http://localhost:4000] " - end - end - -end diff --git a/spec/unit/knife/data_bag_create_spec.rb b/spec/unit/knife/data_bag_create_spec.rb deleted file mode 100644 index c31c88577d..0000000000 --- a/spec/unit/knife/data_bag_create_spec.rb +++ /dev/null @@ -1,109 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@opscode.com>) -# Author:: Seth Falcon (<seth@opscode.com>) -# Copyright:: Copyright (c) 2009-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. -# - -require 'spec_helper' -require 'tempfile' - -describe Chef::Knife::DataBagCreate do - let(:knife) do - k = Chef::Knife::DataBagCreate.new - allow(k).to receive(:rest).and_return(rest) - allow(k.ui).to receive(:stdout).and_return(stdout) - k - end - - let(:rest) { double("Chef::REST") } - let(:stdout) { StringIO.new } - - let(:bag_name) { "sudoing_admins" } - let(:item_name) { "ME" } - - let(:secret) { "abc123SECRET" } - - let(:raw_hash) {{ "login_name" => "alphaomega", "id" => item_name }} - - let(:config) { {} } - - before do - Chef::Config[:node_name] = "webmonkey.example.com" - knife.name_args = [bag_name, item_name] - allow(knife).to receive(:config).and_return(config) - end - - it "tries to create a data bag with an invalid name when given one argument" do - 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) - end - - context "when given one argument" do - before do - knife.name_args = [bag_name] - end - - it "creates a data bag" do - expect(rest).to receive(:post_rest).with("data", {"name" => bag_name}) - expect(knife.ui).to receive(:info).with("Created data_bag[#{bag_name}]") - - knife.run - end - end - - context "no secret is specified for encryption" do - let(:item) do - item = Chef::DataBagItem.from_hash(raw_hash) - item.data_bag(bag_name) - item - end - - 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 - - knife.run - end - end - - context "a secret is specified for encryption" do - let(:encoded_data) { Chef::EncryptedDataBagItem.encrypt_data_bag_item(raw_hash, secret) } - - let(:item) do - item = Chef::DataBagItem.from_hash(encoded_data) - item.data_bag(bag_name) - item - end - - it "creates an encrypted data bag item" do - expect(knife).to receive(:create_object).and_yield(raw_hash) - expect(knife).to receive(:encryption_secret_provided?).and_return(true) - expect(knife).to receive(:read_secret).and_return(secret) - expect(Chef::EncryptedDataBagItem) - .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 - - knife.run - end - end - -end diff --git a/spec/unit/knife/data_bag_edit_spec.rb b/spec/unit/knife/data_bag_edit_spec.rb deleted file mode 100644 index 6f19b5e63e..0000000000 --- a/spec/unit/knife/data_bag_edit_spec.rb +++ /dev/null @@ -1,127 +0,0 @@ -# -# Author:: Seth Falcon (<seth@opscode.com>) -# Copyright:: Copyright 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. -# - -require 'spec_helper' -require 'tempfile' - -describe Chef::Knife::DataBagEdit do - before do - Chef::Config[:node_name] = "webmonkey.example.com" - knife.name_args = [bag_name, item_name] - allow(knife).to receive(:config).and_return(config) - end - - let(:knife) do - k = Chef::Knife::DataBagEdit.new - allow(k).to receive(:rest).and_return(rest) - allow(k.ui).to receive(:stdout).and_return(stdout) - 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(:rest) { double("Chef::REST") } - let(:stdout) { StringIO.new } - - let(:bag_name) { "sudoing_admins" } - let(:item_name) { "ME" } - - let(:secret) { "abc123SECRET" } - - let(:config) { {} } - - let(:is_encrypted?) { false } - let(:transmitted_hash) { raw_edited_hash } - let(:data_to_edit) { db } - - shared_examples_for "editing a data bag" do - it "correctly edits then uploads the data bag" 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 - - knife.run - end - end - - 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(stdout.string).to eq("") - end - - context "when no secret is provided" do - include_examples "editing a data bag" - end - - context "when config[:print_after] is set" do - let(:config) { {:print_after => true} } - before do - expect(knife.ui).to receive(:output).with(raw_edited_hash) - end - - include_examples "editing a data bag" - end - - context "when a secret is provided" do - let!(:enc_raw_hash) { Chef::EncryptedDataBagItem.encrypt_data_bag_item(raw_hash, secret) } - let!(:enc_edited_hash) { Chef::EncryptedDataBagItem.encrypt_data_bag_item(raw_edited_hash, secret) } - let(:transmitted_hash) { enc_edited_hash } - - before(:each) do - expect(knife).to receive(:read_secret).at_least(1).times.and_return(secret) - expect(Chef::EncryptedDataBagItem).to receive(:encrypt_data_bag_item).with(raw_edited_hash, secret).and_return(enc_edited_hash) - end - - context "the data bag starts encrypted" do - let(:is_encrypted?) { true } - let(:db) { Chef::DataBagItem.from_hash(enc_raw_hash) } - # If the data bag is encrypted, it gets passed to `edit` as a hash. Otherwise, it gets passed as a DataBag - let (:data_to_edit) { raw_hash } - - before(:each) do - expect(knife).to receive(:encryption_secret_provided_ignore_encrypt_flag?).and_return(true) - end - - include_examples "editing a data bag" - end - - context "the data bag starts unencrypted" do - before(:each) do - expect(knife).to receive(:encryption_secret_provided_ignore_encrypt_flag?).exactly(0).times - expect(knife).to receive(:encryption_secret_provided?).and_return(true) - end - - include_examples "editing a data bag" - end - end - - it "fails to edit an encrypted data bag if the secret is missing" 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(true) - 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) - end - -end diff --git a/spec/unit/knife/data_bag_from_file_spec.rb b/spec/unit/knife/data_bag_from_file_spec.rb deleted file mode 100644 index dba5cc282b..0000000000 --- a/spec/unit/knife/data_bag_from_file_spec.rb +++ /dev/null @@ -1,172 +0,0 @@ -# -# Author:: Seth Falcon (<seth@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. -# - -require 'spec_helper' - -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 - Chef::Platform.stub(:windows?) { false } - Chef::Config[:node_name] = "webmonkey.example.com" - FileUtils.mkdir_p([db_folder, db_folder2]) - db_file.write(plain_data.to_json) - db_file.flush - allow(knife).to receive(:config).and_return(config) - allow(Chef::Knife::Core::ObjectLoader).to receive(:new).and_return(loader) - end - - # We have to explicitly clean up Tempfile on Windows because it said so. - after :each do - db_file.close - db_file2.close - db_file3.close - FileUtils.rm_rf(db_folder) - FileUtils.rm_rf(db_folder2) - FileUtils.remove_entry_secure tmp_dir - end - - let(:knife) do - k = Chef::Knife::DataBagFromFile.new - allow(k).to receive(:rest).and_return(rest) - allow(k.ui).to receive(:stdout).and_return(stdout) - k - end - - let(:tmp_dir) { Dir.mktmpdir } - let(:db_folder) { File.join(tmp_dir, data_bags_path, bag_name) } - let(:db_file) { Tempfile.new(["data_bag_from_file_test", ".json"], db_folder) } - let(:db_file2) { Tempfile.new(["data_bag_from_file_test2", ".json"], db_folder) } - let(:db_folder2) { File.join(tmp_dir, data_bags_path, bag_name2) } - let(:db_file3) { Tempfile.new(["data_bag_from_file_test3", ".json"], db_folder2) } - - def new_bag_expects(b = bag_name, d = plain_data) - data_bag = double - expect(data_bag).to receive(:data_bag).with(b) - expect(data_bag).to receive(:raw_data=).with(d) - expect(data_bag).to receive(:save) - expect(data_bag).to receive(:data_bag) - expect(data_bag).to receive(:id) - data_bag - end - - let(:loader) { double("Knife::Core::ObjectLoader") } - - let(:data_bags_path) { "data_bags" } - let(:plain_data) { { - "id" => "item_name", - "greeting" => "hello", - "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(:stdout) { StringIO.new } - - let(:bag_name) { "sudoing_admins" } - let(:bag_name2) { "sudoing_admins2" } - let(:item_name) { "ME" } - - let(:secret) { "abc123SECRET" } - - let(:config) { {} } - - it "loads from a file and saves" do - knife.name_args = [bag_name, db_file.path] - expect(loader).to receive(:load_from).with(data_bags_path, bag_name, db_file.path).and_return(plain_data) - expect(Chef::DataBagItem).to receive(:new).and_return(new_bag_expects) - - knife.run - end - - it "loads all from multiple files and saves" do - knife.name_args = [ bag_name, db_file.path, db_file2.path ] - expect(loader).to receive(:load_from).with(data_bags_path, bag_name, db_file.path).and_return(plain_data) - expect(loader).to receive(:load_from).with(data_bags_path, bag_name, db_file2.path).and_return(plain_data) - expect(Chef::DataBagItem).to receive(:new).twice.and_return(new_bag_expects, new_bag_expects) - - knife.run - end - - it "loads all from a folder and saves" do - knife.name_args = [ bag_name, db_folder ] - expect(loader).to receive(:load_from).with(data_bags_path, bag_name, db_file.path).and_return(plain_data) - expect(loader).to receive(:load_from).with(data_bags_path, bag_name, db_file2.path).and_return(plain_data) - expect(Chef::DataBagItem).to receive(:new).twice.and_return(new_bag_expects, new_bag_expects) - - knife.run - end - - describe "loading all data bags" do - - it "loads all data bags when -a or --all options is provided" do - knife.name_args = [] - config[:all] = true - expect(loader).to receive(:find_all_object_dirs).with("./#{data_bags_path}").and_return([bag_name, bag_name2]) - expect(loader).to receive(:find_all_objects).with("./#{data_bags_path}/#{bag_name}").and_return([File.basename(db_file.path), File.basename(db_file2.path)]) - expect(loader).to receive(:find_all_objects).with("./#{data_bags_path}/#{bag_name2}").and_return([File.basename(db_file3.path)]) - expect(loader).to receive(:load_from).with(data_bags_path, bag_name, File.basename(db_file.path)).and_return(plain_data) - expect(loader).to receive(:load_from).with(data_bags_path, bag_name, File.basename(db_file2.path)).and_return(plain_data) - expect(loader).to receive(:load_from).with(data_bags_path, bag_name2, File.basename(db_file3.path)).and_return(plain_data) - expect(Chef::DataBagItem).to receive(:new).exactly(3).times.and_return(new_bag_expects, new_bag_expects, new_bag_expects(bag_name2)) - - knife.run - end - - it "loads all data bags items when -a or --all options is provided" do - knife.name_args = [bag_name2] - config[:all] = true - expect(loader).to receive(:find_all_objects).with("./#{data_bags_path}/#{bag_name2}").and_return([File.basename(db_file3.path)]) - expect(loader).to receive(:load_from).with(data_bags_path, bag_name2, File.basename(db_file3.path)).and_return(plain_data) - expect(Chef::DataBagItem).to receive(:new).and_return(new_bag_expects(bag_name2)) - - knife.run - end - - end - - describe "encrypted data bag items" do - before(:each) do - expect(knife).to receive(:encryption_secret_provided?).and_return(true) - expect(knife).to receive(:read_secret).and_return(secret) - expect(Chef::EncryptedDataBagItem).to receive(:encrypt_data_bag_item).with(plain_data, secret).and_return(enc_data) - end - - it "encrypts values when given --secret" do - knife.name_args = [bag_name, db_file.path] - expect(loader).to receive(:load_from).with(data_bags_path, bag_name, db_file.path).and_return(plain_data) - expect(Chef::DataBagItem).to receive(:new).and_return(new_bag_expects(bag_name, enc_data)) - - knife.run - end - - end - - 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(stdout.string).to start_with("knife data bag from file BAG FILE|FOLDER [FILE|FOLDER..] (options)") - end - end - -end diff --git a/spec/unit/knife/data_bag_secret_options_spec.rb b/spec/unit/knife/data_bag_secret_options_spec.rb deleted file mode 100644 index 0a2d8ca4bf..0000000000 --- a/spec/unit/knife/data_bag_secret_options_spec.rb +++ /dev/null @@ -1,165 +0,0 @@ -# -# Author:: Tyler Ball (<tball@opscode.com>) -# Copyright:: Copyright (c) 2009-2014 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/knife' -require 'chef/config' -require 'tempfile' - -class ExampleDataBagCommand < Chef::Knife - include Chef::Knife::DataBagSecretOptions -end - -describe Chef::Knife::DataBagSecretOptions do - let(:example_db) do - k = ExampleDataBagCommand.new - allow(k.ui).to receive(:stdout).and_return(stdout) - k - end - - let(:stdout) { StringIO.new } - - let(:secret) { "abc123SECRET" } - let(:secret_file) do - sfile = Tempfile.new("encrypted_data_bag_secret") - sfile.puts(secret) - sfile.flush - sfile - end - - after do - secret_file.close - secret_file.unlink - end - - describe "#validate_secrets" do - - it "throws an error when provided with both --secret and --secret-file on the CL" do - Chef::Config[:knife][:cl_secret_file] = secret_file.path - Chef::Config[:knife][:cl_secret] = secret - expect(example_db).to receive(:exit).with(1) - expect(example_db.ui).to receive(:fatal).with("Please specify only one of --secret, --secret-file") - - example_db.validate_secrets - end - - it "throws an error when provided with `secret` and `secret_file` in knife.rb" do - Chef::Config[:knife][:secret_file] = secret_file.path - Chef::Config[:knife][:secret] = secret - expect(example_db).to receive(:exit).with(1) - expect(example_db.ui).to receive(:fatal).with("Please specify only one of 'secret' or 'secret_file' in your config file") - - example_db.validate_secrets - end - - end - - describe "#read_secret" do - - it "returns the secret first" do - Chef::Config[:knife][:cl_secret] = secret - expect(example_db).to receive(:config).and_return({ :secret => secret }) - expect(example_db.read_secret).to eq(secret) - end - - it "returns the secret_file only if secret does not exist" do - Chef::Config[:knife][:cl_secret_file] = secret_file.path - expect(example_db).to receive(:config).and_return({ :secret_file => secret_file.path }) - expect(Chef::EncryptedDataBagItem).to receive(:load_secret).with(secret_file.path).and_return("secret file contents") - expect(example_db.read_secret).to eq("secret file contents") - end - - it "returns the secret from the knife.rb config" do - Chef::Config[:knife][:secret_file] = secret_file.path - Chef::Config[:knife][:secret] = secret - expect(example_db.read_secret).to eq(secret) - end - - it "returns the secret_file from the knife.rb config only if the secret does not exist" do - Chef::Config[:knife][:secret_file] = secret_file.path - expect(Chef::EncryptedDataBagItem).to receive(:load_secret).with(secret_file.path).and_return("secret file contents") - expect(example_db.read_secret).to eq("secret file contents") - end - - end - - describe "#encryption_secret_provided?" do - - it "returns true if the secret is passed on the CL" do - Chef::Config[:knife][:cl_secret] = secret - expect(example_db.encryption_secret_provided?).to eq(true) - end - - it "returns true if the secret_file is passed on the CL" do - Chef::Config[:knife][:cl_secret_file] = secret_file.path - expect(example_db.encryption_secret_provided?).to eq(true) - end - - it "returns true if --encrypt is passed on the CL and :secret is in config" do - expect(example_db).to receive(:config).and_return({ :encrypt => true }) - Chef::Config[:knife][:secret] = secret - expect(example_db.encryption_secret_provided?).to eq(true) - end - - it "returns true if --encrypt is passed on the CL and :secret_file is in config" do - expect(example_db).to receive(:config).and_return({ :encrypt => true }) - Chef::Config[:knife][:secret_file] = secret_file.path - expect(example_db.encryption_secret_provided?).to eq(true) - end - - it "throws an error if --encrypt is passed and there is not :secret or :secret_file in the config" do - expect(example_db).to receive(:config).and_return({ :encrypt => true }) - expect(example_db).to receive(:exit).with(1) - expect(example_db.ui).to receive(:fatal).with("No secret or secret_file specified in config, unable to encrypt item.") - example_db.encryption_secret_provided? - end - - it "returns false if no secret is passed" do - expect(example_db).to receive(:config).and_return({}) - expect(example_db.encryption_secret_provided?).to eq(false) - end - - it "returns false if --encrypt is not provided and :secret is in the config" do - expect(example_db).to receive(:config).and_return({}) - Chef::Config[:knife][:secret] = secret - expect(example_db.encryption_secret_provided?).to eq(false) - end - - it "returns false if --encrypt is not provided and :secret_file is in the config" do - expect(example_db).to receive(:config).and_return({}) - Chef::Config[:knife][:secret_file] = secret_file.path - expect(example_db.encryption_secret_provided?).to eq(false) - end - - it "returns true if --encrypt is not provided, :secret is in the config and need_encrypt_flag is false" do - Chef::Config[:knife][:secret] = secret - expect(example_db.encryption_secret_provided_ignore_encrypt_flag?).to eq(true) - end - - it "returns true if --encrypt is not provided, :secret_file is in the config and need_encrypt_flag is false" do - Chef::Config[:knife][:secret_file] = secret_file.path - expect(example_db.encryption_secret_provided_ignore_encrypt_flag?).to eq(true) - end - - it "returns false if --encrypt is not provided and need_encrypt_flag is false" do - expect(example_db.encryption_secret_provided_ignore_encrypt_flag?).to eq(false) - end - - end - -end diff --git a/spec/unit/knife/data_bag_show_spec.rb b/spec/unit/knife/data_bag_show_spec.rb deleted file mode 100644 index 1125d99c2a..0000000000 --- a/spec/unit/knife/data_bag_show_spec.rb +++ /dev/null @@ -1,123 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: Seth Falcon (<seth@opscode.com>) -# Copyright:: Copyright (c) 2008-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. -# - -require 'spec_helper' - -require 'chef/data_bag_item' -require 'chef/encrypted_data_bag_item' -require 'chef/json_compat' -require 'tempfile' - -describe Chef::Knife::DataBagShow do - - before do - Chef::Config[:node_name] = "webmonkey.example.com" - knife.name_args = [bag_name, item_name] - allow(knife).to receive(:config).and_return(config) - end - - let(:knife) do - k = Chef::Knife::DataBagShow.new - allow(k).to receive(:rest).and_return(rest) - allow(k.ui).to receive(:stdout).and_return(stdout) - k - end - - let(:rest) { double("Chef::REST") } - 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_with_encoded_hash) { Chef::DataBagItem.from_hash(enc_hash) } - let(:enc_data_bag) { Chef::EncryptedDataBagItem.new(enc_hash, secret) } - - let(:secret) { "abc123SECRET" } - # - # let(:raw_hash) {{ "login_name" => "alphaomega", "id" => item_name }} - # - let(:config) { {format: "json"} } - - context "Data bag to show is encrypted" do - before do - allow(knife).to receive(:encrypted?).and_return(true) - end - - it "decrypts and displays the encrypted data bag when the secret is provided" do - expect(knife).to receive(:encryption_secret_provided_ignore_encrypt_flag?).and_return(true) - expect(knife).to receive(:read_secret).and_return(secret) - expect(Chef::DataBagItem).to receive(:load).with(bag_name, item_name).and_return(data_bag_with_encoded_hash) - 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 -id: id -qux: http://localhost:4000/data/bag_o_data/qux| - knife.run - expect(stdout.string.strip).to eq(expected) - end - - it "displays the encrypted data bag when the secret is not provided" do - expect(knife).to receive(:encryption_secret_provided_ignore_encrypt_flag?).and_return(false) - expect(Chef::DataBagItem).to receive(:load).with(bag_name, item_name).and_return(data_bag_with_encoded_hash) - expect(knife.ui).to receive(:warn).with("Encrypted data bag detected, but no secret provided for decoding. Displaying encrypted data.") - - knife.run - expect(stdout.string.strip).to include("baz", "qux", "cipher") - end - end - - context "Data bag to show is not encrypted" do - before do - allow(knife).to receive(:encrypted?).and_return(false) - expect(knife).to receive(:read_secret).exactly(0).times - end - - it "displays the data bag" do - 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 -id: id -qux: http://localhost:4000/data/bag_o_data/qux| - knife.run - expect(stdout.string.strip).to eq(expected) - end - end - - it "displays the list of items in the data bag when only one @name_arg is provided" do - knife.name_args = [bag_name] - expect(Chef::DataBag).to receive(:load).with(bag_name).and_return({}) - - knife.run - expect(stdout.string.strip).to eq("") - end - - it "raises an error when no @name_args are provided" do - knife.name_args = [] - - expect {knife.run}.to exit_with_code(1) - expect(stdout.string).to start_with("knife data bag show BAG [ITEM] (options)") - end - -end diff --git a/spec/unit/knife/environment_compare_spec.rb b/spec/unit/knife/environment_compare_spec.rb deleted file mode 100644 index 3606b617a9..0000000000 --- a/spec/unit/knife/environment_compare_spec.rb +++ /dev/null @@ -1,112 +0,0 @@ -# -# Author:: Sander Botman (<sbotman@schubergphilis.com>) -# Copyright:: Copyright (c) 2013 Sander Botman. -# 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::EnvironmentCompare do - before(:each) do - @knife = Chef::Knife::EnvironmentCompare.new - - @environments = { - "cita" => "http://localhost:4000/environments/cita", - "citm" => "http://localhost:4000/environments/citm" - } - - @knife.stub(:environment_list).and_return(@environments) - - @constraints = { - "cita" => { "foo" => "= 1.0.1", "bar" => "= 0.0.4" }, - "citm" => { "foo" => "= 1.0.1", "bar" => "= 0.0.2" } - } - - @knife.stub(:constraint_list).and_return(@constraints) - - @cookbooks = { "foo"=>"= 1.0.1", "bar"=>"= 0.0.1" } - - @knife.stub(:cookbook_list).and_return(@cookbooks) - - @rest_double = double('rest') - @knife.stub(:rest).and_return(@rest_double) - @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 - - @rest_double.stub(:get_rest).with("/cookbooks?num_versions=1").and_return(@cookbook_data) - - @stdout = StringIO.new - @knife.ui.stub(:stdout).and_return(@stdout) - end - - describe 'run' do - it 'should display only cookbooks with version constraints' do - @knife.config[:format] = 'summary' - @knife.run - @environments.each do |item, url| - @stdout.string.should match /#{item}/ and @stdout.string.lines.count.should be 4 - end - end - - it 'should display 4 number of lines' do - @knife.config[:format] = 'summary' - @knife.run - @stdout.string.lines.count.should 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' - @knife.config[:mismatch] = true - @knife.run - @constraints.each do |item, ver| - @stdout.string.should match /#{ver[1]}/ - end - end - - it 'should display 3 number of lines' do - @knife.config[:format] = 'summary' - @knife.config[:mismatch] = true - @knife.run - @stdout.string.lines.count.should be 3 - end - end - - 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| - @stdout.string.should match /#{ver[1]}/ - end - end - - it 'should display 8 number of lines' do - @knife.config[:format] = 'summary' - @knife.config[:all] = true - @knife.run - @stdout.string.lines.count.should be 8 - end - end - -end diff --git a/spec/unit/knife/environment_create_spec.rb b/spec/unit/knife/environment_create_spec.rb deleted file mode 100644 index 81bf6731b7..0000000000 --- a/spec/unit/knife/environment_create_spec.rb +++ /dev/null @@ -1,91 +0,0 @@ -# -# Author:: Stephen Delano (<stephen@ospcode.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. -# - -require 'spec_helper' - -describe Chef::Knife::EnvironmentCreate do - before(:each) do - @knife = Chef::Knife::EnvironmentCreate.new - @knife.stub(:msg).and_return true - @knife.stub(:output).and_return true - @knife.stub(:show_usage).and_return true - @knife.name_args = [ "production" ] - - @environment = Chef::Environment.new - @environment.stub(:save) - - Chef::Environment.stub(:new).and_return @environment - @knife.stub(:edit_data).and_return @environment - end - - describe "run" do - it "should create a new environment" do - Chef::Environment.should_receive(:new) - @knife.run - end - - it "should set the environment name" do - @environment.should_receive(:name).with("production") - @knife.run - end - - it "should not print the environment" do - @knife.should_not_receive(:output) - @knife.run - end - - it "should prompt you to edit the data" do - @knife.should_receive(:edit_data).with(@environment) - @knife.run - end - - it "should save the environment" do - @environment.should_receive(:save) - @knife.run - end - - it "should show usage and exit when no environment name is provided" do - @knife.name_args = [ ] - @knife.ui.should_receive(:fatal) - @knife.should_receive(:show_usage) - lambda { @knife.run }.should raise_error(SystemExit) - end - - describe "with --description" do - before(:each) do - @knife.config[:description] = "This is production" - end - - it "should set the description" do - @environment.should_receive(:description).with("This is production") - @knife.run - end - end - - describe "with --print-after" do - before(:each) do - @knife.config[:print_after] = true - end - - it "should pretty print the environment, formatted for display" do - @knife.should_receive(:output).with(@environment) - @knife.run - end - end - end -end diff --git a/spec/unit/knife/environment_delete_spec.rb b/spec/unit/knife/environment_delete_spec.rb deleted file mode 100644 index 0f6b5f3272..0000000000 --- a/spec/unit/knife/environment_delete_spec.rb +++ /dev/null @@ -1,71 +0,0 @@ -# -# Author:: Stephen Delano (<stephen@ospcode.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. -# - -require 'spec_helper' - -describe Chef::Knife::EnvironmentDelete do - before(:each) do - @knife = Chef::Knife::EnvironmentDelete.new - @knife.stub(:msg).and_return true - @knife.stub(:output).and_return true - @knife.stub(:show_usage).and_return true - @knife.stub(:confirm).and_return true - @knife.name_args = [ "production" ] - - @environment = Chef::Environment.new - @environment.name("production") - @environment.description("Please delete me") - @environment.stub(:destroy).and_return true - Chef::Environment.stub(:load).and_return @environment - end - - it "should confirm that you want to delete" do - @knife.should_receive(:confirm) - @knife.run - end - - it "should load the environment" do - Chef::Environment.should_receive(:load).with("production") - @knife.run - end - - it "should delete the environment" do - @environment.should_receive(:destroy) - @knife.run - end - - it "should not print the environment" do - @knife.should_not_receive(:output) - @knife.run - end - - it "should show usage and exit when no environment name is provided" do - @knife.name_args = [] - @knife.ui.should_receive(:fatal) - @knife.should_receive(:show_usage) - lambda { @knife.run }.should raise_error(SystemExit) - end - - describe "with --print-after" do - it "should pretty print the environment, formatted for display" do - @knife.config[:print_after] = true - @knife.should_receive(:output).with(@environment) - @knife.run - end - end -end diff --git a/spec/unit/knife/environment_edit_spec.rb b/spec/unit/knife/environment_edit_spec.rb deleted file mode 100644 index a82ead0b6b..0000000000 --- a/spec/unit/knife/environment_edit_spec.rb +++ /dev/null @@ -1,79 +0,0 @@ -# -# Author:: Stephen Delano (<stephen@ospcode.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. -# - -require 'spec_helper' - -describe Chef::Knife::EnvironmentEdit do - before(:each) do - @knife = Chef::Knife::EnvironmentEdit.new - @knife.ui.stub(:msg).and_return true - @knife.ui.stub(:output).and_return true - @knife.ui.stub(:show_usage).and_return true - @knife.name_args = [ "production" ] - - @environment = Chef::Environment.new - @environment.name("production") - @environment.description("Please edit me") - @environment.stub(:save).and_return true - Chef::Environment.stub(:load).and_return @environment - @knife.ui.stub(:edit_data).and_return @environment - end - - it "should load the environment" do - Chef::Environment.should_receive(:load).with("production") - @knife.run - end - - it "should let you edit the environment" do - @knife.ui.should_receive(:edit_data).with(@environment) - @knife.run - end - - it "should save the edited environment data" do - pansy = Chef::Environment.new - - @environment.name("new_environment_name") - @knife.ui.should_receive(:edit_data).with(@environment).and_return(pansy) - pansy.should_receive(:save) - @knife.run - end - - it "should not save the unedited environment data" do - @environment.should_not_receive(:save) - @knife.run - end - - it "should not print the environment" do - @knife.should_not_receive(:output) - @knife.run - end - - it "shoud show usage and exit when no environment name is provided" do - @knife.name_args = [] - @knife.should_receive(:show_usage) - lambda { @knife.run }.should raise_error(SystemExit) - end - - describe "with --print-after" do - it "should pretty print the environment, formatted for display" do - @knife.config[:print_after] = true - @knife.ui.should_receive(:output).with(@environment) - @knife.run - end - end -end diff --git a/spec/unit/knife/environment_from_file_spec.rb b/spec/unit/knife/environment_from_file_spec.rb deleted file mode 100644 index 562e7f8cf5..0000000000 --- a/spec/unit/knife/environment_from_file_spec.rb +++ /dev/null @@ -1,90 +0,0 @@ -# -# Author:: Stephen Delano (<stephen@ospcode.com>) -# Author:: Seth Falcon (<seth@ospcode.com>) -# Copyright:: Copyright 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. -# - -require 'spec_helper' - -Chef::Knife::EnvironmentFromFile.load_deps - -describe Chef::Knife::EnvironmentFromFile do - before(:each) do - Chef::Platform.stub(:windows?) { false } - @knife = Chef::Knife::EnvironmentFromFile.new - @stdout = StringIO.new - @knife.ui.stub(:stdout).and_return(@stdout) - @knife.name_args = [ "spec.rb" ] - - @environment = Chef::Environment.new - @environment.name("spec") - @environment.description("runs the unit tests") - @environment.cookbook_versions({"apt" => "= 1.2.3"}) - @environment.stub(:save).and_return true - @knife.loader.stub(:load_from).and_return @environment - end - - describe "run" do - it "loads the environment data from a file and saves it" do - @knife.loader.should_receive(:load_from).with('environments', 'spec.rb').and_return(@environment) - @environment.should_receive(:save) - @knife.run - end - - context "when handling multiple environments" do - before(:each) do - @env_apple = @environment.dup - @env_apple.name("apple") - @knife.loader.stub(:load_from).with("apple.rb").and_return @env_apple - end - - it "loads multiple environments if given" do - @knife.name_args = [ "spec.rb", "apple.rb" ] - @environment.should_receive(:save).twice - @knife.run - end - - it "loads all environments with -a" do - File.stub(:expand_path).with("./environments/").and_return("/tmp/environments") - Dir.stub(:glob).with("/tmp/environments/*.{json,rb}").and_return(["spec.rb", "apple.rb"]) - @knife.name_args = [] - @knife.stub(:config).and_return({:all => true}) - @environment.should_receive(:save).twice - @knife.run - end - end - - it "should not print the environment" do - @knife.should_not_receive(:output) - @knife.run - end - - it "should show usage and exit if not filename is provided" do - @knife.name_args = [] - @knife.ui.should_receive(:fatal) - @knife.should_receive(:show_usage) - lambda { @knife.run }.should raise_error(SystemExit) - end - - describe "with --print-after" do - it "should pretty print the environment, formatted for display" do - @knife.config[:print_after] = true - @knife.should_receive(:output) - @knife.run - end - end - end -end diff --git a/spec/unit/knife/environment_list_spec.rb b/spec/unit/knife/environment_list_spec.rb deleted file mode 100644 index 25d2714d23..0000000000 --- a/spec/unit/knife/environment_list_spec.rb +++ /dev/null @@ -1,54 +0,0 @@ -# -# Author:: Stephen Delano (<stephen@ospcode.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. -# - -require 'spec_helper' - -describe Chef::Knife::EnvironmentList do - before(:each) do - @knife = Chef::Knife::EnvironmentList.new - @knife.stub(:msg).and_return true - @knife.stub(:output).and_return true - @knife.stub(:show_usage).and_return true - - @environments = { - "production" => "http://localhost:4000/environments/production", - "development" => "http://localhost:4000/environments/development", - "testing" => "http://localhost:4000/environments/testing" - } - Chef::Environment.stub(:list).and_return @environments - end - - it "should make an api call to list the environments" do - Chef::Environment.should_receive(:list) - @knife.run - end - - it "should print the environment names in a sorted list" do - names = @environments.keys.sort { |a,b| a <=> b } - @knife.should_receive(:output).with(names) - @knife.run - end - - describe "with --with-uri" do - it "should print and unsorted list of the environments and their URIs" do - @knife.config[:with_uri] = true - @knife.should_receive(:output).with(@environments) - @knife.run - end - end -end diff --git a/spec/unit/knife/environment_show_spec.rb b/spec/unit/knife/environment_show_spec.rb deleted file mode 100644 index c7b0c21657..0000000000 --- a/spec/unit/knife/environment_show_spec.rb +++ /dev/null @@ -1,52 +0,0 @@ -# -# Author:: Stephen Delano (<stephen@ospcode.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. -# - -require 'spec_helper' - -describe Chef::Knife::EnvironmentShow do - before(:each) do - @knife = Chef::Knife::EnvironmentShow.new - @knife.stub(:msg).and_return true - @knife.stub(:output).and_return true - @knife.stub(:show_usage).and_return true - @knife.name_args = [ "production" ] - - @environment = Chef::Environment.new - @environment.name("production") - @environment.description("Look at me!") - Chef::Environment.stub(:load).and_return @environment - end - - it "should load the environment" do - Chef::Environment.should_receive(:load).with("production") - @knife.run - end - - it "should pretty print the environment, formatted for display" do - @knife.should_receive(:format_for_display).with(@environment) - @knife.should_receive(:output) - @knife.run - end - - it "should show usage and exit when no environment name is provided" do - @knife.name_args = [] - @knife.ui.should_receive(:fatal) - @knife.should_receive(:show_usage) - lambda { @knife.run }.should raise_error(SystemExit) - end -end diff --git a/spec/unit/knife/index_rebuild_spec.rb b/spec/unit/knife/index_rebuild_spec.rb deleted file mode 100644 index 3a8ec00651..0000000000 --- a/spec/unit/knife/index_rebuild_spec.rb +++ /dev/null @@ -1,128 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@kallistec.com>) -# Copyright:: Copyright (c) 2009 Daniel DeLeo -# 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::IndexRebuild do - - let(:knife){Chef::Knife::IndexRebuild.new} - let(:rest_client){double(Chef::REST)} - - let(:stub_rest!) do - knife.should_receive(:rest).and_return(rest_client) - end - - before :each do - # This keeps the test output clean - knife.ui.stub(:stdout).and_return(StringIO.new) - end - - context "#grab_api_info" do - let(:http_not_found_response) do - e = Net::HTTPNotFound.new("1.1", 404, "blah") - e.stub(:[]).with("x-ops-api-info").and_return(api_header_value) - e - end - - let(:http_server_exception) do - Net::HTTPServerException.new("404: Not Found", http_not_found_response) - end - - before(:each) do - stub_rest! - rest_client.stub(:get_rest).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"} - it "retrieves API information" do - knife.grab_api_info.should == {"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} - it "finds no API information" do - knife.grab_api_info.should == {} - end - end # Chef 10 - end # grab_api_info - - context "#unsupported_version?" do - context "with Chef 11 API metadata" do - it "is unsupported" do - knife.unsupported_version?({"version" => "11.0.0", "flavor" => "osc", "erchef" => "1.2.3"}).should be_true - end - - it "only truly relies on the version being non-nil" do - knife.unsupported_version?({"version" => "1", "flavor" => "osc", "erchef" => "1.2.3"}).should be_true - end - end - - context "with Chef 10 API metadata" do - it "is supported" do - # Chef 10 will have no metadata - knife.unsupported_version?({}).should be_false - end - end - end # unsupported_version? - - context "Simulating a 'knife index rebuild' run" do - - before :each do - knife.should_receive(:grab_api_info).and_return(api_info) - server_specific_stubs! - end - - context "against a Chef 11 server" do - let(:api_info) do - {"flavor" => "osc", - "version" => "11.0.0", - "erchef" => "1.2.3" - } - end - let(:server_specific_stubs!) do - knife.should_receive(:unsupported_server_message).with(api_info) - knife.should_receive(:exit).with(1) - end - - it "should not be allowed" do - knife.run - end - end - - context "against a Chef 10 server" do - let(:api_info){ {} } - let(:server_specific_stubs!) do - stub_rest! - rest_client.should_receive(:post_rest).with("/search/reindex", {}).and_return("representative output") - knife.should_not_receive(:unsupported_server_message) - knife.should_receive(:deprecated_server_message) - knife.should_receive(:nag) - knife.should_receive(:output).with("representative output") - end - it "should be allowed" do - knife.run - end - end - end - -end - - - diff --git a/spec/unit/knife/knife_help.rb b/spec/unit/knife/knife_help.rb deleted file mode 100644 index e66a44801b..0000000000 --- a/spec/unit/knife/knife_help.rb +++ /dev/null @@ -1,92 +0,0 @@ -# -# Author:: Bryan McLellan <btm@loftninjas.org> -# Copyright:: Copyright (c) 2011 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::Knife::Help do - before(:each) do - # Perilously use the build in list even though it is dynamic so we don't get warnings about the constant - # HELP_TOPICS = [ "foo", "bar", "knife-kittens", "ceiling-cat", "shell" ] - @knife = Chef::Knife::Help.new - end - - it "should return a list of help topics" do - @knife.help_topics.should include("knife-status") - end - - it "should run man for you" do - @knife.name_args = [ "shell" ] - @knife.should_receive(:exec).with(/^man \/.*\/shell.1$/) - @knife.run - end - - it "should suggest topics" do - @knife.name_args = [ "list" ] - @knife.ui.stub(:msg) - @knife.ui.should_receive(:info).with("Available help topics are: ") - @knife.ui.should_receive(:msg).with(/knife/) - @knife.stub(:exec) - @knife.should_receive(:exit).with(1) - @knife.run - end - - describe "find_manpage_path" do - it "should find the man page in the gem" do - @knife.find_manpage_path("shell").should =~ /distro\/common\/man\/man1\/chef-shell.1$/ - end - - it "should provide the man page name if not in the gem" do - @knife.find_manpage_path("foo").should == "foo" - end - end - - describe "find_manpages_for_query" do - it "should error if it does not find a match" do - @knife.ui.stub(:error) - @knife.ui.stub(:info) - @knife.ui.stub(:msg) - @knife.should_receive(:exit).with(1) - @knife.ui.should_receive(:error).with("No help found for 'chickens'") - @knife.ui.should_receive(:msg).with(/knife/) - @knife.find_manpages_for_query("chickens") - end - end - - describe "print_help_topics" do - it "should print the known help topics" do - @knife.ui.stub(:msg) - @knife.ui.stub(:info) - @knife.ui.should_receive(:msg).with(/knife/) - @knife.print_help_topics - end - - it "should shorten topics prefixed by knife-" do - @knife.ui.stub(:msg) - @knife.ui.stub(:info) - @knife.ui.should_receive(:msg).with(/node/) - @knife.print_help_topics - end - - it "should not leave topics prefixed by knife-" do - @knife.ui.stub(:msg) - @knife.ui.stub(:info) - @knife.ui.should_not_receive(:msg).with(/knife-node/) - @knife.print_help_topics - end - end -end diff --git a/spec/unit/knife/node_bulk_delete_spec.rb b/spec/unit/knife/node_bulk_delete_spec.rb deleted file mode 100644 index 3faece5469..0000000000 --- a/spec/unit/knife/node_bulk_delete_spec.rb +++ /dev/null @@ -1,97 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef::Knife::NodeBulkDelete do - before(:each) do - Chef::Log.logger = Logger.new(StringIO.new) - - Chef::Config[:node_name] = "webmonkey.example.com" - @knife = Chef::Knife::NodeBulkDelete.new - @knife.name_args = ["."] - @stdout = StringIO.new - @knife.ui.stub(:stdout).and_return(@stdout) - @knife.ui.stub(:confirm).and_return(true) - @nodes = Hash.new - %w{adam brent jacob}.each do |node_name| - @nodes[node_name] = "http://localhost:4000/nodes/#{node_name}" - end - end - - 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 - end - Chef::Node.should_receive(:list).and_return(@nodes) - # I hate not having == defined for anything :( - actual = @knife.all_nodes - actual.keys.should =~ expected.keys - actual.values.map {|n| n.name }.should =~ %w[adam brent jacob] - end - end - - describe "run" do - before do - @inflatedish_list = @nodes.keys.inject({}) do |nodes_by_name, name| - node = Chef::Node.new() - node.name(name) - node.stub(:destroy).and_return(true) - nodes_by_name[name] = node - nodes_by_name - end - @knife.stub(:all_nodes).and_return(@inflatedish_list) - end - - it "should print the nodes you are about to delete" do - @knife.run - @stdout.string.should match(/#{@knife.ui.list(@nodes.keys.sort, :columns_down)}/) - end - - it "should confirm you really want to delete them" do - @knife.ui.should_receive(:confirm) - @knife.run - end - - it "should delete each node" do - @inflatedish_list.each_value do |n| - n.should_receive(:destroy) - end - @knife.run - end - - it "should only delete nodes that match the regex" do - @knife.name_args = ['adam'] - @inflatedish_list['adam'].should_receive(:destroy) - @inflatedish_list['brent'].should_not_receive(:destroy) - @inflatedish_list['jacob'].should_not_receive(:destroy) - @knife.run - end - - it "should exit if the regex is not provided" do - @knife.name_args = [] - lambda { @knife.run }.should raise_error(SystemExit) - end - - end -end - - - diff --git a/spec/unit/knife/node_delete_spec.rb b/spec/unit/knife/node_delete_spec.rb deleted file mode 100644 index 04eca389c6..0000000000 --- a/spec/unit/knife/node_delete_spec.rb +++ /dev/null @@ -1,68 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef::Knife::NodeDelete do - before(:each) do - Chef::Config[:node_name] = "webmonkey.example.com" - @knife = Chef::Knife::NodeDelete.new - @knife.config = { - :print_after => nil - } - @knife.name_args = [ "adam" ] - @knife.stub(:output).and_return(true) - @knife.stub(:confirm).and_return(true) - @node = Chef::Node.new() - @node.stub(:destroy).and_return(true) - Chef::Node.stub(:load).and_return(@node) - @stdout = StringIO.new - @knife.ui.stub(:stdout).and_return(@stdout) - end - - describe "run" do - it "should confirm that you want to delete" do - @knife.should_receive(:confirm) - @knife.run - end - - it "should load the node" do - Chef::Node.should_receive(:load).with("adam").and_return(@node) - @knife.run - end - - it "should delete the node" do - @node.should_receive(:destroy).and_return(@node) - @knife.run - end - - it "should not print the node" do - @knife.should_not_receive(:output).with("poop") - @knife.run - end - - describe "with -p or --print-after" do - it "should pretty print the node, formatted for display" do - @knife.config[:print_after] = true - @knife.should_receive(:format_for_display).with(@node).and_return("poop") - @knife.should_receive(:output).with("poop") - @knife.run - end - end - end -end diff --git a/spec/unit/knife/node_edit_spec.rb b/spec/unit/knife/node_edit_spec.rb deleted file mode 100644 index 27db3416f4..0000000000 --- a/spec/unit/knife/node_edit_spec.rb +++ /dev/null @@ -1,115 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' -Chef::Knife::NodeEdit.load_deps - -describe Chef::Knife::NodeEdit do - - # helper to convert the view from Chef objects into Ruby objects representing JSON - def deserialized_json_view - actual = Chef::JSONCompat.from_json(Chef::JSONCompat.to_json_pretty(@knife.node_editor.send(:view))) - end - - before(:each) do - Chef::Config[:node_name] = "webmonkey.example.com" - @knife = Chef::Knife::NodeEdit.new - @knife.config = { - :editor => 'cat', - :attribute => nil, - :print_after => nil - } - @knife.name_args = [ "adam" ] - @node = Chef::Node.new() - end - - it "should load the node" do - Chef::Node.should_receive(:load).with("adam").and_return(@node) - @knife.node - end - - describe "after loading the node" do - before do - @knife.stub(: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.chef_environment("prod") - @node.run_list("recipe[foo]") - end - - it "creates a view of the node without attributes from roles or ohai" do - actual = deserialized_json_view - actual.should_not have_key("automatic") - actual.should_not have_key("override") - actual.should_not have_key("default") - actual["normal"].should == {"do_show" => "these"} - actual["run_list"].should == ["recipe[foo]"] - actual["chef_environment"].should == "prod" - end - - it "shows the extra attributes when given the --all option" do - @knife.config[:all_attributes] = true - - actual = deserialized_json_view - actual["automatic"].should == {"go" => "away"} - actual["override"].should == {"dont" => "show"} - actual["default"].should == {"hide" => "me"} - actual["normal"].should == {"do_show" => "these"} - actual["run_list"].should == ["recipe[foo]"] - actual["chef_environment"].should == "prod" - end - - it "does not consider unedited data updated" do - view = deserialized_json_view - @knife.node_editor.send(:apply_updates, view) - @knife.node_editor.should_not be_updated - end - - it "considers edited data updated" do - view = deserialized_json_view - view["run_list"] << "role[fuuu]" - @knife.node_editor.send(:apply_updates, view) - @knife.node_editor.should be_updated - end - - end - - describe "edit_node" do - - before do - @knife.stub(:node).and_return(@node) - end - - let(:subject) { @knife.node_editor.edit_node } - - it "raises an exception when editing is disabled" do - @knife.config[:disable_editing] = true - 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) - end - - end - -end - diff --git a/spec/unit/knife/node_environment_set_spec.rb b/spec/unit/knife/node_environment_set_spec.rb deleted file mode 100644 index 46ee1fea18..0000000000 --- a/spec/unit/knife/node_environment_set_spec.rb +++ /dev/null @@ -1,80 +0,0 @@ -# -# Author:: Jimmy McCrory (<jimmy.mccrory@gmail.com>) -# Copyright:: Copyright (c) 2014 Jimmy McCrory -# 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::NodeEnvironmentSet do - before(:each) do - Chef::Config[:node_name] = "webmonkey.example.com" - @knife = Chef::Knife::NodeEnvironmentSet.new - @knife.name_args = [ "adam", "bar" ] - @knife.stub(:output).and_return(true) - @node = Chef::Node.new() - @node.name("knifetest-node") - @node.chef_environment << "foo" - @node.stub(:save).and_return(true) - Chef::Node.stub(:load).and_return(@node) - end - - describe "run" do - it "should load the node" do - Chef::Node.should_receive(:load).with("adam") - @knife.run - end - - it "should update the environment" do - @knife.run - @node.chef_environment.should == 'bar' - end - - it "should save the node" do - @node.should_receive(:save) - @knife.run - end - - it "should print the environment" do - @knife.should_receive(:output).and_return(true) - @knife.run - end - - describe "with no environment" do - # Set up outputs for inspection later - before(:each) do - @stdout = StringIO.new - @stderr = StringIO.new - - @knife.ui.stub(:stdout).and_return(@stdout) - @knife.ui.stub(:stderr).and_return(@stderr) - end - - it "should exit" do - @knife.name_args = [ "adam" ] - lambda { @knife.run }.should raise_error SystemExit - end - - it "should show the user the usage and an error" do - @knife.name_args = [ "adam" ] - - begin ; @knife.run ; rescue SystemExit ; end - - @stdout.string.should eq "USAGE: knife node environment set NODE ENVIRONMENT\n" - @stderr.string.should eq "FATAL: You must specify a node name and an environment.\n" - end - end - end -end diff --git a/spec/unit/knife/node_from_file_spec.rb b/spec/unit/knife/node_from_file_spec.rb deleted file mode 100644 index 56a2a08b68..0000000000 --- a/spec/unit/knife/node_from_file_spec.rb +++ /dev/null @@ -1,59 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -Chef::Knife::NodeFromFile.load_deps - -describe Chef::Knife::NodeFromFile do - before(:each) do - Chef::Config[:node_name] = "webmonkey.example.com" - @knife = Chef::Knife::NodeFromFile.new - @knife.config = { - :print_after => nil - } - @knife.name_args = [ "adam.rb" ] - @knife.stub(:output).and_return(true) - @knife.stub(:confirm).and_return(true) - @node = Chef::Node.new() - @node.stub(:save) - @knife.loader.stub(:load_from).and_return(@node) - @stdout = StringIO.new - @knife.ui.stub(:stdout).and_return(@stdout) - end - - describe "run" do - it "should load from a file" do - @knife.loader.should_receive(:load_from).with('nodes', 'adam.rb').and_return(@node) - @knife.run - end - - it "should not print the Node" do - @knife.should_not_receive(:output) - @knife.run - end - - describe "with -p or --print-after" do - it "should print the Node" do - @knife.config[:print_after] = true - @knife.should_receive(:output) - @knife.run - end - end - end -end diff --git a/spec/unit/knife/node_list_spec.rb b/spec/unit/knife/node_list_spec.rb deleted file mode 100644 index cad2d6482d..0000000000 --- a/spec/unit/knife/node_list_spec.rb +++ /dev/null @@ -1,63 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef::Knife::NodeList do - before(:each) do - 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 - @knife.stub(:output).and_return(true) - @list = { - "foo" => "http://example.com/foo", - "bar" => "http://example.com/foo" - } - Chef::Node.stub(:list).and_return(@list) - Chef::Node.stub(:list_by_environment).and_return(@list) - end - - describe "run" do - it "should list all of the nodes if -E is not specified" do - Chef::Node.should_receive(:list).and_return(@list) - @knife.run - end - - it "should pretty print the list" do - Chef::Node.should_receive(:list).and_return(@list) - @knife.should_receive(:output).with([ "bar", "foo" ]) - @knife.run - end - - it "should list nodes in the specific environment if -E ENVIRONMENT is specified" do - Chef::Config[:environment] = "prod" - Chef::Node.should_receive(:list_by_environment).with("prod").and_return(@list) - @knife.run - end - - describe "with -w or --with-uri" do - it "should pretty print the hash" do - @knife.config[:with_uri] = true - Chef::Node.should_receive(:list).and_return(@list) - @knife.should_receive(:output).with(@list) - @knife.run - end - 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 deleted file mode 100644 index bd33a359a2..0000000000 --- a/spec/unit/knife/node_run_list_add_spec.rb +++ /dev/null @@ -1,148 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef::Knife::NodeRunListAdd do - before(:each) do - Chef::Config[:node_name] = "webmonkey.example.com" - @knife = Chef::Knife::NodeRunListAdd.new - @knife.config = { - :after => nil - } - @knife.name_args = [ "adam", "role[monkey]" ] - @knife.stub(:output).and_return(true) - @node = Chef::Node.new() - @node.stub(:save).and_return(true) - Chef::Node.stub(:load).and_return(@node) - end - - describe "run" do - it "should load the node" do - Chef::Node.should_receive(:load).with("adam") - @knife.run - end - - it "should add to the run list" do - @knife.run - @node.run_list[0].should == 'role[monkey]' - end - - it "should save the node" do - @node.should_receive(:save) - @knife.run - end - - it "should print the run list" do - @knife.should_receive(:output).and_return(true) - @knife.run - end - - describe "with -a or --after specified" do - it "should add to the run list after the specified entry" do - @node.run_list << "role[acorns]" - @node.run_list << "role[barn]" - @knife.config[:after] = "role[acorns]" - @knife.run - @node.run_list[0].should == "role[acorns]" - @node.run_list[1].should == "role[monkey]" - @node.run_list[2].should == "role[barn]" - end - end - - describe "with -b or --before specified" do - it "should add to the run list before the specified entry" do - @node.run_list << "role[acorns]" - @node.run_list << "role[barn]" - @knife.config[:before] = "role[acorns]" - @knife.run - @node.run_list[0].should == "role[monkey]" - @node.run_list[1].should == "role[acorns]" - @node.run_list[2].should == "role[barn]" - end - end - - describe "with both --after and --before specified" do - it "exits with an error" do - @node.run_list << "role[acorns]" - @node.run_list << "role[barn]" - @knife.config[:before] = "role[acorns]" - @knife.config[:after] = "role[acorns]" - @knife.ui.should_receive(:fatal) - lambda { @knife.run }.should raise_error(SystemExit) - end - end - - describe "with more than one role or recipe" do - it "should add to the run list all the entries" do - @knife.name_args = [ "adam", "role[monkey],role[duck]" ] - @node.run_list << "role[acorns]" - @knife.run - @node.run_list[0].should == "role[acorns]" - @node.run_list[1].should == "role[monkey]" - @node.run_list[2].should == "role[duck]" - end - end - - describe "with more than one role or recipe with space between items" do - it "should add to the run list all the entries" do - @knife.name_args = [ "adam", "role[monkey], role[duck]" ] - @node.run_list << "role[acorns]" - @knife.run - @node.run_list[0].should == "role[acorns]" - @node.run_list[1].should == "role[monkey]" - @node.run_list[2].should == "role[duck]" - end - end - - describe "with more than one role or recipe as different arguments" do - it "should add to the run list all the entries" do - @knife.name_args = [ "adam", "role[monkey]", "role[duck]" ] - @node.run_list << "role[acorns]" - @knife.run - @node.run_list[0].should == "role[acorns]" - @node.run_list[1].should == "role[monkey]" - @node.run_list[2].should == "role[duck]" - end - end - - describe "with more than one role or recipe as different arguments and list separated by commas" do - it "should add to the run list all the entries" do - @knife.name_args = [ "adam", "role[monkey]", "role[duck],recipe[bird::fly]" ] - @node.run_list << "role[acorns]" - @knife.run - @node.run_list[0].should == "role[acorns]" - @node.run_list[1].should == "role[monkey]" - @node.run_list[2].should == "role[duck]" - end - end - - describe "with one role or recipe but with an extraneous comma" do - it "should add to the run list one item" do - @knife.name_args = [ "adam", "role[monkey]," ] - @node.run_list << "role[acorns]" - @knife.run - @node.run_list[0].should == "role[acorns]" - @node.run_list[1].should == "role[monkey]" - end - 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 deleted file mode 100644 index 5a008a3e07..0000000000 --- a/spec/unit/knife/node_run_list_remove_spec.rb +++ /dev/null @@ -1,74 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef::Knife::NodeRunListRemove do - before(:each) do - Chef::Config[:node_name] = "webmonkey.example.com" - @knife = Chef::Knife::NodeRunListRemove.new - @knife.config[:print_after] = nil - @knife.name_args = [ "adam", "role[monkey]" ] - @node = Chef::Node.new() - @node.name("knifetest-node") - @node.run_list << "role[monkey]" - @node.stub(:save).and_return(true) - - @knife.ui.stub(:output).and_return(true) - @knife.ui.stub(:confirm).and_return(true) - - Chef::Node.stub(:load).and_return(@node) - end - - describe "run" do - it "should load the node" do - Chef::Node.should_receive(:load).with("adam").and_return(@node) - @knife.run - end - - it "should remove the item from the run list" do - @knife.run - @node.run_list[0].should_not == 'role[monkey]' - end - - it "should save the node" do - @node.should_receive(:save).and_return(true) - @knife.run - end - - it "should print the run list" do - @knife.config[:print_after] = true - @knife.ui.should_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]' ] - @knife.run - @node.run_list.should_not include('role[monkey]') - @node.run_list.should_not include('recipe[duck::type]') - end - 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 deleted file mode 100644 index 02281f8385..0000000000 --- a/spec/unit/knife/node_run_list_set_spec.rb +++ /dev/null @@ -1,140 +0,0 @@ -# -# Author:: Mike Fiedler (<miketheman@gmail.com>) -# Copyright:: Copyright (c) 2013 Mike Fiedler -# 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::NodeRunListSet do - before(:each) do - Chef::Config[:node_name] = "webmonkey.example.com" - @knife = Chef::Knife::NodeRunListSet.new - @knife.config = {} - @knife.name_args = [ "adam", "role[monkey]" ] - @knife.stub(:output).and_return(true) - @node = Chef::Node.new() - @node.stub(:save).and_return(true) - Chef::Node.stub(:load).and_return(@node) - end - - describe "run" do - it "should load the node" do - Chef::Node.should_receive(:load).with("adam") - @knife.run - end - - it "should set the run list" do - @knife.run - @node.run_list[0].should == 'role[monkey]' - end - - it "should save the node" do - @node.should_receive(:save) - @knife.run - end - - it "should print the run list" do - @knife.should_receive(:output).and_return(true) - @knife.run - end - - describe "with more than one role or recipe" do - it "should set the run list to all the entries" do - @knife.name_args = [ "adam", "role[monkey],role[duck]" ] - @knife.run - @node.run_list[0].should == "role[monkey]" - @node.run_list[1].should == "role[duck]" - end - end - - describe "with more than one role or recipe with space between items" do - it "should set the run list to all the entries" do - @knife.name_args = [ "adam", "role[monkey], role[duck]" ] - @knife.run - @node.run_list[0].should == "role[monkey]" - @node.run_list[1].should == "role[duck]" - end - end - - describe "with more than one role or recipe as different arguments" do - it "should set the run list to all the entries" do - @knife.name_args = [ "adam", "role[monkey]", "role[duck]" ] - @knife.run - @node.run_list[0].should == "role[monkey]" - @node.run_list[1].should == "role[duck]" - end - end - - describe "with more than one role or recipe as different arguments and list separated by comas" do - it "should add to the run list all the entries" do - @knife.name_args = [ "adam", "role[monkey]", "role[duck],recipe[bird::fly]" ] - @knife.run - @node.run_list[0].should == "role[monkey]" - @node.run_list[1].should == "role[duck]" - end - end - - describe "with one role or recipe but with an extraneous comma" do - it "should add to the run list one item" do - @knife.name_args = [ "adam", "role[monkey]," ] - @knife.run - @node.run_list[0].should == "role[monkey]" - end - end - - describe "with an existing run list" do - it "should overwrite any existing run list items" do - @node.run_list << "role[acorns]" - @node.run_list << "role[zebras]" - @node.run_list[0].should == "role[acorns]" - @node.run_list[1].should == "role[zebras]" - @node.run_list.run_list_items.size.should == 2 - - @knife.name_args = [ "adam", "role[monkey]", "role[duck]" ] - @knife.run - @node.run_list[0].should == "role[monkey]" - @node.run_list[1].should == "role[duck]" - @node.run_list.run_list_items.size.should == 2 - end - end - - describe "with no role or recipe" do - # Set up outputs for inspection later - before(:each) do - @stdout = StringIO.new - @stderr = StringIO.new - - @knife.ui.stub(:stdout).and_return(@stdout) - @knife.ui.stub(:stderr).and_return(@stderr) - end - - it "should exit" do - @knife.name_args = [ "adam" ] - lambda { @knife.run }.should raise_error SystemExit - end - - it "should show the user" do - @knife.name_args = [ "adam" ] - - begin ; @knife.run ; rescue SystemExit ; end - - @stdout.string.should eq "USAGE: knife node run_list set NODE ENTRIES (options)\n" - @stderr.string.should eq "FATAL: You must supply both a node name and a run list.\n" - end - end - - end -end diff --git a/spec/unit/knife/node_show_spec.rb b/spec/unit/knife/node_show_spec.rb deleted file mode 100644 index 4806354b60..0000000000 --- a/spec/unit/knife/node_show_spec.rb +++ /dev/null @@ -1,65 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef::Knife::NodeShow do - - let(:node) do - node = Chef::Node.new() - node.name("adam") - node.run_list = ['role[base]'] - node - end - - let(:knife) do - knife = Chef::Knife::NodeShow.new - knife.name_args = [ "adam" ] - knife - end - - before(:each) do - Chef::Config[:node_name] = "webmonkey.example.com" - end - - describe "run" do - it "should load the node" do - expect(Chef::Node).to receive(:load).with("adam").and_return(node) - allow(knife).to receive(:output).and_return(true) - knife.run - end - - it "should pretty print the node, formatted for display" do - knife.config[:format] = nil - stdout = StringIO.new - allow(knife.ui).to receive(:stdout).and_return(stdout) - allow(Chef::Node).to receive(:load).and_return(node) - knife.run - expect(stdout.string).to eql("Node Name: adam\nEnvironment: _default\nFQDN: \nIP: \nRun List: \nRoles: \nRecipes: \nPlatform: \nTags: \n") - end - - it "should pretty print json" do - 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) - 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 - end -end diff --git a/spec/unit/knife/role_bulk_delete_spec.rb b/spec/unit/knife/role_bulk_delete_spec.rb deleted file mode 100644 index eb1d3b4cff..0000000000 --- a/spec/unit/knife/role_bulk_delete_spec.rb +++ /dev/null @@ -1,80 +0,0 @@ -# -# Author:: Stephen Delano (<stephen@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. -# - -require 'spec_helper' - -describe Chef::Knife::RoleBulkDelete do - before(:each) do - Chef::Config[:node_name] = "webmonkey.example.com" - @knife = Chef::Knife::RoleBulkDelete.new - @knife.config = { - :print_after => nil - } - @knife.name_args = ["."] - @stdout = StringIO.new - @knife.ui.stub(:stdout).and_return(@stdout) - @knife.ui.stub(:confirm).and_return(true) - @roles = Hash.new - %w{dev staging production}.each do |role_name| - role = Chef::Role.new() - role.name(role_name) - role.stub(:destroy).and_return(true) - @roles[role_name] = role - end - Chef::Role.stub(:list).and_return(@roles) - end - - describe "run" do - - it "should get the list of the roles" do - Chef::Role.should_receive(:list).and_return(@roles) - @knife.run - end - - it "should print the roles you are about to delete" do - @knife.run - @stdout.string.should match(/#{@knife.ui.list(@roles.keys.sort, :columns_down)}/) - end - - it "should confirm you really want to delete them" do - @knife.ui.should_receive(:confirm) - @knife.run - end - - it "should delete each role" do - @roles.each_value do |r| - r.should_receive(:destroy) - end - @knife.run - end - - it "should only delete roles that match the regex" do - @knife.name_args = ["dev"] - @roles["dev"].should_receive(:destroy) - @roles["staging"].should_not_receive(:destroy) - @roles["production"].should_not_receive(:destroy) - @knife.run - end - - it "should exit if the regex is not provided" do - @knife.name_args = [] - lambda { @knife.run }.should raise_error(SystemExit) - end - - end -end diff --git a/spec/unit/knife/role_create_spec.rb b/spec/unit/knife/role_create_spec.rb deleted file mode 100644 index a4d7392b68..0000000000 --- a/spec/unit/knife/role_create_spec.rb +++ /dev/null @@ -1,80 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef::Knife::RoleCreate do - before(:each) do - Chef::Config[:node_name] = "webmonkey.example.com" - @knife = Chef::Knife::RoleCreate.new - @knife.config = { - :description => nil - } - @knife.name_args = [ "adam" ] - @knife.stub(:output).and_return(true) - @role = Chef::Role.new() - @role.stub(:save) - Chef::Role.stub(:new).and_return(@role) - @knife.stub(:edit_data).and_return(@role) - @stdout = StringIO.new - @knife.ui.stub(:stdout).and_return(@stdout) - end - - describe "run" do - it "should create a new role" do - Chef::Role.should_receive(:new).and_return(@role) - @knife.run - end - - it "should set the role name" do - @role.should_receive(:name).with("adam") - @knife.run - end - - it "should not print the role" do - @knife.should_not_receive(:output) - @knife.run - end - - it "should allow you to edit the data" do - @knife.should_receive(:edit_data).with(@role) - @knife.run - end - - it "should save the role" do - @role.should_receive(:save) - @knife.run - end - - describe "with -d or --description" do - it "should set the description" do - @knife.config[:description] = "All is bob" - @role.should_receive(:description).with("All is bob") - @knife.run - end - end - - describe "with -p or --print-after" do - it "should pretty print the node, formatted for display" do - @knife.config[:print_after] = true - @knife.should_receive(:output).with(@role) - @knife.run - end - end - end -end diff --git a/spec/unit/knife/role_delete_spec.rb b/spec/unit/knife/role_delete_spec.rb deleted file mode 100644 index 0771446d49..0000000000 --- a/spec/unit/knife/role_delete_spec.rb +++ /dev/null @@ -1,67 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef::Knife::RoleDelete do - before(:each) do - Chef::Config[:node_name] = "webmonkey.example.com" - @knife = Chef::Knife::RoleDelete.new - @knife.config = { - :print_after => nil - } - @knife.name_args = [ "adam" ] - @knife.stub(:output).and_return(true) - @knife.stub(:confirm).and_return(true) - @role = Chef::Role.new() - @role.stub(:destroy).and_return(true) - Chef::Role.stub(:load).and_return(@role) - @stdout = StringIO.new - @knife.ui.stub(:stdout).and_return(@stdout) - end - - describe "run" do - it "should confirm that you want to delete" do - @knife.should_receive(:confirm) - @knife.run - end - - it "should load the Role" do - Chef::Role.should_receive(:load).with("adam").and_return(@role) - @knife.run - end - - it "should delete the Role" do - @role.should_receive(:destroy).and_return(@role) - @knife.run - end - - it "should not print the Role" do - @knife.should_not_receive(:output) - @knife.run - end - - describe "with -p or --print-after" do - it "should pretty print the Role, formatted for display" do - @knife.config[:print_after] = true - @knife.should_receive(:output) - @knife.run - end - end - end -end diff --git a/spec/unit/knife/role_edit_spec.rb b/spec/unit/knife/role_edit_spec.rb deleted file mode 100644 index f6d3b41d98..0000000000 --- a/spec/unit/knife/role_edit_spec.rb +++ /dev/null @@ -1,79 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef::Knife::RoleEdit do - before(:each) do - Chef::Config[:node_name] = "webmonkey.example.com" - @knife = Chef::Knife::RoleEdit.new - @knife.config[:print_after] = nil - @knife.name_args = [ "adam" ] - @knife.ui.stub(:output).and_return(true) - @role = Chef::Role.new() - @role.stub(:save) - Chef::Role.stub(:load).and_return(@role) - @knife.ui.stub(:edit_data).and_return(@role) - @knife.ui.stub(:msg) - end - - describe "run" do - it "should load the role" do - Chef::Role.should_receive(:load).with("adam").and_return(@role) - @knife.run - end - - it "should edit the role data" do - @knife.ui.should_receive(:edit_data).with(@role) - @knife.run - end - - it "should save the edited role data" do - pansy = Chef::Role.new - - @role.name("new_role_name") - @knife.ui.should_receive(:edit_data).with(@role).and_return(pansy) - pansy.should_receive(:save) - @knife.run - end - - it "should not save the unedited role data" do - pansy = Chef::Role.new - - @knife.ui.should_receive(:edit_data).with(@role).and_return(pansy) - pansy.should_not_receive(:save) - @knife.run - - end - - it "should not print the role" do - @knife.ui.should_not_receive(:output) - @knife.run - end - - describe "with -p or --print-after" do - it "should pretty print the role, formatted for display" do - @knife.config[:print_after] = true - @knife.ui.should_receive(:output).with(@role) - @knife.run - end - end - end -end - - diff --git a/spec/unit/knife/role_from_file_spec.rb b/spec/unit/knife/role_from_file_spec.rb deleted file mode 100644 index 986414647c..0000000000 --- a/spec/unit/knife/role_from_file_spec.rb +++ /dev/null @@ -1,69 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -Chef::Knife::RoleFromFile.load_deps - -describe Chef::Knife::RoleFromFile do - before(:each) do - Chef::Config[:node_name] = "webmonkey.example.com" - @knife = Chef::Knife::RoleFromFile.new - @knife.config = { - :print_after => nil - } - @knife.name_args = [ "adam.rb" ] - @knife.stub(:output).and_return(true) - @knife.stub(:confirm).and_return(true) - @role = Chef::Role.new() - @role.stub(:save) - @knife.loader.stub(:load_from).and_return(@role) - @stdout = StringIO.new - @knife.ui.stub(:stdout).and_return(@stdout) - end - - describe "run" do - it "should load from a file" do - @knife.loader.should_receive(:load_from).with('roles', 'adam.rb').and_return(@role) - @knife.run - end - - it "should not print the role" do - @knife.should_not_receive(:output) - @knife.run - end - - describe "with -p or --print-after" do - it "should print the role" do - @knife.config[:print_after] = true - @knife.should_receive(:output) - @knife.run - end - end - end - - describe "run with multiple arguments" do - it "should load each file" do - @knife.name_args = [ "adam.rb", "caleb.rb" ] - @knife.loader.should_receive(:load_from).with('roles', 'adam.rb').and_return(@role) - @knife.loader.should_receive(:load_from).with('roles', 'caleb.rb').and_return(@role) - @knife.run - end - end - -end diff --git a/spec/unit/knife/role_list_spec.rb b/spec/unit/knife/role_list_spec.rb deleted file mode 100644 index ef9642c04c..0000000000 --- a/spec/unit/knife/role_list_spec.rb +++ /dev/null @@ -1,56 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef::Knife::RoleList do - before(:each) do - Chef::Config[:node_name] = "webmonkey.example.com" - @knife = Chef::Knife::RoleList.new - @knife.stub(:output).and_return(true) - @list = { - "foo" => "http://example.com/foo", - "bar" => "http://example.com/foo" - } - Chef::Role.stub(:list).and_return(@list) - end - - describe "run" do - it "should list the roles" do - Chef::Role.should_receive(:list).and_return(@list) - @knife.run - end - - it "should pretty print the list" do - Chef::Role.should_receive(:list).and_return(@list) - @knife.should_receive(:output).with([ "bar", "foo" ]) - @knife.run - end - - describe "with -w or --with-uri" do - it "should pretty print the hash" do - @knife.config[:with_uri] = true - Chef::Role.should_receive(:list).and_return(@list) - @knife.should_receive(:output).with(@list) - @knife.run - end - end - end -end - - diff --git a/spec/unit/knife/role_show_spec.rb b/spec/unit/knife/role_show_spec.rb deleted file mode 100644 index b086136186..0000000000 --- a/spec/unit/knife/role_show_spec.rb +++ /dev/null @@ -1,59 +0,0 @@ -# -# Author:: Lamont Granquist (<lamont@getchef.com>) -# Copyright:: Copyright (c) 2014 Lamont Granquist -# 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::RoleShow do - let(:role) { 'base' } - - let(:knife) do - knife = Chef::Knife::RoleShow.new - knife.name_args = [ role ] - knife - end - - 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) - expect(knife).to receive(:format_for_display).with(role_mock) - knife.run - end - - 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) - knife.run - expect(stdout.string).to eql("{\n \"foo\": \"bar\",\n \"baz\": \"qux\"\n}\n") - end - - context "without a role name" do - let(:role) { } - - 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) - end - end - end -end diff --git a/spec/unit/knife/ssh_spec.rb b/spec/unit/knife/ssh_spec.rb deleted file mode 100644 index 10d63c9c74..0000000000 --- a/spec/unit/knife/ssh_spec.rb +++ /dev/null @@ -1,395 +0,0 @@ -# -# Author:: Bryan McLellan <btm@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 'net/ssh' -require 'net/ssh/multi' - -describe Chef::Knife::Ssh do - before(:each) do - Chef::Config[:client_key] = CHEF_SPEC_DATA + "/ssl/private_key.pem" - end - - 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" - end - - describe "#configure_session" do - context "manual is set to false (default)" do - before do - @knife.config[:manual] = false - @query = Chef::Search::Query.new - end - - def configure_query(node_array) - @query.stub(:search).and_return([node_array]) - Chef::Search::Query.stub(:new).and_return(@query) - end - - 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" - configure_query([@node_foo, @node_bar]) - @knife.should_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 - configure_query([@node_foo, @node_bar]) - @knife.should_receive(:session_from_list).with([['10.0.0.1', nil], ['10.0.0.2', nil]]) - @knife.configure_session - end - end - - it "searchs for and returns an array of fqdns" do - configure_query([@node_foo, @node_bar]) - @knife.should_receive(:session_from_list).with([ - ['foo.example.org', nil], - ['bar.example.org', nil] - ]) - @knife.configure_session - end - - should_return_specified_attributes - - context "when cloud hostnames are available" do - before 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]) - @knife.should_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] - ]) - @knife.configure_session - end - - should_return_specified_attributes - end - - it "should raise an error if no host are found" do - configure_query([ ]) - @knife.ui.should_receive(:fatal) - @knife.should_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 - before do - @query.stub(:search).and_return([[@node_foo, @node_bar]]) - @node_foo.automatic_attrs[:fqdn] = nil - @node_bar.automatic_attrs[:fqdn] = nil - Chef::Search::Query.stub(:new).and_return(@query) - end - - it "should raise a specific error (CHEF-3402)" do - @knife.ui.should_receive(:fatal).with(/^2 nodes found/) - @knife.should_receive(:exit).with(10) - @knife.configure_session - end - end - end - - context "manual is set to true" do - before do - @knife.config[:manual] = true - end - - it "returns an array of provided values" do - @knife.instance_variable_set(:@name_args, ["foo.example.org bar.example.org"]) - @knife.should_receive(:session_from_list).with(['foo.example.org', 'bar.example.org']) - @knife.configure_session - end - end - end - - describe "#configure_attribute" do - before do - Chef::Config[:knife][:ssh_attribute] = nil - @knife.config[:attribute] = nil - end - - it "should return fqdn by default" do - @knife.configure_attribute - @knife.config[:attribute].should == "fqdn" - end - - it "should return the value set in the configuration file" do - Chef::Config[:knife][:ssh_attribute] = "config_file" - @knife.configure_attribute - @knife.config[:attribute].should == "config_file" - end - - it "should return the value set on the command line" do - @knife.config[:attribute] = "command_line" - @knife.configure_attribute - @knife.config[:attribute].should == "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 - @knife.config[:attribute].should == "command_line" - @knife.config[:attribute_from_cli].should == "command_line" - 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 - @knife.config[:attribute].should == "command_line" - @knife.config[:attribute_from_cli].should == "command_line" - end - end - - describe "#session_from_list" do - before :each do - @knife.instance_variable_set(:@longest, 0) - ssh_config = {:timeout => 50, :user => "locutus", :port => 23 } - Net::SSH.stub(: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.servers[0].port.should == 23 - end - - it "uses the port from a cloud attr" do - @knife.session_from_list([['the.b.org', 123]]) - @knife.session.servers[0].port.should == 123 - end - - it "uses the user from an ssh config file" do - @knife.session_from_list([['the.b.org', 123]]) - @knife.session.servers[0].user.should == "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(:execution_channel2) { double(:execution_channel, :on_data => nil) } - let(:session_channel2) { double(:session_channel, :request_pty => nil)} - - let(:session) { double(:session, :loop => nil) } - - let(:command) { "false" } - - before do - execution_channel. - should_receive(:on_request). - and_yield(nil, double(:data_stream, :read_long => exit_status)) - - session_channel. - should_receive(:exec). - with(command). - and_yield(execution_channel, true) - - execution_channel2. - should_receive(:on_request). - and_yield(nil, double(:data_stream, :read_long => exit_status2)) - - session_channel2. - should_receive(:exec). - with(command). - and_yield(execution_channel2, true) - - session. - should_receive(:open_channel). - and_yield(session_channel). - and_yield(session_channel2) - end - - context "both connections return 0" do - let(:exit_status) { 0 } - let(:exit_status2) { 0 } - - it "returns a 0 exit code" do - @knife.ssh_command(command, session).should == 0 - end - end - - context "the first connection returns 1 and the second returns 0" do - let(:exit_status) { 1 } - let(:exit_status2) { 0 } - - it "returns a non-zero exit code" do - @knife.ssh_command(command, session).should == 1 - end - end - - context "the first connection returns 1 and the second returns 2" do - let(:exit_status) { 1 } - let(:exit_status2) { 2 } - - it "returns a non-zero exit code" do - @knife.ssh_command(command, session).should == 2 - end - end - end - - describe "#run" do - before do - @query = Chef::Search::Query.new - @query.should_receive(:search).and_return([[@node_foo]]) - Chef::Search::Query.stub(:new).and_return(@query) - @knife.stub(:ssh_command).and_return(exit_code) - @knife.name_args = ['*:*', 'false'] - end - - context "with an error" do - let(:exit_code) { 1 } - - it "should exit with a non-zero exit code" do - @knife.should_receive(:exit).with(exit_code) - @knife.run - end - end - - context "with no error" do - let(:exit_code) { 0 } - - it "should not exit" do - @knife.should_not_receive(:exit) - @knife.run - end - end - end - - describe "#configure_password" do - before do - @knife.config.delete(:ssh_password_ng) - @knife.config.delete(:ssh_password) - 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 - @knife.config[:ssh_password_ng] = nil - @knife.should_receive(:get_password).and_return("mysekretpassw0rd") - @knife.configure_password - @knife.config[:ssh_password].should == "mysekretpassw0rd" - end - - it "should set ssh_password to false if ssh_password_ng is false" do - @knife.config[:ssh_password_ng] = false - @knife.should_not_receive(:get_password) - @knife.configure_password - @knife.config[:ssh_password].should be_false - end - - it "should set ssh_password to ssh_password_ng if we set a password" do - @knife.config[:ssh_password_ng] = "mysekretpassw0rd" - @knife.should_not_receive(:get_password) - @knife.configure_password - @knife.config[:ssh_password].should == "mysekretpassw0rd" - end - end - - context "when setting ssh_password from knife bootstrap / knife * server create" do - # in this case ssh_password exists, but ssh_password_ng does not - it "should set ssh_password to nil when ssh_password is nil" do - @knife.config[:ssh_password] = nil - @knife.should_not_receive(:get_password) - @knife.configure_password - @knife.config[:ssh_password].should be_nil - end - - it "should set ssh_password to false when ssh_password is false" do - @knife.config[:ssh_password] = false - @knife.should_not_receive(:get_password) - @knife.configure_password - @knife.config[:ssh_password].should be_false - end - - it "should set ssh_password to ssh_password if we set a password" do - @knife.config[:ssh_password] = "mysekretpassw0rd" - @knife.should_not_receive(:get_password) - @knife.configure_password - @knife.config[:ssh_password].should == "mysekretpassw0rd" - end - end - context "when setting ssh_password in the config variable" do - before(:each) do - Chef::Config[:knife][:ssh_password] = "my_knife_passw0rd" - 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 - @knife.config[:ssh_password_ng] = nil - @knife.should_receive(:get_password).and_return("mysekretpassw0rd") - @knife.configure_password - @knife.config[:ssh_password].should == "mysekretpassw0rd" - end - - it "should set ssh_password to the configured knife.rb value if ssh_password_ng is false" do - @knife.config[:ssh_password_ng] = false - @knife.should_not_receive(:get_password) - @knife.configure_password - @knife.config[:ssh_password].should == "my_knife_passw0rd" - end - - it "should set ssh_password to ssh_password_ng if we set a password" do - @knife.config[:ssh_password_ng] = "mysekretpassw0rd" - @knife.should_not_receive(:get_password) - @knife.configure_password - @knife.config[:ssh_password].should == "mysekretpassw0rd" - end - end - - context "when setting ssh_password from knife bootstrap / knife * server create" do - # in this case ssh_password exists, but ssh_password_ng does not - it "should set ssh_password to the configured knife.rb value when ssh_password is nil" do - @knife.config[:ssh_password] = nil - @knife.should_not_receive(:get_password) - @knife.configure_password - @knife.config[:ssh_password].should == "my_knife_passw0rd" - end - - it "should set ssh_password to the configured knife.rb value when ssh_password is false" do - @knife.config[:ssh_password] = false - @knife.should_not_receive(:get_password) - @knife.configure_password - @knife.config[:ssh_password].should == "my_knife_passw0rd" - end - - it "should set ssh_password to ssh_password if we set a password" do - @knife.config[:ssh_password] = "mysekretpassw0rd" - @knife.should_not_receive(:get_password) - @knife.configure_password - @knife.config[:ssh_password].should == "mysekretpassw0rd" - end - end - end - end -end diff --git a/spec/unit/knife/ssl_check_spec.rb b/spec/unit/knife/ssl_check_spec.rb deleted file mode 100644 index bb803ce2ca..0000000000 --- a/spec/unit/knife/ssl_check_spec.rb +++ /dev/null @@ -1,232 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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 'stringio' - -describe Chef::Knife::SslCheck do - - let(:name_args) { [] } - let(:stdout_io) { StringIO.new } - let(:stderr_io) { StringIO.new } - - def stderr - stderr_io.string - end - - def stdout - stdout_io.string - end - - subject(:ssl_check) do - s = Chef::Knife::SslCheck.new - s.ui.stub(:stdout).and_return(stdout_io) - s.ui.stub(:stderr).and_return(stderr_io) - s.name_args = name_args - s - end - - before do - Chef::Config.chef_server_url = "https://example.com:8443/chef-server" - end - - context "when no arguments are given" do - it "uses the chef_server_url as the host to check" do - expect(ssl_check.host).to eq("example.com") - expect(ssl_check.port).to eq(8443) - end - end - - context "when a specific URI is given" do - let(:name_args) { %w{https://example.test:10443/foo} } - - it "checks the SSL configuration against the given host" do - expect(ssl_check.host).to eq("example.test") - expect(ssl_check.port).to eq(10443) - end - end - - context "when an invalid URI is given" do - - let(:name_args) { %w{foo.test} } - - it "prints an error and exits" do - expect { ssl_check.run }.to raise_error(SystemExit) - expected_stdout=<<-E -USAGE: knife ssl check [URL] (options) -E - expected_stderr=<<-E -ERROR: Given URI: `foo.test' is invalid -E - expect(stdout_io.string).to eq(expected_stdout) - expect(stderr_io.string).to eq(expected_stderr) - end - - context "and its malformed enough to make URI.parse barf" do - - let(:name_args) { %w{ftp://lkj\\blah:example.com/blah} } - - it "prints an error and exits" do - expect { ssl_check.run }.to raise_error(SystemExit) - expected_stdout=<<-E -USAGE: knife ssl check [URL] (options) -E - expected_stderr=<<-E -ERROR: Given URI: `#{name_args[0]}' is invalid -E - expect(stdout_io.string).to eq(expected_stdout) - expect(stderr_io.string).to eq(expected_stderr) - end - end - end - - describe "verifying trusted certificate X509 properties" do - let(:name_args) { %w{https://foo.example.com:8443} } - - let(:trusted_certs_dir) { File.join(CHEF_SPEC_DATA, "trusted_certs") } - let(:trusted_cert_file) { File.join(trusted_certs_dir, "example.crt") } - - let(:store) { OpenSSL::X509::Store.new } - let(:certificate) { OpenSSL::X509::Certificate.new(IO.read(trusted_cert_file)) } - - before do - Chef::Config[:trusted_certs_dir] = trusted_certs_dir - ssl_check.stub(:trusted_certificates).and_return([trusted_cert_file]) - store.stub(:add_cert).with(certificate) - OpenSSL::X509::Store.stub(:new).and_return(store) - OpenSSL::X509::Certificate.stub(:new).with(IO.read(trusted_cert_file)).and_return(certificate) - ssl_check.stub(:verify_cert).and_return(true) - ssl_check.stub(:verify_cert_host).and_return(true) - end - - context "when the trusted certificates have valid X509 properties" do - before do - store.stub(:verify).with(certificate).and_return(true) - end - - it "does not generate any X509 warnings" do - expect(ssl_check.ui).not_to receive(:warn).with(/There are invalid certificates in your trusted_certs_dir/) - ssl_check.run - end - end - - context "when the trusted certificates have invalid X509 properties" do - before do - store.stub(:verify).with(certificate).and_return(false) - store.stub(:error_string).and_return("unable to get local issuer certificate") - end - - it "generates a warning message with invalid certificate file names" do - expect(ssl_check.ui).to receive(:warn).with(/#{trusted_cert_file}: unable to get local issuer certificate/) - ssl_check.run - end - end - end - - describe "verifying the remote certificate" do - let(:name_args) { %w{https://foo.example.com:8443} } - - let(:tcp_socket) { double(TCPSocket) } - let(:ssl_socket) { double(OpenSSL::SSL::SSLSocket) } - - before do - TCPSocket.should_receive(:new).with("foo.example.com", 8443).and_return(tcp_socket) - OpenSSL::SSL::SSLSocket.should_receive(:new).with(tcp_socket, ssl_check.verify_peer_ssl_context).and_return(ssl_socket) - end - - def run - ssl_check.run - rescue Exception - #puts "OUT: #{stdout_io.string}" - #puts "ERR: #{stderr_io.string}" - raise - end - - context "when the remote host's certificate is valid" do - - before do - ssl_check.should_receive(:verify_X509).and_return(true) # X509 valid certs (no warn) - ssl_socket.should_receive(:connect) # no error - ssl_socket.should_receive(:post_connection_check).with("foo.example.com") # no error - end - - it "prints a success message" do - ssl_check.run - expect(stdout_io.string).to include("Successfully verified certificates from `foo.example.com'") - end - end - - describe "and the certificate is not valid" do - - let(:tcp_socket_for_debug) { double(TCPSocket) } - let(:ssl_socket_for_debug) { double(OpenSSL::SSL::SSLSocket) } - - let(:self_signed_crt_path) { File.join(CHEF_SPEC_DATA, "trusted_certs", "example.crt") } - let(:self_signed_crt) { OpenSSL::X509::Certificate.new(File.read(self_signed_crt_path)) } - - before do - trap(:INT, "DEFAULT") - - TCPSocket.should_receive(:new). - with("foo.example.com", 8443). - and_return(tcp_socket_for_debug) - OpenSSL::SSL::SSLSocket.should_receive(:new). - with(tcp_socket_for_debug, ssl_check.noverify_peer_ssl_context). - and_return(ssl_socket_for_debug) - end - - context "when the certificate's CN does not match the hostname" do - before do - ssl_check.should_receive(:verify_X509).and_return(true) # X509 valid certs - ssl_socket.should_receive(:connect) # no error - ssl_socket.should_receive(:post_connection_check). - with("foo.example.com"). - and_raise(OpenSSL::SSL::SSLError) - ssl_socket_for_debug.should_receive(:connect) - ssl_socket_for_debug.should_receive(:peer_cert).and_return(self_signed_crt) - end - - it "shows the CN used by the certificate and prints an error" do - expect { run }.to raise_error(SystemExit) - expect(stderr).to include("The SSL cert is signed by a trusted authority but is not valid for the given hostname") - expect(stderr).to include("You are attempting to connect to: 'foo.example.com'") - expect(stderr).to include("The server's certificate belongs to 'example.local'") - end - - end - - context "when the cert is not signed by any trusted authority" do - before do - ssl_check.should_receive(:verify_X509).and_return(true) # X509 valid certs - ssl_socket.should_receive(:connect). - and_raise(OpenSSL::SSL::SSLError) - ssl_socket_for_debug.should_receive(:connect) - ssl_socket_for_debug.should_receive(:peer_cert).and_return(self_signed_crt) - end - - it "shows the CN used by the certificate and prints an error" do - expect { run }.to raise_error(SystemExit) - expect(stderr).to include("The SSL certificate of foo.example.com could not be verified") - end - - end - end - - end - -end diff --git a/spec/unit/knife/ssl_fetch_spec.rb b/spec/unit/knife/ssl_fetch_spec.rb deleted file mode 100644 index 0d3c8913f7..0000000000 --- a/spec/unit/knife/ssl_fetch_spec.rb +++ /dev/null @@ -1,151 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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 'chef/knife/ssl_fetch' - -describe Chef::Knife::SslFetch do - - let(:name_args) { [] } - let(:stdout_io) { StringIO.new } - let(:stderr_io) { StringIO.new } - - def stderr - stderr_io.string - end - - def stdout - stdout_io.string - end - - subject(:ssl_fetch) do - s = Chef::Knife::SslFetch.new - s.name_args = name_args - s.ui.stub(:stdout).and_return(stdout_io) - s.ui.stub(:stderr).and_return(stderr_io) - s - end - - context "when no arguments are given" do - - before do - Chef::Config.chef_server_url = "https://example.com:8443/chef-server" - end - - it "uses the chef_server_url as the host to fetch" do - expect(ssl_fetch.host).to eq("example.com") - expect(ssl_fetch.port).to eq(8443) - end - end - - context "when a specific URI is given" do - let(:name_args) { %w{https://example.test:10443/foo} } - - it "fetchs the SSL configuration against the given host" do - expect(ssl_fetch.host).to eq("example.test") - expect(ssl_fetch.port).to eq(10443) - end - end - - context "when an invalid URI is given" do - - let(:name_args) { %w{foo.test} } - - it "prints an error and exits" do - expect { ssl_fetch.run }.to raise_error(SystemExit) - expected_stdout=<<-E -USAGE: knife ssl fetch [URL] (options) -E - expected_stderr=<<-E -ERROR: Given URI: `foo.test' is invalid -E - expect(stdout_io.string).to eq(expected_stdout) - expect(stderr_io.string).to eq(expected_stderr) - end - - context "and its malformed enough to make URI.parse barf" do - - let(:name_args) { %w{ftp://lkj\\blah:example.com/blah} } - - it "prints an error and exits" do - expect { ssl_fetch.run }.to raise_error(SystemExit) - expected_stdout=<<-E -USAGE: knife ssl fetch [URL] (options) -E - expected_stderr=<<-E -ERROR: Given URI: `#{name_args[0]}' is invalid -E - expect(stdout_io.string).to eq(expected_stdout) - expect(stderr_io.string).to eq(expected_stderr) - end - end - end - - describe "normalizing CNs for use as paths" do - - it "normalizes '*' to 'wildcard'" do - expect(ssl_fetch.normalize_cn("*.example.com")).to eq("wildcard_example_com") - end - - it "normalizes non-alnum and hyphen characters to underscores" do - expect(ssl_fetch.normalize_cn("Billy-Bob's Super Awesome CA!")).to eq("Billy-Bob_s_Super_Awesome_CA_") - end - - end - - describe "fetching the remote cert chain" do - - let(:name_args) { %w{https://foo.example.com:8443} } - - let(:tcp_socket) { double(TCPSocket) } - let(:ssl_socket) { double(OpenSSL::SSL::SSLSocket) } - - let(:self_signed_crt_path) { File.join(CHEF_SPEC_DATA, "trusted_certs", "example.crt") } - let(:self_signed_crt) { OpenSSL::X509::Certificate.new(File.read(self_signed_crt_path)) } - - let(:trusted_certs_dir) { Dir.mktmpdir } - - def run - ssl_fetch.run - rescue Exception - puts "OUT: #{stdout_io.string}" - puts "ERR: #{stderr_io.string}" - raise - end - - before do - Chef::Config.trusted_certs_dir = trusted_certs_dir - - TCPSocket.should_receive(:new).with("foo.example.com", 8443).and_return(tcp_socket) - OpenSSL::SSL::SSLSocket.should_receive(:new).with(tcp_socket, ssl_fetch.noverify_peer_ssl_context).and_return(ssl_socket) - ssl_socket.should_receive(:connect) - ssl_socket.should_receive(:peer_cert_chain).and_return([self_signed_crt]) - end - - after do - FileUtils.rm_rf(trusted_certs_dir) - end - - it "fetches the cert chain and writes the certs to the trusted_certs_dir" do - run - stored_cert_path = File.join(trusted_certs_dir, "example_local.crt") - expect(File).to exist(stored_cert_path) - expect(File.read(stored_cert_path)).to eq(File.read(self_signed_crt_path)) - end - end -end diff --git a/spec/unit/knife/status_spec.rb b/spec/unit/knife/status_spec.rb deleted file mode 100644 index 6d8d9d5b25..0000000000 --- a/spec/unit/knife/status_spec.rb +++ /dev/null @@ -1,43 +0,0 @@ -# -# Author:: Sahil Muthoo (<sahil.muthoo@gmail.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 'highline' - -describe Chef::Knife::Status do - before(:each) do - node = Chef::Node.new.tap do |n| - n.automatic_attrs["fqdn"] = "foobar" - n.automatic_attrs["ohai_time"] = 1343845969 - end - query = double("Chef::Search::Query") - query.stub(:search).and_yield(node) - Chef::Search::Query.stub(:new).and_return(query) - @knife = Chef::Knife::Status.new - @stdout = StringIO.new - @knife.stub(:highline).and_return(HighLine.new(StringIO.new, @stdout)) - end - - describe "run" do - it "should not colorize output unless it's writing to a tty" do - @knife.run - @stdout.string.match(/foobar/).should_not be_nil - @stdout.string.match(/\e.*ago/).should be_nil - end - end -end diff --git a/spec/unit/knife/tag_create_spec.rb b/spec/unit/knife/tag_create_spec.rb deleted file mode 100644 index bafea8d268..0000000000 --- a/spec/unit/knife/tag_create_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -require 'spec_helper' - -describe Chef::Knife::TagCreate do - before(:each) do - Chef::Config[:node_name] = "webmonkey.example.com" - @knife = Chef::Knife::TagCreate.new - @knife.name_args = [ Chef::Config[:node_name], "happytag" ] - - @node = Chef::Node.new - @node.stub :save - Chef::Node.stub(:load).and_return @node - @stderr = StringIO.new - @knife.ui.stub(:stderr).and_return(@stderr) - end - - describe "run" do - it "can create tags on a node" do - @knife.run - @node.tags.should == ["happytag"] - @stderr.string.should match /created tags happytag.+node webmonkey.example.com/i - end - end -end diff --git a/spec/unit/knife/tag_delete_spec.rb b/spec/unit/knife/tag_delete_spec.rb deleted file mode 100644 index 514228f0a2..0000000000 --- a/spec/unit/knife/tag_delete_spec.rb +++ /dev/null @@ -1,25 +0,0 @@ -require 'spec_helper' - -describe Chef::Knife::TagDelete do - before(:each) do - Chef::Config[:node_name] = "webmonkey.example.com" - @knife = Chef::Knife::TagDelete.new - @knife.name_args = [ Chef::Config[:node_name], "sadtag" ] - - @node = Chef::Node.new - @node.stub :save - @node.tags << "sadtag" << "happytag" - Chef::Node.stub(:load).and_return @node - @stderr = StringIO.new - @knife.ui.stub(:stderr).and_return(@stderr) - end - - describe "run" do - it "can delete tags on a node" do - @node.tags.should == ["sadtag", "happytag"] - @knife.run - @node.tags.should == ["happytag"] - @stderr.string.should match /deleted.+sadtag/i - end - end -end diff --git a/spec/unit/knife/tag_list_spec.rb b/spec/unit/knife/tag_list_spec.rb deleted file mode 100644 index 3724a5c0b7..0000000000 --- a/spec/unit/knife/tag_list_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -require 'spec_helper' - -describe Chef::Knife::TagList do - before(:each) do - Chef::Config[:node_name] = "webmonkey.example.com" - @knife = Chef::Knife::TagList.new - @knife.name_args = [ Chef::Config[:node_name], "sadtag" ] - - @node = Chef::Node.new - @node.stub :save - @node.tags << "sadtag" << "happytag" - Chef::Node.stub(:load).and_return @node - end - - describe "run" do - it "can list tags on a node" do - expected = %w(sadtag happytag) - @node.tags.should == expected - @knife.should_receive(:output).with(expected) - @knife.run - end - end -end diff --git a/spec/unit/knife/user_create_spec.rb b/spec/unit/knife/user_create_spec.rb deleted file mode 100644 index 58ef868053..0000000000 --- a/spec/unit/knife/user_create_spec.rb +++ /dev/null @@ -1,88 +0,0 @@ -# -# Author:: Steven Danna (<steve@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' - -Chef::Knife::UserCreate.load_deps - -describe Chef::Knife::UserCreate do - before(:each) do - @knife = Chef::Knife::UserCreate.new - - @stdout = StringIO.new - @stderr = StringIO.new - @knife.ui.stub(:stdout).and_return(@stdout) - @knife.ui.stub(: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' - @user.stub(:create).and_return(@user_with_private_key) - Chef::User.stub(:new).and_return(@user) - Chef::User.stub(:from_hash).and_return(@user) - @knife.stub(:edit_data).and_return(@user.to_hash) - end - - it "creates a new user" do - Chef::User.should_receive(:new).and_return(@user) - @user.should_receive(:create) - @knife.run - @stderr.string.should match /created user.+a_user/i - end - - it "sets the password" do - @knife.config[:user_password] = "a_password" - @user.should_receive(:password).with("a_password") - @knife.run - end - - it "exits with an error if password is blank" do - @knife.config[:user_password] = '' - lambda { @knife.run }.should raise_error SystemExit - @stderr.string.should match /You must specify a non-blank password/ - end - - it "sets the user name" do - @user.should_receive(:name).with("a_user") - @knife.run - end - - it "sets the public key if given" do - @knife.config[:user_key] = "/a/filename" - File.stub(:read).with(File.expand_path("/a/filename")).and_return("a_key") - @user.should_receive(:public_key).with("a_key") - @knife.run - end - - it "allows you to edit the data" do - @knife.should_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") - filehandle.should_receive(:print).with('private_key') - File.should_receive(:open).with("/tmp/a_file", "w").and_yield(filehandle) - @knife.run - end -end diff --git a/spec/unit/knife/user_delete_spec.rb b/spec/unit/knife/user_delete_spec.rb deleted file mode 100644 index be027e5128..0000000000 --- a/spec/unit/knife/user_delete_spec.rb +++ /dev/null @@ -1,39 +0,0 @@ -# -# Author:: Steven Danna (<steve@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::Knife::UserDelete do - before(:each) do - Chef::Knife::UserDelete.load_deps - @knife = Chef::Knife::UserDelete.new - @knife.name_args = [ 'my_user' ] - end - - it 'deletes the user' do - @knife.should_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 = [] - @knife.should_receive(:show_usage) - @knife.ui.should_receive(:fatal) - lambda { @knife.run }.should raise_error(SystemExit) - end -end diff --git a/spec/unit/knife/user_edit_spec.rb b/spec/unit/knife/user_edit_spec.rb deleted file mode 100644 index 20a4c0d9e9..0000000000 --- a/spec/unit/knife/user_edit_spec.rb +++ /dev/null @@ -1,47 +0,0 @@ -# -# Author:: Steven Danna (<steve@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::Knife::UserEdit do - before(:each) do - @stderr = StringIO.new - @stdout = StringIO.new - - Chef::Knife::UserEdit.load_deps - @knife = Chef::Knife::UserEdit.new - @knife.ui.stub(:stderr).and_return(@stderr) - @knife.ui.stub(: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" } - Chef::User.stub(:load).with("my_user").and_return(data) - @knife.should_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 = [] - @knife.should_receive(:show_usage) - @knife.ui.should_receive(:fatal) - lambda { @knife.run }.should raise_error(SystemExit) - end -end diff --git a/spec/unit/knife/user_list_spec.rb b/spec/unit/knife/user_list_spec.rb deleted file mode 100644 index 7a47f9ddba..0000000000 --- a/spec/unit/knife/user_list_spec.rb +++ /dev/null @@ -1,32 +0,0 @@ -# -# Author:: Steven Danna -# 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::Knife::UserList do - before(:each) do - Chef::Knife::UserList.load_deps - @knife = Chef::Knife::UserList.new - end - - it 'lists the users' do - Chef::User.should_receive(:list) - @knife.should_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 deleted file mode 100644 index 1cbbdb47d2..0000000000 --- a/spec/unit/knife/user_reregister_spec.rb +++ /dev/null @@ -1,53 +0,0 @@ -# -# Author:: Steven Danna (<steve@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::Knife::UserReregister do - before(:each) 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") - Chef::User.stub(:load).and_return(@user_mock) - @stdout = StringIO.new - @knife.ui.stub(:stdout).and_return(@stdout) - end - - it 'prints usage and exits when a user name is not provided' do - @knife.name_args = [] - @knife.should_receive(:show_usage) - @knife.ui.should_receive(:fatal) - lambda { @knife.run }.should raise_error(SystemExit) - end - - it 'reregisters the user and prints the key' do - @user_mock.should_receive(:reregister).and_return(@user_mock) - @knife.run - @stdout.string.should match( /private_key/ ) - end - - it 'writes the private key to a file when --file is specified' do - @user_mock.should_receive(:reregister).and_return(@user_mock) - @knife.config[:file] = '/tmp/a_file' - filehandle = StringIO.new - File.should_receive(:open).with('/tmp/a_file', 'w').and_yield(filehandle) - @knife.run - filehandle.string.should == "private_key" - end -end diff --git a/spec/unit/knife/user_show_spec.rb b/spec/unit/knife/user_show_spec.rb deleted file mode 100644 index af8485ad7d..0000000000 --- a/spec/unit/knife/user_show_spec.rb +++ /dev/null @@ -1,41 +0,0 @@ -# -# Author:: Steven Danna (<steve@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::Knife::UserShow do - before(:each) do - Chef::Knife::UserShow.load_deps - @knife = Chef::Knife::UserShow.new - @knife.name_args = [ 'my_user' ] - @user_mock = double('user_mock') - end - - it 'loads and displays the user' do - Chef::User.should_receive(:load).with('my_user').and_return(@user_mock) - @knife.should_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 = [] - @knife.should_receive(:show_usage) - @knife.ui.should_receive(:fatal) - lambda { @knife.run }.should raise_error(SystemExit) - end -end diff --git a/spec/unit/knife_spec.rb b/spec/unit/knife_spec.rb deleted file mode 100644 index 2db6b40b28..0000000000 --- a/spec/unit/knife_spec.rb +++ /dev/null @@ -1,403 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: Tim Hinderliter (<tim@opscode.com>) -# Copyright:: Copyright (c) 2008, 2011 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. -# - -# Fixtures for subcommand loading live in this namespace -module KnifeSpecs -end - -require 'spec_helper' -require 'uri' - -describe Chef::Knife do - before(:each) do - Chef::Log.logger = Logger.new(StringIO.new) - - Chef::Config[:node_name] = "webmonkey.example.com" - - # Prevent gratuitous code reloading: - Chef::Knife.stub(:load_commands) - @knife = Chef::Knife.new - @knife.ui.stub(:puts) - @knife.ui.stub(:print) - Chef::Log.stub(:init) - Chef::Log.stub(:level) - [:debug, :info, :warn, :error, :crit].each do |level_sym| - Chef::Log.stub(level_sym) - end - Chef::Knife.stub(:puts) - @stderr = StringIO.new - end - - describe "after loading a subcommand" do - before do - Chef::Knife.reset_subcommands! - - if KnifeSpecs.const_defined?(:TestNameMapping) - KnifeSpecs.send(:remove_const, :TestNameMapping) - end - - if KnifeSpecs.const_defined?(:TestExplicitCategory) - 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')) - end - - it "has a category based on its name" do - KnifeSpecs::TestNameMapping.subcommand_category.should == 'test' - end - - it "has an explictly defined category if set" do - KnifeSpecs::TestExplicitCategory.subcommand_category.should == 'cookbook site' - end - - it "can reference the subcommand by its snake cased name" do - Chef::Knife.subcommands['test_name_mapping'].should equal(KnifeSpecs::TestNameMapping) - end - - it "lists subcommands by category" do - Chef::Knife.subcommands_by_category['test'].should include('test_name_mapping') - end - - it "lists subcommands by category when the subcommands have explicit categories" do - Chef::Knife.subcommands_by_category['cookbook site'].should include('test_explicit_category') - end - - it "has empty dependency_loader list by default" do - KnifeSpecs::TestNameMapping.dependency_loaders.should be_empty - end - end - - describe "after loading all subcommands" do - before do - Chef::Knife.reset_subcommands! - Chef::Knife.load_commands - end - - it "references a subcommand class by its snake cased name" do - class SuperAwesomeCommand < Chef::Knife - end - - Chef::Knife.load_commands - - Chef::Knife.subcommands.should have_key("super_awesome_command") - Chef::Knife.subcommands["super_awesome_command"].should == SuperAwesomeCommand - 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 - Chef::Knife.guess_category(%w{cookbook foo bar baz}).should == 'cookbook' - Chef::Knife.guess_category(%w{cookbook site foo bar baz}).should == 'cookbook site' - Chef::Knife.guess_category(%w{cookbook site --help}).should == 'cookbook site' - end - - it "finds a subcommand class based on ARGV" do - Chef::Knife.subcommands["cookbook_site_vendor"] = :CookbookSiteVendor - Chef::Knife.subcommands["cookbook"] = :Cookbook - Chef::Knife.subcommand_class_from(%w{cookbook site vendor --help foo bar baz}).should == :CookbookSiteVendor - end - - end - - 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(:request_id) {"1234"} - - let(:request_mock) { {} } - - let(:rest) do - Net::HTTP.stub(:new).and_return(http_client) - Chef::RequestID.instance.stub(:request_id).and_return(request_id) - Chef::Config.stub(:chef_server_url).and_return("https://api.opscode.piab") - command = Chef::Knife.run(%w{test yourself}) - rest = command.noauth_rest - rest - end - - let!(:http_client) do - http_client = Net::HTTP.new(url.host, url.port) - http_client.stub(:request).and_yield(http_response).and_return(http_response) - http_client - end - - let(:url) { URI.parse("https://api.opscode.piab") } - - let(:http_response) do - http_response = Net::HTTPSuccess.new("1.1", "200", "successful rest req") - http_response.stub(:read_body) - http_response.stub(:body).and_return(body) - http_response["Content-Length"] = body.bytesize.to_s - http_response - end - - let(:body) { "ninja" } - - before(:each) do - Chef::Config[:chef_server_url] = "https://api.opscode.piab" - if KnifeSpecs.const_defined?(:TestYourself) - KnifeSpecs.send :remove_const, :TestYourself - end - 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 - Net::HTTP::Get.should_receive(:new).with("/monkey", headers).and_return(request_mock) - rest.get_rest("monkey") - end - end - - describe "when running a command" do - before(:each) do - if KnifeSpecs.const_defined?(:TestYourself) - KnifeSpecs.send :remove_const, :TestYourself - end - 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"} - - # there is special hackery to return the subcommand instance going on here. - command = Chef::Knife.run(%w{test yourself}, extra_opts) - editor_opts = command.options[:editor] - editor_opts[:long].should == "--editor EDITOR" - editor_opts[:description].should == "Set the editor to use for interactive commands" - editor_opts[:short].should == "-e EDITOR" - editor_opts[:default].should == "/usr/bin/vim" - end - - it "creates an instance of the subcommand and runs it" do - command = Chef::Knife.run(%w{test yourself}) - command.should be_an_instance_of(KnifeSpecs::TestYourself) - command.ran.should be_true - end - - it "passes the command specific args to the subcommand" do - command = Chef::Knife.run(%w{test yourself with some args}) - command.name_args.should == %w{with some args} - end - - it "excludes the command name from the name args when parts are joined with underscores" do - command = Chef::Knife.run(%w{test_yourself with some args}) - command.name_args.should == %w{with some args} - end - - it "exits if no subcommand matches the CLI args" do - Chef::Knife.ui.stub(:stderr).and_return(@stderr) - Chef::Knife.ui.should_receive(:fatal) - lambda {Chef::Knife.run(%w{fuuu uuuu fuuuu})}.should raise_error(SystemExit) { |e| e.status.should_not == 0 } - end - - it "loads lazy dependencies" do - Chef::Knife.run(%w{test yourself}) - KnifeSpecs::TestYourself.test_deps_loaded.should be_true - end - - it "loads lazy dependencies from multiple deps calls" do - other_deps_loaded = false - KnifeSpecs::TestYourself.class_eval do - deps { other_deps_loaded = true } - end - - Chef::Knife.run(%w{test yourself}) - KnifeSpecs::TestYourself.test_deps_loaded.should be_true - other_deps_loaded.should be_true - end - - describe "merging configuration options" do - before do - KnifeSpecs::TestYourself.option(:opt_with_default, - :short => "-D VALUE", - :default => "default-value") - 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 - knife_command.config[:opt_with_default].should == "default-value" - end - - it "prefers a value in Chef::Config[:knife] to the default" do - Chef::Config[:knife][:opt_with_default] = "from-knife-config" - knife_command = KnifeSpecs::TestYourself.new([]) #empty argv - knife_command.configure_chef - knife_command.config[:opt_with_default].should == "from-knife-config" - end - - it "prefers a value from command line over Chef::Config and the default" do - Chef::Config[:knife][:opt_with_default] = "from-knife-config" - knife_command = KnifeSpecs::TestYourself.new(["-D", "from-cli"]) - knife_command.configure_chef - knife_command.config[:opt_with_default].should == "from-cli" - end - end - - end - - describe "when first created" do - before do - unless KnifeSpecs.const_defined?(:TestYourself) - Kernel.load(File.join(CHEF_SPEC_DATA, 'knife_subcommand', 'test_yourself.rb')) - end - @knife = KnifeSpecs::TestYourself.new(%w{with some args -s scrogramming}) - end - - it "it parses the options passed to it" do - @knife.config[:scro].should == 'scrogramming' - end - - it "extracts its command specific args from the full arg list" do - @knife.name_args.should == %w{with some args} - end - - it "does not have lazy dependencies loaded" do - @knife.class.test_deps_loaded.should_not be_true - end - end - - describe "when formatting exceptions" do - before do - @stdout, @stderr, @stdin = StringIO.new, StringIO.new, StringIO.new - @knife.ui = Chef::Knife::UI.new(@stdout, @stderr, @stdin, {}) - @knife.should_receive(:exit).with(100) - end - - it "formats 401s nicely" do - response = Net::HTTPUnauthorized.new("1.1", "401", "Unauthorized") - response.instance_variable_set(:@read, true) # I hate you, net/http. - response.stub(:body).and_return(Chef::JSONCompat.to_json(:error => "y u no syncronize your clock?")) - @knife.stub(:run).and_raise(Net::HTTPServerException.new("401 Unauthorized", response)) - @knife.run_with_pretty_exceptions - @stderr.string.should match(/ERROR: Failed to authenticate to/) - @stderr.string.should match(/Response: y u no syncronize your clock\?/) - end - - it "formats 403s nicely" do - response = Net::HTTPForbidden.new("1.1", "403", "Forbidden") - response.instance_variable_set(:@read, true) # I hate you, net/http. - response.stub(:body).and_return(Chef::JSONCompat.to_json(:error => "y u no administrator")) - @knife.stub(:run).and_raise(Net::HTTPServerException.new("403 Forbidden", response)) - @knife.stub(:username).and_return("sadpanda") - @knife.run_with_pretty_exceptions - @stderr.string.should match(%r[ERROR: You authenticated successfully to http.+ as sadpanda but you are not authorized for this action]) - @stderr.string.should match(%r[Response: y u no administrator]) - end - - it "formats 400s nicely" do - response = Net::HTTPBadRequest.new("1.1", "400", "Bad Request") - response.instance_variable_set(:@read, true) # I hate you, net/http. - response.stub(:body).and_return(Chef::JSONCompat.to_json(:error => "y u search wrong")) - @knife.stub(:run).and_raise(Net::HTTPServerException.new("400 Bad Request", response)) - @knife.run_with_pretty_exceptions - @stderr.string.should match(%r[ERROR: The data in your request was invalid]) - @stderr.string.should match(%r[Response: y u search wrong]) - end - - it "formats 404s nicely" do - response = Net::HTTPNotFound.new("1.1", "404", "Not Found") - response.instance_variable_set(:@read, true) # I hate you, net/http. - response.stub(:body).and_return(Chef::JSONCompat.to_json(:error => "nothing to see here")) - @knife.stub(:run).and_raise(Net::HTTPServerException.new("404 Not Found", response)) - @knife.run_with_pretty_exceptions - @stderr.string.should match(%r[ERROR: The object you are looking for could not be found]) - @stderr.string.should match(%r[Response: nothing to see here]) - end - - it "formats 500s nicely" do - response = Net::HTTPInternalServerError.new("1.1", "500", "Internal Server Error") - response.instance_variable_set(:@read, true) # I hate you, net/http. - response.stub(:body).and_return(Chef::JSONCompat.to_json(:error => "sad trombone")) - @knife.stub(:run).and_raise(Net::HTTPFatalError.new("500 Internal Server Error", response)) - @knife.run_with_pretty_exceptions - @stderr.string.should match(%r[ERROR: internal server error]) - @stderr.string.should match(%r[Response: sad trombone]) - end - - it "formats 502s nicely" do - response = Net::HTTPBadGateway.new("1.1", "502", "Bad Gateway") - response.instance_variable_set(:@read, true) # I hate you, net/http. - response.stub(:body).and_return(Chef::JSONCompat.to_json(:error => "sadder trombone")) - @knife.stub(:run).and_raise(Net::HTTPFatalError.new("502 Bad Gateway", response)) - @knife.run_with_pretty_exceptions - @stderr.string.should match(%r[ERROR: bad gateway]) - @stderr.string.should match(%r[Response: sadder trombone]) - end - - it "formats 503s nicely" do - response = Net::HTTPServiceUnavailable.new("1.1", "503", "Service Unavailable") - response.instance_variable_set(:@read, true) # I hate you, net/http. - response.stub(:body).and_return(Chef::JSONCompat.to_json(:error => "saddest trombone")) - @knife.stub(:run).and_raise(Net::HTTPFatalError.new("503 Service Unavailable", response)) - @knife.run_with_pretty_exceptions - @stderr.string.should match(%r[ERROR: Service temporarily unavailable]) - @stderr.string.should match(%r[Response: saddest trombone]) - end - - it "formats other HTTP errors nicely" do - response = Net::HTTPPaymentRequired.new("1.1", "402", "Payment Required") - response.instance_variable_set(:@read, true) # I hate you, net/http. - response.stub(:body).and_return(Chef::JSONCompat.to_json(:error => "nobugfixtillyoubuy")) - @knife.stub(:run).and_raise(Net::HTTPServerException.new("402 Payment Required", response)) - @knife.run_with_pretty_exceptions - @stderr.string.should match(%r[ERROR: Payment Required]) - @stderr.string.should match(%r[Response: nobugfixtillyoubuy]) - end - - it "formats NameError and NoMethodError nicely" do - @knife.stub(:run).and_raise(NameError.new("Undefined constant FUUU")) - @knife.run_with_pretty_exceptions - @stderr.string.should match(%r[ERROR: knife encountered an unexpected error]) - @stderr.string.should match(%r[This may be a bug in the 'knife' knife command or plugin]) - @stderr.string.should match(%r[Exception: NameError: Undefined constant FUUU]) - end - - it "formats missing private key errors nicely" do - @knife.stub(:run).and_raise(Chef::Exceptions::PrivateKeyMissing.new('key not there')) - @knife.stub(:api_key).and_return("/home/root/.chef/no-key-here.pem") - @knife.run_with_pretty_exceptions - @stderr.string.should match(%r[ERROR: Your private key could not be loaded from /home/root/.chef/no-key-here.pem]) - @stderr.string.should match(%r[Check your configuration file and ensure that your private key is readable]) - end - - it "formats connection refused errors nicely" do - @knife.stub(: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. - @stderr.string.should match(%r[ERROR: Network Error: .* - y u no shut up]) - @stderr.string.should match(%r[Check your knife configuration and network settings]) - end - end - -end diff --git a/spec/unit/log_spec.rb b/spec/unit/log_spec.rb deleted file mode 100644 index 7be40f77e6..0000000000 --- a/spec/unit/log_spec.rb +++ /dev/null @@ -1,24 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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 '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 deleted file mode 100644 index 960aff3c36..0000000000 --- a/spec/unit/lwrp_spec.rb +++ /dev/null @@ -1,398 +0,0 @@ -# -# Author:: Christopher Walters (<cw@opscode.com>) -# Copyright:: Copyright (c) 2009 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' - -module LwrpConstScopingConflict -end - -describe "LWRP" do - before do - @original_VERBOSE = $VERBOSE - $VERBOSE = nil - end - - after do - $VERBOSE = @original_VERBOSE - end - - describe "when overriding an existing class" do - before :each do - $stderr.stub(:write) - end - - it "should log if attempting to load resource of same name" do - Dir[File.expand_path( "lwrp/resources/*", CHEF_SPEC_DATA)].each do |file| - Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil) - end - - Dir[File.expand_path( "lwrp/resources/*", CHEF_SPEC_DATA)].each do |file| - Chef::Log.should_receive(:info).with(/overriding/) - Chef::Resource::LWRPBase.build_from_file("lwrp", file, nil) - end - end - - it "should log if attempting to load provider of same name" do - Dir[File.expand_path( "lwrp/providers/*", CHEF_SPEC_DATA)].each do |file| - Chef::Provider::LWRPBase.build_from_file("lwrp", file, nil) - end - - Dir[File.expand_path( "lwrp/providers/*", CHEF_SPEC_DATA)].each do |file| - Chef::Log.should_receive(:info).with(/overriding/) - Chef::Provider::LWRPBase.build_from_file("lwrp", file, nil) - end - end - - it "removes the old LRWP resource class from the list of resource subclasses [CHEF-3432]" do - # CHEF-3432 regression test: - # Chef::Resource keeps a list of all subclasses to assist class inflation - # for json parsing (see Chef::JSONCompat). When replacing LWRP resources, - # we need to ensure the old resource class is remove from that list. - 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 - Chef::Resource.resource_classes.should 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) - end - Chef::Resource.resource_classes.should_not include(first_lwr_foo_class) - end - - it "does not attempt to remove classes from higher up namespaces [CHEF-4117]" do - conflicting_lwrp_file = File.expand_path( "lwrp_const_scoping/resources/conflict.rb", CHEF_SPEC_DATA) - # The test is that this should not raise an error: - Chef::Resource::LWRPBase.build_from_file("lwrp_const_scoping", conflicting_lwrp_file, nil) - 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 - - Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp_override", "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 - Chef::Resource.const_get("LwrpFoo").should be_kind_of(Class) - end - - it "should set resource_name" do - Chef::Resource::LwrpFoo.new("blah").resource_name.should eql(:lwrp_foo) - end - - it "should add the specified actions to the allowed_actions array" do - Chef::Resource::LwrpFoo.new("blah").allowed_actions.should include(:pass_buck, :twiddle_thumbs) - end - - it "should set the specified action as the default action" do - Chef::Resource::LwrpFoo.new("blah").action.should == :pass_buck - end - - it "should create a method for each attribute" do - Chef::Resource::LwrpFoo.new("blah").methods.map{ |m| m.to_sym}.should include(:monkey) - end - - it "should build attribute methods that respect validation rules" do - lambda { Chef::Resource::LwrpFoo.new("blah").monkey(42) }.should raise_error(ArgumentError) - end - - it "should have access to the run context and node during class definition" do - node = Chef::Node.new - node.normal[:penguin_name] = "jackass" - run_context = Chef::RunContext.new(node, Chef::CookbookCollection.new, @events) - - Dir[File.expand_path(File.join(File.dirname(__FILE__), "..", "data", "lwrp", "resources_with_default_attributes", "*"))].each do |file| - Chef::Resource::LWRPBase.build_from_file("lwrp", file, run_context) - end - - cls = Chef::Resource.const_get("LwrpNodeattr") - cls.node.should be_kind_of(Chef::Node) - cls.run_context.should be_kind_of(Chef::RunContext) - cls.node[:penguin_name].should eql("jackass") - end - - context "resource_name" do - let(:klass) { Class.new(Chef::Resource::LWRPBase) } - - it "returns nil when the resource_name is not set" do - expect(klass.resource_name).to be_nil - end - - it "allows to user to user the resource_name" do - expect { - klass.resource_name(:foo) - }.to_not raise_error - end - - it "returns the set value for the resource" do - klass.resource_name(:foo) - 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}!"} - end - end - - let(:instance) { klass.new('kitchen') } - - it "evaluates the default value when requested" do - 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!!') - end - end - end - - describe "when #default_action is an array" do - let(:lwrp) do - Class.new(Chef::Resource::LWRPBase) do - actions :eat, :sleep - default_action [:eat, :sleep] - end - end - - it "returns the array of default actions" do - expect(lwrp.default_action).to eq([:eat, :sleep]) - end - end - - describe "when inheriting from LWRPBase" do - let(:parent) do - Class.new(Chef::Resource::LWRPBase) do - actions :eat, :sleep - default_action :eat - end - end - - context "when the child does not defined the methods" do - let(:child) do - Class.new(parent) - end - - it "delegates #actions to the parent" do - expect(child.actions).to eq([:eat, :sleep]) - end - - it "delegates #default_action to the parent" do - expect(child.default_action).to eq(:eat) - end - end - - context "when the child does define the methods" do - let(:child) do - Class.new(parent) do - actions :dont_eat, :dont_sleep - default_action :dont_eat - end - end - - it "does not delegate #actions to the parent" do - expect(child.actions).to eq([:dont_eat, :dont_sleep]) - end - - it "does not delegate #default_action to the parent" do - expect(child.default_action).to eq(:dont_eat) - end - 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) - 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 - - 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 - - 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) - end - - end - - it "should properly handle a new_resource reference" do - resource = Chef::Resource::LwrpFoo.new("morpheus") - resource.monkey("bob") - resource.provider(:lwrp_monkey_name_printer) - resource.run_context = @run_context - - 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 - Chef::Provider.const_get("LwrpBuckPasser").should be_kind_of(Class) - end - - it "should create a method for each attribute" do - new_resource = double("new resource").as_null_object - Chef::Provider::LwrpBuckPasser.new(nil, new_resource).methods.map{|m|m.to_sym}.should include(:action_pass_buck) - Chef::Provider::LwrpThumbTwiddler.new(nil, new_resource).methods.map{|m|m.to_sym}.should include(:action_twiddle_thumbs) - 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.action(:pass_buck) - injector.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) - - Chef::Runner.new(@run_context).converge - - @run_context.resource_collection[0].should eql(injector) - @run_context.resource_collection[1].name.should eql(:prepared_thumbs) - @run_context.resource_collection[2].name.should eql(:twiddled_thumbs) - @run_context.resource_collection[3].should 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.action(:pass_buck) - injector.provider(:lwrp_buck_passer) - - injector2 = Chef::Resource::LwrpBar.new("tank", @run_context) - injector2.action(:pass_buck) - injector2.provider(:lwrp_buck_passer_2) - - 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) - - Chef::Runner.new(@run_context).converge - - @run_context.resource_collection[0].should eql(injector) - @run_context.resource_collection[1].name.should eql(:prepared_thumbs) - @run_context.resource_collection[2].name.should eql(:twiddled_thumbs) - @run_context.resource_collection[3].should eql(dummy) - @run_context.resource_collection[4].should eql(injector2) - @run_context.resource_collection[5].name.should eql(:prepared_eyes) - @run_context.resource_collection[6].name.should eql(:dried_paint_watched) - end - - it "should properly handle a new_resource reference" do - resource = Chef::Resource::LwrpFoo.new("morpheus", @run_context) - resource.monkey("bob") - resource.provider(:lwrp_monkey_name_printer) - - provider = Chef::Platform.provider_for_resource(resource, :twiddle_thumbs) - provider.action_twiddle_thumbs - - provider.monkey_name.should == "my monkey's name is 'bob'" - end - - it "should properly handle an embedded Resource accessing the enclosing Provider's scope" do - resource = Chef::Resource::LwrpFoo.new("morpheus", @run_context) - resource.monkey("bob") - resource.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 - - provider.enclosed_resource.monkey.should == 'bob, the monkey' - end - - describe "when using inline compilation" do - before do - # Behavior in these examples depends on implementation of fixture provider. - # See spec/data/lwrp/providers/inline_compiler - - # 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.allowed_actions << :test - @resource.action(:test) - @resource.provider(:lwrp_inline_compiler) - end - - it "does not add interior resources to the exterior resource collection" do - @resource.run_action(:test) - @run_context.resource_collection.should be_empty - end - - context "when interior resources are updated" do - it "processes notifications within the LWRP provider's action" do - @resource.run_action(:test) - $interior_ruby_block_2.should == "executed" - end - - it "marks the parent resource updated" do - @resource.run_action(:test) - @resource.should be_updated - @resource.should be_updated_by_last_action - end - end - - context "when interior resources are not updated" do - it "does not mark the parent resource updated" do - @resource.run_action(:no_updates) - @resource.should_not be_updated - @resource.should_not be_updated_by_last_action - end - end - - end - - end - -end diff --git a/spec/unit/mash_spec.rb b/spec/unit/mash_spec.rb deleted file mode 100644 index 7358781e60..0000000000 --- a/spec/unit/mash_spec.rb +++ /dev/null @@ -1,51 +0,0 @@ -# -# Author:: Matthew Kent (<mkent@magoazul.com>) -# Copyright:: Copyright (c) 2011 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/mash' - -describe Mash do - it "should duplicate a simple key/value mash to a new mash" do - data = {:x=>"one", :y=>"two", :z=>"three"} - @orig = Mash.new(data) - @copy = @orig.dup - @copy.to_hash.should == Mash.new(data).to_hash - @copy[:x] = "four" - @orig[:x].should == "one" - end - - it "should duplicate a mash with an array to a new mash" do - data = {:x=>"one", :y=>"two", :z=>[1,2,3]} - @orig = Mash.new(data) - @copy = @orig.dup - @copy.to_hash.should == Mash.new(data).to_hash - @copy[:z] << 4 - @orig[:z].should == [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]})} - @orig = Mash.new(data) - @copy = @orig.dup - @copy.to_hash.should == Mash.new(data).to_hash - @copy[:z][:a] << 4 - @orig[:z][:a].should == [1,2,3] - end - - # add more! -end diff --git a/spec/unit/mixin/checksum_spec.rb b/spec/unit/mixin/checksum_spec.rb deleted file mode 100644 index 54689c9992..0000000000 --- a/spec/unit/mixin/checksum_spec.rb +++ /dev/null @@ -1,41 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Copyright:: Copyright (c) 2009 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/mixin/checksum' -require 'stringio' - -class Chef::CMCCheck - include Chef::Mixin::Checksum -end - -describe Chef::Mixin::Checksum do - before(:each) do - @checksum_user = Chef::CMCCheck.new - @cache = Chef::Digester.instance - @file = CHEF_SPEC_DATA + "/checksum/random.txt" - @stat = double("File::Stat", { :mtime => Time.at(0) }) - File.stub(:stat).and_return(@stat) - end - - it "gets the checksum of a file" do - @checksum_user.checksum(@file).should == "09ee9c8cc70501763563bcf9c218d71b2fbf4186bf8e1e0da07f0f42c80a3394" - end - -end - diff --git a/spec/unit/mixin/command_spec.rb b/spec/unit/mixin/command_spec.rb deleted file mode 100644 index 96660be436..0000000000 --- a/spec/unit/mixin/command_spec.rb +++ /dev/null @@ -1,105 +0,0 @@ -# -# Author:: Hongli Lai (hongli@phusion.nl) -# Copyright:: Copyright (c) 2009 Phusion -# 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::Command, :volatile do - - if windows? - - pending("TODO MOVE: this is a platform specific integration test.") - - else - - describe "popen4" do - include Chef::Mixin::Command - - it "should be possible to read the child process's stdout and stderr" do - popen4("sh -c 'echo hello && echo world >&2'") do |pid, stdin, stdout, stderr| - stdout.read.should == "hello\n" - stderr.read.should == "world\n" - end - end - - it "should default all commands to be run in the POSIX standard C locale" do - popen4("echo $LC_ALL") do |pid, stdin, stdout, stderr| - stdout.read.strip.should == "C" - end - end - - it "should respect locale when specified explicitly" do - popen4("echo $LC_ALL", :environment => {"LC_ALL" => "es"}) do |pid, stdin, stdout, stderr| - stdout.read.strip.should == "es" - end - end - - it "should end when the child process reads from STDIN and a block is given" do - lambda {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 - end - }.should_not raise_error - end - - describe "when a process detaches but doesn't close STDOUT and STDERR [CHEF-584]" do - - it "returns immediately after the first child process exits" do - lambda {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| - end - end}.should_not raise_error - end - - end - - end - - describe "run_command" do - include Chef::Mixin::Command - - it "logs the command's stderr and stdout output if the command failed" do - Chef::Log.stub(:level).and_return(:debug) - begin - run_command(:command => "sh -c 'echo hello; echo world >&2; false'") - violated "Exception expected, but nothing raised." - rescue => e - e.message.should =~ /STDOUT: hello/ - e.message.should =~ /STDERR: world/ - end - end - - describe "when a process detaches but doesn't close STDOUT and STDERR [CHEF-584]" do - it "returns successfully" do - # CHEF-2916 might have added a slight delay here, or our CI - # infrastructure is burdened. Bumping timeout from 2 => 4 -- - # btm - # Serdar - During Solaris tests, we've seen that processes - # are taking a long time to exit. Bumping timeout now to 10. - lambda {Timeout.timeout(10) do - evil_forker="exit if fork; 10.times { sleep 1}" - run_command(:command => "ruby -e '#{evil_forker}'") - end}.should_not raise_error - end - - end - end - end -end diff --git a/spec/unit/mixin/convert_to_class_name_spec.rb b/spec/unit/mixin/convert_to_class_name_spec.rb deleted file mode 100644 index 0276a55fd7..0000000000 --- a/spec/unit/mixin/convert_to_class_name_spec.rb +++ /dev/null @@ -1,54 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@kallistec.com>) -# Copyright:: Copyright (c) 2009 Daniel DeLeo -# 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 ConvertToClassTestHarness - include Chef::Mixin::ConvertToClassName -end - -describe Chef::Mixin::ConvertToClassName do - - before do - @convert = ConvertToClassTestHarness.new - end - - it "converts a_snake_case_word to a CamelCaseWord" do - @convert.convert_to_class_name("now_camelized").should == "NowCamelized" - end - - it "converts a CamelCaseWord to a snake_case_word" do - @convert.convert_to_snake_case("NowImASnake").should == "now_im_a_snake" - end - - it "removes the base classes before snake casing" do - @convert.convert_to_snake_case("NameSpaced::Class::ThisIsWin", "NameSpaced::Class").should == "this_is_win" - end - - it "removes the base classes without explicitly naming them and returns snake case" do - @convert.snake_case_basename("NameSpaced::Class::ExtraWin").should == "extra_win" - end - - it "interprets non-alphanumeric characters in snake case as word boundaries" do - @convert.convert_to_class_name("now_camelized_without-hyphen").should == "NowCamelizedWithoutHyphen" - end - - it "interprets underscore" do - @convert.convert_to_class_name("_remove_leading_underscore").should == "RemoveLeadingUnderscore" - end -end diff --git a/spec/unit/mixin/deep_merge_spec.rb b/spec/unit/mixin/deep_merge_spec.rb deleted file mode 100644 index dbc49e68f2..0000000000 --- a/spec/unit/mixin/deep_merge_spec.rb +++ /dev/null @@ -1,382 +0,0 @@ -# -# Author:: Matthew Kent (<mkent@magoazul.com>) -# Author:: Steve Midgley (http://www.misuse.org/science) -# Copyright:: Copyright (c) 2010 Matthew Kent -# Copyright:: Copyright (c) 2008 Steve Midgley -# 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. - -# Notice: -# This code is imported from deep_merge by Steve Midgley. deep_merge is -# available under the MIT license from -# http://trac.misuse.org/science/wiki/DeepMerge - -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' - 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_dst = {} - @dm.deep_merge!(hash_src.dup, hash_dst) - hash_dst.should == hash_src - end - - it "tests merging an hash w/array into blank hash" do - hash_src = {'region' => {'id' => ['227', '2']}} - hash_dst = {} - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == hash_src - end - - it "tests merge from empty hash" do - hash_src = {} - hash_dst = {"property" => ["2","4"]} - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == {"property" => ["2","4"]} - end - - it "tests merge to empty hash" do - hash_src = {"property" => ["2","4"]} - hash_dst = {} - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == {"property" => ["2","4"]} - end - - it "tests simple string overwrite" do - hash_src = {"name" => "value"} - hash_dst = {"name" => "value1"} - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == {"name" => "value"} - end - - it "tests simple string overwrite of empty hash" do - hash_src = {"name" => "value"} - hash_dst = {} - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == hash_src - end - - it "tests hashes holding array" do - hash_src = {"property" => ["1","3"]} - hash_dst = {"property" => ["2","4"]} - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == {"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"]}} - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == {"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"]}} - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == {"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"]}} - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == {"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"]}} - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == {"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"]}} - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == {"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"]}} - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == {"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"]}} - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == {"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"]}} - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == {"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"]}} - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == {"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"]}} - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == {"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"]}} - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == {"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"]}} - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == {"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_dst = {} - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == {"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"]} - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == {["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_dst = {} - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == {'property' => {'bedroom_count' => ["1","2,3"]}} - end - - it "tests merging into a blank hash" do - hash_src = {"action"=>"browse", "controller"=>"results"} - hash_dst = {} - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == hash_src - end - - it "tests are unmerged hashes passed unmodified w/out :unpack_arrays?" do - hash_src = {"amenity"=>{"id"=>["26,27"]}} - hash_dst = {} - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == {"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"}]} - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == {"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} - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == {"valid" => false} - end - - it "should overwrite false with true when merging boolean values" do - hash_src = {"valid" => true} - hash_dst = {"valid" => false} - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == {"valid" => true} - end - - it "should overwrite a string with an empty string when merging string values" do - hash_src = {"item" => " "} - hash_dst = {"item" => "orange"} - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == {"item" => " "} - end - - it "should overwrite an empty string with a string when merging string values" do - hash_src = {"item" => "orange"} - hash_dst = {"item" => " "} - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == {"item" => "orange"} - end - - it 'should overwrite hashes with nil' do - hash_src = {"item" => { "1" => "2"}, "other" => true } - hash_dst = {"item" => nil } - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == {"item" => nil, "other" => true } - end - - it 'should overwrite strings with nil' do - hash_src = {"item" => "to_overwrite", "other" => false } - hash_dst = {"item" => nil } - @dm.deep_merge!(hash_src, hash_dst) - hash_dst.should == {"item" => nil, "other" => false } - end -end # deep_merge! - -# Chef specific -describe Chef::Mixin::DeepMerge do - before do - @dm = Chef::Mixin::DeepMerge - end - - describe "merge" do - it "should merge a hash into an empty hash" do - hash_dst = {} - hash_src = {'id' => '2'} - @dm.merge(hash_dst, hash_src).should == hash_src - end - - it "should merge a nested hash into an empty hash" do - hash_dst = {} - hash_src = {'region' => {'id' => ['227', '2']}} - @dm.merge(hash_dst, hash_src).should == hash_src - end - - it "should overwrite as string value when merging hashes" do - hash_dst = {"name" => "value1"} - hash_src = {"name" => "value"} - @dm.merge(hash_dst, hash_src).should == {"name" => "value"} - end - - it "should merge arrays within hashes" do - hash_dst = {"property" => ["2","4"]} - hash_src = {"property" => ["1","3"]} - @dm.merge(hash_dst, hash_src).should == {"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"}}} - @dm.merge(hash_dst, hash_src).should == {"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"]} - ret = @dm.merge(hash_dst, hash_src) - hash_dst.should == {"property" => ["1","2","3"]} - hash_src.should == {"property" => ["4","5","6"]} - ret.should == {"property" => ["1","2","3","4","5","6"]} - end - - it "should not error merging un-dupable objects" do - @dm.deep_merge(nil, 4) - end - - end - - describe "role_merge" do - it "errors out if knockout merge use is detected in an array" do - hash_dst = {"property" => ["2","4"]} - hash_src = {"property" => ["1","!merge:4"]} - lambda {@dm.role_merge(hash_dst, hash_src)}.should raise_error(Chef::Mixin::DeepMerge::InvalidSubtractiveMerge) - end - - it "errors out if knockout merge use is detected in an array (reversed merge order)" do - hash_dst = {"property" => ["1","!merge:4"]} - hash_src = {"property" => ["2","4"]} - lambda {@dm.role_merge(hash_dst, hash_src)}.should raise_error(Chef::Mixin::DeepMerge::InvalidSubtractiveMerge) - end - - it "errors out if knockout merge use is detected in a string" do - hash_dst = {"property" => ["2","4"]} - hash_src = {"property" => "!merge"} - lambda {@dm.role_merge(hash_dst, hash_src)}.should raise_error(Chef::Mixin::DeepMerge::InvalidSubtractiveMerge) - end - - it "errors out if knockout merge use is detected in a string (reversed merge order)" do - hash_dst = {"property" => "!merge"} - hash_src= {"property" => ["2","4"]} - lambda {@dm.role_merge(hash_dst, hash_src)}.should raise_error(Chef::Mixin::DeepMerge::InvalidSubtractiveMerge) - end - end - - 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" } - - merged_result = @dm.hash_only_merge(merge_ee_hash, merge_with_hash) - - merged_result["top_level_b"].should == "top-level-b-merged-onto" - merged_result["top_level_a"]["1_deep_a"].should == "1-a-merge-ee" - merged_result["top_level_a"]["1_deep_b"].should == "1-deep-b-merged-onto" - merged_result["top_level_a"]["1_deep_c"].should == "1-deep-c-merged-onto" - 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" } - - merged_result = @dm.hash_only_merge(merge_ee_hash, merge_with_hash) - - merged_result["top_level_b"].should == "top-level-b-merged-onto" - merged_result["top_level_a"]["1_deep_a"].should == "1-a-merge-ee" - merged_result["top_level_a"]["1_deep_b"].should == %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" } - - merged_result = @dm.hash_only_merge(merge_ee_hash, merge_with_hash) - - merged_result["top_level_a"].should be_a(Hash) - merged_result["top_level_a"]["1_deep_a"].should be_nil - merged_result["top_level_a"]["1_deep_b"].should == %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" }}}} - @dm.hash_only_merge(merge_ee_hash, merge_with_hash) - merge_ee_hash.should == {"top_level_a" => {"1_deep_a" => { "2_deep_a" => { "3_deep_a" => "foo" }}}} - merge_with_hash.should == {"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 } - @dm.hash_only_merge(merge_ee_hash, merge_with_hash) - end - end -end diff --git a/spec/unit/mixin/deprecation_spec.rb b/spec/unit/mixin/deprecation_spec.rb deleted file mode 100644 index 3ebf06e830..0000000000 --- a/spec/unit/mixin/deprecation_spec.rb +++ /dev/null @@ -1,57 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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. -# - -require 'spec_helper' -require 'chef/mixin/deprecation' - -describe Chef::Mixin do - describe "deprecating constants (Class/Module)" do - before do - Chef::Mixin.deprecate_constant(:DeprecatedClass, Chef::Node, "This is a test deprecation") - @log_io = StringIO.new - Chef::Log.init(@log_io) - end - - it "has a list of deprecated constants" do - Chef::Mixin.deprecated_constants.should have_key(:DeprecatedClass) - end - - it "returns the replacement when accessing the deprecated constant" do - Chef::Mixin::DeprecatedClass.should == Chef::Node - end - - it "warns when accessing the deprecated constant" do - Chef::Mixin::DeprecatedClass - @log_io.string.should include("This is a test deprecation") - end - end -end - -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') - end - - it "forward method calls to the target object" do - @deprecated_ivar.length.should == 5 - @deprecated_ivar.to_sym.should == :value - end - -end diff --git a/spec/unit/mixin/enforce_ownership_and_permissions_spec.rb b/spec/unit/mixin/enforce_ownership_and_permissions_spec.rb deleted file mode 100644 index fe72d53de5..0000000000 --- a/spec/unit/mixin/enforce_ownership_and_permissions_spec.rb +++ /dev/null @@ -1,96 +0,0 @@ -# -# Author:: Mark Mzyk (<mmzyk@opscode.com>) -# Copyright:: Copyright (c) 2011 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 'etc' -require 'ostruct' - -describe Chef::Mixin::EnforceOwnershipAndPermissions do - - before(:each) do - @node = Chef::Node.new - @node.name "make_believe" - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - @tmpdir = Dir.mktmpdir - @resource = Chef::Resource::File.new("#{@tmpdir}/madeup.txt") - FileUtils.touch @resource.path - @resource.owner "adam" - @provider = Chef::Provider::File.new(@resource, @run_context) - @provider.current_resource = @resource - end - - after(:each) do - FileUtils.rm_rf(@tmpdir) - end - - it "should call set_all on the file access control object" do - Chef::FileAccessControl.any_instance.should_receive(:set_all) - @provider.enforce_ownership_and_permissions - end - - context "when nothing was updated" do - before do - Chef::FileAccessControl.any_instance.stub(:uid_from_resource).and_return(0) - Chef::FileAccessControl.any_instance.stub(:requires_changes?).and_return(false) - Chef::FileAccessControl.any_instance.stub(:define_resource_requirements) - - 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) - Etc.stub(:getpwuid).and_return(passwd_struct) - Etc.stub(:getgrgid).and_return(group_struct) - end - - it "does not set updated_by_last_action on the new resource" do - @provider.new_resource.should_not_receive(:updated_by_last_action) - - Chef::FileAccessControl.any_instance.stub(:set_all) - @provider.run_action(:create) - end - - end - - context "when something was modified" do - before do - Chef::FileAccessControl.any_instance.stub(:requires_changes?).and_return(true) - Chef::FileAccessControl.any_instance.stub(:uid_from_resource).and_return(0) - - 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) - Etc.stub(:getpwuid).and_return(passwd_struct) - Etc.stub(:getgrgid).and_return(group_struct) - end - - it "sets updated_by_last_action on the new resource" do - @provider.new_resource.owner(0) # CHEF-3557 hack - Set these because we don't for windows - @provider.new_resource.group(0) # CHEF-3557 hack - Set these because we don't for windows - @provider.new_resource.should_receive(:updated_by_last_action) - Chef::FileAccessControl.any_instance.stub(:set_all) - @provider.run_action(:create) - end - end - -end diff --git a/spec/unit/mixin/homebrew_user_spec.rb b/spec/unit/mixin/homebrew_user_spec.rb deleted file mode 100644 index 4e30455765..0000000000 --- a/spec/unit/mixin/homebrew_user_spec.rb +++ /dev/null @@ -1,100 +0,0 @@ -# -# Author:: Joshua Timberman (<joshua@getchef.com>) -# -# Copyright 2014, Chef Software, Inc <legal@getchef.com> -# -# 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/homebrew_user' - -class ExampleHomebrewUser - include Chef::Mixin::HomebrewUser -end - -describe Chef::Mixin::HomebrewUser do - before(:each) do - node.default['homebrew']['owner'] = nil - end - - let(:homebrew_user) { ExampleHomebrewUser.new } - let(:node) { Chef::Node.new } - - 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 - 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 - expect(File).to receive(:exist?).exactly(0).times - Etc.stub_chain(:getpwnam, :uid).and_return(uid) - expect(homebrew_user.find_homebrew_uid(user)).to eq(uid) - end - - end - - shared_examples "successfully find executable" do - let(:user) { nil } - let(:brew_owner) { 2001 } - let(:default_brew_path) { '/usr/local/bin/brew' } - let(:stat_double) { - d = double() - expect(d).to receive(:uid).and_return(brew_owner) - d - } - - context "debug statement prints owner name" do - - before 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 - 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 - expect(File).to receive(:exist?).with(default_brew_path).and_return(false) - homebrew_user.stub_chain(:shell_out, :stdout, :strip).and_return("/foo") - expect(File).to receive(:stat).with("/foo").and_return(stat_double) - expect(homebrew_user.find_homebrew_uid(user)).to eq(brew_owner) - end - - end - end - - describe 'when the homebrew user is not provided' do - - it 'raises an error if no executable is found' do - expect(File).to receive(:exist?).with(default_brew_path).and_return(false) - homebrew_user.stub_chain(:shell_out, :stdout, :strip).and_return("") - expect { homebrew_user.find_homebrew_uid(user) }.to raise_error(Chef::Exceptions::CannotDetermineHomebrewOwner) - end - - include_examples "successfully find executable" - - context "the executable is owned by root" do - include_examples "successfully find executable" do - let(:brew_owner) { 0 } - end - end - - end - -end diff --git a/spec/unit/mixin/params_validate_spec.rb b/spec/unit/mixin/params_validate_spec.rb deleted file mode 100644 index cc2fe198ca..0000000000 --- a/spec/unit/mixin/params_validate_spec.rb +++ /dev/null @@ -1,407 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -class TinyClass - include Chef::Mixin::ParamsValidate - - def music(is_good=true) - is_good - end -end - -describe Chef::Mixin::ParamsValidate do - before(:each) do - @vo = TinyClass.new() - end - - it "should allow a hash and a hash as arguments to validate" do - lambda { @vo.validate({:one => "two"}, {}) }.should_not raise_error - end - - it "should raise an argument error if validate is called incorrectly" do - lambda { @vo.validate("one", "two") }.should raise_error(ArgumentError) - end - - it "should require validation map keys to be symbols or strings" do - lambda { @vo.validate({:one => "two"}, { :one => true }) }.should_not raise_error - lambda { @vo.validate({:one => "two"}, { "one" => true }) }.should_not raise_error - lambda { @vo.validate({:one => "two"}, { Hash.new => true }) }.should raise_error(ArgumentError) - end - - it "should allow options to be required with true" do - lambda { @vo.validate({:one => "two"}, { :one => true }) }.should_not raise_error - end - - it "should allow options to be optional with false" do - lambda { @vo.validate({}, {:one => false})}.should_not raise_error - end - - it "should allow you to check what kind_of? thing an argument is with kind_of" do - lambda { - @vo.validate( - {:one => "string"}, - { - :one => { - :kind_of => String - } - } - ) - }.should_not raise_error - - lambda { - @vo.validate( - {:one => "string"}, - { - :one => { - :kind_of => Array - } - } - ) - }.should raise_error(ArgumentError) - end - - it "should allow you to specify an argument is required with required" do - lambda { - @vo.validate( - {:one => "string"}, - { - :one => { - :required => true - } - } - ) - }.should_not raise_error - - lambda { - @vo.validate( - {:two => "string"}, - { - :one => { - :required => true - } - } - ) - }.should raise_error(ArgumentError) - - lambda { - @vo.validate( - {:two => "string"}, - { - :one => { - :required => false - } - } - ) - }.should_not raise_error - end - - it "should allow you to specify whether an object has a method with respond_to" do - lambda { - @vo.validate( - {:one => @vo}, - { - :one => { - :respond_to => "validate" - } - } - ) - }.should_not raise_error - - lambda { - @vo.validate( - {:one => @vo}, - { - :one => { - :respond_to => "monkey" - } - } - ) - }.should raise_error(ArgumentError) - end - - it "should allow you to specify whether an object has all the given methods with respond_to and an array" do - lambda { - @vo.validate( - {:one => @vo}, - { - :one => { - :respond_to => ["validate", "music"] - } - } - ) - }.should_not raise_error - - lambda { - @vo.validate( - {:one => @vo}, - { - :one => { - :respond_to => ["monkey", "validate"] - } - } - ) - }.should raise_error(ArgumentError) - end - - it "should let you set a default value with default => value" do - arguments = Hash.new - @vo.validate(arguments, { - :one => { - :default => "is the loneliest number" - } - }) - arguments[:one].should == "is the loneliest number" - end - - it "should let you check regular expressions" do - lambda { - @vo.validate( - { :one => "is good" }, - { - :one => { - :regex => /^is good$/ - } - } - ) - }.should_not raise_error - - lambda { - @vo.validate( - { :one => "is good" }, - { - :one => { - :regex => /^is bad$/ - } - } - ) - }.should raise_error(ArgumentError) - end - - it "should let you specify your own callbacks" do - lambda { - @vo.validate( - { :one => "is good" }, - { - :one => { - :callbacks => { - "should be equal to is good" => lambda { |a| - a == "is good" - }, - } - } - } - ) - }.should_not raise_error - - lambda { - @vo.validate( - { :one => "is bad" }, - { - :one => { - :callbacks => { - "should be equal to 'is good'" => lambda { |a| - a == "is good" - }, - } - } - } - ) - }.should raise_error(ArgumentError) - end - - it "should let you combine checks" do - args = { :one => "is good", :two => "is bad" } - lambda { - @vo.validate( - args, - { - :one => { - :kind_of => String, - :respond_to => [ :to_s, :upcase ], - :regex => /^is good/, - :callbacks => { - "should be your friend" => lambda { |a| - a == "is good" - } - }, - :required => true - }, - :two => { - :kind_of => String, - :required => false - }, - :three => { :default => "neato mosquito" } - } - ) - }.should_not raise_error - args[:three].should == "neato mosquito" - lambda { - @vo.validate( - args, - { - :one => { - :kind_of => String, - :respond_to => [ :to_s, :upcase ], - :regex => /^is good/, - :callbacks => { - "should be your friend" => lambda { |a| - a == "is good" - } - }, - :required => true - }, - :two => { - :kind_of => Hash, - :required => false - }, - :three => { :default => "neato mosquito" } - } - ) - }.should raise_error(ArgumentError) - end - - it "should raise an ArgumentError if the validation map has an unknown check" do - lambda { @vo.validate( - { :one => "two" }, - { - :one => { - :busted => "check" - } - } - ) - }.should raise_error(ArgumentError) - end - - it "should accept keys that are strings in the options" do - lambda { - @vo.validate({ "one" => "two" }, { :one => { :regex => /^two$/ }}) - }.should_not raise_error - end - - it "should allow an array to kind_of" do - lambda { - @vo.validate( - {:one => "string"}, - { - :one => { - :kind_of => [ String, Array ] - } - } - ) - }.should_not raise_error - lambda { - @vo.validate( - {:one => ["string"]}, - { - :one => { - :kind_of => [ String, Array ] - } - } - ) - }.should_not raise_error - lambda { - @vo.validate( - {:one => Hash.new}, - { - :one => { - :kind_of => [ String, Array ] - } - } - ) - }.should raise_error(ArgumentError) - end - - it "asserts that a value returns false from a predicate method" do - lambda do - @vo.validate({:not_blank => "should pass"}, - {:not_blank => {:cannot_be => :nil, :cannot_be => :empty}}) - end.should_not raise_error - lambda do - @vo.validate({:not_blank => ""}, - {:not_blank => {:cannot_be => :nil, :cannot_be => :empty}}) - end.should raise_error(Chef::Exceptions::ValidationFailed) - end - - it "should set and return a value, then return the same value" do - value = "meow" - @vo.set_or_return(:test, value, {}).object_id.should == value.object_id - @vo.set_or_return(:test, nil, {}).object_id.should == value.object_id - end - - it "should set and return a default value when the argument is nil, then return the same value" do - value = "meow" - @vo.set_or_return(:test, nil, { :default => value }).object_id.should == value.object_id - @vo.set_or_return(:test, nil, {}).object_id.should == value.object_id - end - - it "should raise an ArgumentError when argument is nil and required is true" do - lambda { - @vo.set_or_return(:test, nil, { :required => true }) - }.should raise_error(ArgumentError) - end - - it "should not raise an error when argument is nil and required is false" do - lambda { - @vo.set_or_return(:test, nil, { :required => false }) - }.should_not raise_error - end - - it "should set and return @name, then return @name for foo when argument is nil" do - value = "meow" - @vo.set_or_return(:name, value, { }).object_id.should == value.object_id - @vo.set_or_return(:foo, nil, { :name_attribute => true }).object_id.should == 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}) - 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}) - lambda do - @vo.set_or_return(:test, nil, {:kind_of => Numeric}) - end.should 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.instance_variable_get(:@delayed).should 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 }, {}) - @vo.set_or_return(:test, nil, {}).should == 'fubar' - value = 'foobar' - @vo.set_or_return(:test, nil, {}).should == 'foobar' - value = 'fauxbar' - @vo.set_or_return(:test, nil, {}).should == 'fauxbar' - end - - it "should not evaluate non DelayedEvaluator instances" do - value = lambda{ 'test' } - @vo.set_or_return(:test, value, {}) - @vo.set_or_return(:test, nil, {}).object_id.should == value.object_id - @vo.set_or_return(:test, nil, {}).should be_a(Proc) - end - -end diff --git a/spec/unit/mixin/path_sanity_spec.rb b/spec/unit/mixin/path_sanity_spec.rb deleted file mode 100644 index 64c667b483..0000000000 --- a/spec/unit/mixin/path_sanity_spec.rb +++ /dev/null @@ -1,86 +0,0 @@ -# -# Author:: Seth Chisamore (<schisamo@opscode.com>) -# Copyright:: Copyright (c) 2011 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' - -class PathSanityTestHarness - include Chef::Mixin::PathSanity -end - -describe Chef::Mixin::PathSanity do - - before do - @sanity = PathSanityTestHarness.new - end - - describe "when enforcing path sanity" do - before do - Chef::Config[:enforce_path_sanity] = true - @ruby_bindir = '/some/ruby/bin' - @gem_bindir = '/some/gem/bin' - Gem.stub(:bindir).and_return(@gem_bindir) - RbConfig::CONFIG.stub(:[]).with('bindir').and_return(@ruby_bindir) - Chef::Platform.stub(:windows?).and_return(false) - end - - it "adds all useful PATHs even if environment is an empty hash" do - env={} - @sanity.enforce_path_sanity(env) - env["PATH"].should == "#{@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" => ""} - @sanity.enforce_path_sanity(env) - env["PATH"].should == "#{@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"} - @sanity.enforce_path_sanity(env) - env["PATH"].should == "/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" => ""} - @sanity.enforce_path_sanity(env) - env["PATH"].should == "#{@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' - Gem.stub(:bindir).and_return(gem_bindir) - RbConfig::CONFIG.stub(:[]).with('bindir').and_return(ruby_bindir) - env = {"PATH" => gem_bindir} - @sanity.enforce_path_sanity(env) - env["PATH"].should == "/yo/gabba/gabba:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" - end - - it "builds a valid windows path" do - ruby_bindir = 'C:\ruby\bin' - gem_bindir = 'C:\gems\bin' - Gem.stub(:bindir).and_return(gem_bindir) - RbConfig::CONFIG.stub(:[]).with('bindir').and_return(ruby_bindir) - Chef::Platform.stub(:windows?).and_return(true) - env = {"PATH" => 'C:\Windows\system32;C:\mr\softie'} - @sanity.enforce_path_sanity(env) - env["PATH"].should == "C:\\Windows\\system32;C:\\mr\\softie;#{ruby_bindir};#{gem_bindir}" - end - end -end diff --git a/spec/unit/mixin/securable_spec.rb b/spec/unit/mixin/securable_spec.rb deleted file mode 100644 index 10954083d8..0000000000 --- a/spec/unit/mixin/securable_spec.rb +++ /dev/null @@ -1,314 +0,0 @@ -# encoding: UTF-8 -# -# Author:: Mark Mzyk (<mmzyk@opscode.com>) -# Copyright:: Copyright (c) 2011 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::Mixin::Securable do - - before(:each) do - @securable = Object.new - @securable.send(:extend, Chef::Mixin::Securable) - @securable.send(:extend, Chef::Mixin::ParamsValidate) - end - - it "should accept a group name or id for group" do - lambda { @securable.group "root" }.should_not raise_error - lambda { @securable.group 123 }.should_not raise_error - lambda { @securable.group "+bad:group" }.should raise_error(ArgumentError) - end - - it "should accept a user name or id for owner" do - lambda { @securable.owner "root" }.should_not raise_error - lambda { @securable.owner 123 }.should_not raise_error - lambda { @securable.owner "+bad:owner" }.should raise_error(ArgumentError) - end - - it "allows the owner to be specified as #user" do - @securable.should respond_to(:user) - end - - describe "unix-specific behavior" do - before(:each) do - platform_mock :unix do - load File.join(File.dirname(__FILE__), "..", "..", "..", "lib", "chef", "mixin", "securable.rb") - @securable = Object.new - @securable.send(:extend, Chef::Mixin::Securable) - @securable.send(:extend, Chef::Mixin::ParamsValidate) - end - end - - it "should accept group/owner names with spaces and backslashes" do - lambda { @securable.group 'test\ group' }.should_not raise_error - lambda { @securable.owner 'test\ group' }.should_not raise_error - end - - it "should accept group/owner names that are a single character or digit" do - lambda { @securable.group 'v' }.should_not raise_error - lambda { @securable.group '1' }.should_not raise_error - lambda { @securable.owner 'v' }.should_not raise_error - lambda { @securable.owner '1' }.should_not raise_error - end - - it "should not accept group/owner names starting with '-', '+', or '~'" do - lambda { @securable.group '-test' }.should raise_error(ArgumentError) - lambda { @securable.group '+test' }.should raise_error(ArgumentError) - lambda { @securable.group '~test' }.should raise_error(ArgumentError) - lambda { @securable.group 'te-st' }.should_not raise_error - lambda { @securable.group 'te+st' }.should_not raise_error - lambda { @securable.group 'te~st' }.should_not raise_error - lambda { @securable.owner '-test' }.should raise_error(ArgumentError) - lambda { @securable.owner '+test' }.should raise_error(ArgumentError) - lambda { @securable.owner '~test' }.should raise_error(ArgumentError) - lambda { @securable.owner 'te-st' }.should_not raise_error - lambda { @securable.owner 'te+st' }.should_not raise_error - lambda { @securable.owner 'te~st' }.should_not raise_error - end - - it "should not accept group/owner names containing ':', ',' or non-space whitespace" do - lambda { @securable.group ':test' }.should raise_error(ArgumentError) - lambda { @securable.group 'te:st' }.should raise_error(ArgumentError) - lambda { @securable.group ',test' }.should raise_error(ArgumentError) - lambda { @securable.group 'te,st' }.should raise_error(ArgumentError) - lambda { @securable.group "\ttest" }.should raise_error(ArgumentError) - lambda { @securable.group "te\tst" }.should raise_error(ArgumentError) - lambda { @securable.group "\rtest" }.should raise_error(ArgumentError) - lambda { @securable.group "te\rst" }.should raise_error(ArgumentError) - lambda { @securable.group "\ftest" }.should raise_error(ArgumentError) - lambda { @securable.group "te\fst" }.should raise_error(ArgumentError) - lambda { @securable.group "\0test" }.should raise_error(ArgumentError) - lambda { @securable.group "te\0st" }.should raise_error(ArgumentError) - lambda { @securable.owner ':test' }.should raise_error(ArgumentError) - lambda { @securable.owner 'te:st' }.should raise_error(ArgumentError) - lambda { @securable.owner ',test' }.should raise_error(ArgumentError) - lambda { @securable.owner 'te,st' }.should raise_error(ArgumentError) - lambda { @securable.owner "\ttest" }.should raise_error(ArgumentError) - lambda { @securable.owner "te\tst" }.should raise_error(ArgumentError) - lambda { @securable.owner "\rtest" }.should raise_error(ArgumentError) - lambda { @securable.owner "te\rst" }.should raise_error(ArgumentError) - lambda { @securable.owner "\ftest" }.should raise_error(ArgumentError) - lambda { @securable.owner "te\fst" }.should raise_error(ArgumentError) - lambda { @securable.owner "\0test" }.should raise_error(ArgumentError) - lambda { @securable.owner "te\0st" }.should raise_error(ArgumentError) - end - - it "should accept Active Directory-style domain names pulled in via LDAP (on unix hosts)" do - lambda { @securable.owner "domain\@user" }.should_not raise_error - lambda { @securable.owner "domain\\user" }.should_not raise_error - lambda { @securable.group "domain\@group" }.should_not raise_error - lambda { @securable.group "domain\\group" }.should_not raise_error - lambda { @securable.group "domain\\group^name" }.should_not raise_error - end - - it "should not accept group/owner names containing embedded carriage returns" do - pending "XXX: params_validate needs to be extended to support multi-line regex" - #lambda { @securable.group "\ntest" }.should raise_error(ArgumentError) - #lambda { @securable.group "te\nst" }.should raise_error(ArgumentError) - #lambda { @securable.owner "\ntest" }.should raise_error(ArgumentError) - #lambda { @securable.owner "te\nst" }.should raise_error(ArgumentError) - end - - it "should accept group/owner names in UTF-8" do - lambda { @securable.group 'tëst' }.should_not raise_error - lambda { @securable.group 'ë' }.should_not raise_error - lambda { @securable.owner 'tëst' }.should_not raise_error - lambda { @securable.owner 'ë' }.should_not raise_error - end - - it "should accept a unix file mode in string form as an octal number" do - lambda { @securable.mode "0" }.should_not raise_error - lambda { @securable.mode "0000" }.should_not raise_error - lambda { @securable.mode "0111" }.should_not raise_error - lambda { @securable.mode "0444" }.should_not raise_error - - lambda { @securable.mode "111" }.should_not raise_error - lambda { @securable.mode "444" }.should_not raise_error - lambda { @securable.mode "7777" }.should_not raise_error - lambda { @securable.mode "07777" }.should_not raise_error - - lambda { @securable.mode "-01" }.should raise_error(ArgumentError) - lambda { @securable.mode "010000" }.should raise_error(ArgumentError) - lambda { @securable.mode "-1" }.should raise_error(ArgumentError) - lambda { @securable.mode "10000" }.should raise_error(ArgumentError) - - lambda { @securable.mode "07778" }.should raise_error(ArgumentError) - lambda { @securable.mode "7778" }.should raise_error(ArgumentError) - lambda { @securable.mode "4095" }.should raise_error(ArgumentError) - - lambda { @securable.mode "0foo1234" }.should raise_error(ArgumentError) - lambda { @securable.mode "foo1234" }.should raise_error(ArgumentError) - end - - it "should accept a unix file mode in numeric form as a ruby-interpreted integer" do - lambda { @securable.mode(0) }.should_not raise_error - lambda { @securable.mode(0000) }.should_not raise_error - lambda { @securable.mode(444) }.should_not raise_error - lambda { @securable.mode(0444) }.should_not raise_error - lambda { @securable.mode(07777) }.should_not raise_error - - lambda { @securable.mode(292) }.should_not raise_error - lambda { @securable.mode(4095) }.should_not raise_error - - lambda { @securable.mode(0111) }.should_not raise_error - lambda { @securable.mode(73) }.should_not raise_error - - lambda { @securable.mode(-01) }.should raise_error(ArgumentError) - lambda { @securable.mode(010000) }.should raise_error(ArgumentError) - lambda { @securable.mode(-1) }.should raise_error(ArgumentError) - lambda { @securable.mode(4096) }.should raise_error(ArgumentError) - end - end - - describe "windows-specific behavior" do - before(:each) do - platform_mock :windows do - load File.join(File.dirname(__FILE__), "..", "..", "..", "lib", "chef", "mixin", "securable.rb") - securable_class = Class.new do - include Chef::Mixin::Securable - include Chef::Mixin::ParamsValidate - end - @securable = securable_class.new - end - end - - it "should not accept a group name or id for group with spaces and multiple backslashes" do - lambda { @securable.group 'test\ \group' }.should raise_error(ArgumentError) - end - - it "should accept a unix file mode in string form as an octal number" do - lambda { @securable.mode "0" }.should_not raise_error - lambda { @securable.mode "0000" }.should_not raise_error - lambda { @securable.mode "0111" }.should_not raise_error - lambda { @securable.mode "0444" }.should_not raise_error - - lambda { @securable.mode "111" }.should_not raise_error - lambda { @securable.mode "444" }.should_not raise_error - lambda { @securable.mode "7777" }.should raise_error(ArgumentError) - lambda { @securable.mode "07777" }.should raise_error(ArgumentError) - - lambda { @securable.mode "-01" }.should raise_error(ArgumentError) - lambda { @securable.mode "010000" }.should raise_error(ArgumentError) - lambda { @securable.mode "-1" }.should raise_error(ArgumentError) - lambda { @securable.mode "10000" }.should raise_error(ArgumentError) - - lambda { @securable.mode "07778" }.should raise_error(ArgumentError) - lambda { @securable.mode "7778" }.should raise_error(ArgumentError) - lambda { @securable.mode "4095" }.should raise_error(ArgumentError) - - lambda { @securable.mode "0foo1234" }.should raise_error(ArgumentError) - lambda { @securable.mode "foo1234" }.should raise_error(ArgumentError) - end - - it "should accept a unix file mode in numeric form as a ruby-interpreted integer" do - lambda { @securable.mode 0 }.should_not raise_error - lambda { @securable.mode 0000 }.should_not raise_error - lambda { @securable.mode 444 }.should_not raise_error - lambda { @securable.mode 0444 }.should_not raise_error - lambda { @securable.mode 07777 }.should raise_error(ArgumentError) - - lambda { @securable.mode 292 }.should_not raise_error - lambda { @securable.mode 4095 }.should raise_error(ArgumentError) - - lambda { @securable.mode 0111 }.should_not raise_error - lambda { @securable.mode 73 }.should_not raise_error - - lambda { @securable.mode -01 }.should raise_error(ArgumentError) - lambda { @securable.mode 010000 }.should raise_error(ArgumentError) - lambda { @securable.mode -1 }.should raise_error(ArgumentError) - lambda { @securable.mode 4096 }.should raise_error(ArgumentError) - end - - it "should allow you to specify :full_control, :modify, :read_execute, :read, and :write rights" do - lambda { @securable.rights :full_control, "The Dude" }.should_not raise_error - lambda { @securable.rights :modify, "The Dude" }.should_not raise_error - lambda { @securable.rights :read_execute, "The Dude" }.should_not raise_error - lambda { @securable.rights :read, "The Dude" }.should_not raise_error - lambda { @securable.rights :write, "The Dude" }.should_not raise_error - lambda { @securable.rights :to_party, "The Dude" }.should raise_error(ArgumentError) - end - - it "should allow you to specify :full_control, :modify, :read_execute, :read, and :write deny_rights" do - lambda { @securable.deny_rights :full_control, "The Dude" }.should_not raise_error - lambda { @securable.deny_rights :modify, "The Dude" }.should_not raise_error - lambda { @securable.deny_rights :read_execute, "The Dude" }.should_not raise_error - lambda { @securable.deny_rights :read, "The Dude" }.should_not raise_error - lambda { @securable.deny_rights :write, "The Dude" }.should_not raise_error - lambda { @securable.deny_rights :to_party, "The Dude" }.should raise_error(ArgumentError) - end - - it "should accept a principal as a string or an array" do - lambda { @securable.rights :read, "The Dude" }.should_not raise_error - lambda { @securable.rights :read, ["The Dude","Donny"] }.should_not raise_error - lambda { @securable.rights :read, 3 }.should raise_error(ArgumentError) - end - - it "should allow you to specify whether the permissions applies_to_children with true/false/:containers_only/:objects_only" do - lambda { @securable.rights :read, "The Dude", :applies_to_children => false }.should_not raise_error - lambda { @securable.rights :read, "The Dude", :applies_to_children => true }.should_not raise_error - lambda { @securable.rights :read, "The Dude", :applies_to_children => :containers_only }.should_not raise_error - lambda { @securable.rights :read, "The Dude", :applies_to_children => :objects_only }.should_not raise_error - lambda { @securable.rights :read, "The Dude", :applies_to_children => 'poop' }.should raise_error(ArgumentError) - end - - it "should allow you to specify whether the permissions applies_to_self with true/false" do - lambda { @securable.rights :read, "The Dude", :applies_to_children => true, :applies_to_self => false }.should_not raise_error - lambda { @securable.rights :read, "The Dude", :applies_to_self => true }.should_not raise_error - lambda { @securable.rights :read, "The Dude", :applies_to_self => 'poop' }.should raise_error(ArgumentError) - end - - it "should allow you to specify whether the permissions applies one_level_deep with true/false" do - lambda { @securable.rights :read, "The Dude", :applies_to_children => true, :one_level_deep => false }.should_not raise_error - lambda { @securable.rights :read, "The Dude", :applies_to_children => true, :one_level_deep => true }.should_not raise_error - lambda { @securable.rights :read, "The Dude", :applies_to_children => true, :one_level_deep => 'poop' }.should raise_error(ArgumentError) - end - - it "should allow multiple rights and deny_rights declarations" do - @securable.rights :read, "The Dude" - @securable.deny_rights :full_control, "The Dude" - @securable.rights :full_control, "The Dude" - @securable.rights :write, "The Dude" - @securable.deny_rights :read, "The Dude" - @securable.rights.size.should == 3 - @securable.deny_rights.size.should == 2 - end - - it "should allow you to specify whether the permission applies_to_self only if you specified applies_to_children" do - lambda { @securable.rights :read, "The Dude", :applies_to_children => true, :applies_to_self => true }.should_not raise_error - lambda { @securable.rights :read, "The Dude", :applies_to_children => true, :applies_to_self => false }.should_not raise_error - lambda { @securable.rights :read, "The Dude", :applies_to_children => false, :applies_to_self => true }.should_not raise_error - lambda { @securable.rights :read, "The Dude", :applies_to_children => false, :applies_to_self => false }.should raise_error(ArgumentError) - lambda { @securable.rights :read, "The Dude", :applies_to_self => true }.should_not raise_error - lambda { @securable.rights :read, "The Dude", :applies_to_self => false }.should_not raise_error - end - - it "should allow you to specify whether the permission applies one_level_deep only if you specified applies_to_children" do - lambda { @securable.rights :read, "The Dude", :applies_to_children => true, :one_level_deep => true }.should_not raise_error - lambda { @securable.rights :read, "The Dude", :applies_to_children => true, :one_level_deep => false }.should_not raise_error - lambda { @securable.rights :read, "The Dude", :applies_to_children => false, :one_level_deep => true }.should raise_error(ArgumentError) - lambda { @securable.rights :read, "The Dude", :applies_to_children => false, :one_level_deep => false }.should_not raise_error - lambda { @securable.rights :read, "The Dude", :one_level_deep => true }.should_not raise_error - lambda { @securable.rights :read, "The Dude", :one_level_deep => false }.should_not raise_error - end - - it "should allow you to specify whether the permissions inherit with true/false" do - lambda { @securable.inherits true }.should_not raise_error - lambda { @securable.inherits false }.should_not raise_error - lambda { @securable.inherits "monkey" }.should raise_error(ArgumentError) - end - end -end diff --git a/spec/unit/mixin/shell_out_spec.rb b/spec/unit/mixin/shell_out_spec.rb deleted file mode 100644 index 38a63a32ee..0000000000 --- a/spec/unit/mixin/shell_out_spec.rb +++ /dev/null @@ -1,271 +0,0 @@ -# -# Author:: Ho-Sheng Hsiao (hosh@opscode.com) -# Code derived from spec/unit/mixin/command_spec.rb -# -# Original header: -# Author:: Hongli Lai (hongli@phusion.nl) -# Copyright:: Copyright (c) 2009 Phusion -# 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::ShellOut do - include Chef::Mixin::ShellOut - - describe '#run_command_compatible_options' do - subject { run_command_compatible_options(command_args) } - let(:command_args) { [ cmd, options ] } - let(:cmd) { "echo '#{rand(1000)}'" } - - let(:output) { StringIO.new } - 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 - let(:command_args) { [ cmd ] } - - it 'should not edit command args' do - should eql(command_args) - end - end - - context 'without deprecated options' do - let(:options) { { :environment => environment } } - let(:environment) { { 'LC_ALL' => 'C' } } - - it 'should not edit command args' do - should eql(command_args) - end - end - - def self.should_emit_deprecation_warning_about(old_option, new_option) - it 'should emit a deprecation warning' do - assume_deprecation_log_level and capture_log_output - subject - expect(output.string).to match /DEPRECATION:/ - expect(output.string).to match Regexp.escape(old_option.to_s) - expect(output.string).to match Regexp.escape(new_option.to_s) - end - end - - 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 - should 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 - let(:options) { { :command_log_prepend => command_log_prepend } } - let(:command_log_prepend) { 'PROVIDER:' } - - it 'should convert :command_log_prepend to :log_tag' do - should eql [ cmd, { :log_tag => command_log_prepend } ] - end - - should_emit_deprecation_warning_about :command_log_prepend, :log_tag - end - - 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 - should 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 - let(:options) { { 'command_log_prepend' => command_log_prepend } } - let(:command_log_prepend) { 'PROVIDER:' } - - it "should convert 'command_log_prepend' to :log_tag" do - should eql [ cmd, { :log_tag => command_log_prepend } ] - end - - should_emit_deprecation_warning_about :command_log_prepend, :log_tag - end - end - - context "when testing individual methods" do - before(:each) do - @original_env = ENV.to_hash - ENV.clear - end - - after(:each) do - ENV.clear - ENV.update(@original_env) - end - - let(:shell_out) { Chef::Mixin::ShellOut } - let(:cmd) { "echo '#{rand(1000)}'" } - - describe "#shell_out" 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 } } - expect(shell_out).to receive(:shell_out_command).with(cmd, options).and_return(true) - shell_out.shell_out(cmd, options) - end - - it "should not change environment['LC_ALL'] when set to non-nil" do - options = { :environment => { 'LC_ALL' => 'en_US.UTF-8' } } - expect(shell_out).to receive(:shell_out_command).with(cmd, options).and_return(true) - shell_out.shell_out(cmd, options) - end - - it "should set environment['LC_ALL'] to 'en_US.UTF-8' when 'LC_ALL' not present" do - options = { :environment => { 'HOME' => '/Users/morty' } } - expect(shell_out).to receive(:shell_out_command).with(cmd, { - :environment => { 'HOME' => '/Users/morty', 'LC_ALL' => Chef::Config[:internal_locale] }, - }).and_return(true) - shell_out.shell_out(cmd, options) - end - - it "should not mutate the options hash when it adds LC_ALL" do - options = { :environment => { 'HOME' => '/Users/morty' } } - expect(shell_out).to receive(:shell_out_command).with(cmd, { - :environment => { 'HOME' => '/Users/morty', 'LC_ALL' => Chef::Config[:internal_locale] }, - }).and_return(true) - shell_out.shell_out(cmd, options) - 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 set to nil" do - options = { :env => { 'LC_ALL' => nil } } - expect(shell_out).to receive(:shell_out_command).with(cmd, options).and_return(true) - shell_out.shell_out(cmd, options) - end - - it "should not change env when set to non-nil" do - options = { :env => { 'LC_ALL' => 'de_DE.UTF-8'}} - expect(shell_out).to receive(:shell_out_command).with(cmd, options).and_return(true) - shell_out.shell_out(cmd, options) - end - - it "should set env['LC_ALL'] to 'en_US.UTF-8' when 'LC_ALL' not present" do - options = { :env => { 'HOME' => '/Users/morty' } } - expect(shell_out).to receive(:shell_out_command).with(cmd, { - :env => { 'HOME' => '/Users/morty', 'LC_ALL' => Chef::Config[:internal_locale] }, - }).and_return(true) - shell_out.shell_out(cmd, options) - end - - it "should not mutate the options hash when it adds LC_ALL" do - options = { :env => { 'HOME' => '/Users/morty' } } - expect(shell_out).to receive(:shell_out_command).with(cmd, { - :env => { 'HOME' => '/Users/morty', 'LC_ALL' => Chef::Config[:internal_locale] }, - }).and_return(true) - shell_out.shell_out(cmd, options) - expect(options[:env].has_key?('LC_ALL')).to be false - end - end - - describe "and no env/environment option is present" do - it "should add environment option and set environment['LC_ALL'] to 'en_US.UTF_8'" do - options = { :user => 'morty' } - expect(shell_out).to receive(:shell_out_command).with(cmd, { - :user => 'morty', :environment => { 'LC_ALL' => Chef::Config[:internal_locale] }, - }).and_return(true) - shell_out.shell_out(cmd, options) - end - end - end - - describe "when the last argument is not a Hash" do - it "should add environment options and set environment['LC_ALL'] to 'en_US.UTF-8'" do - expect(shell_out).to receive(:shell_out_command).with(cmd, { - :environment => { 'LC_ALL' => Chef::Config[:internal_locale] }, - }).and_return(true) - shell_out.shell_out(cmd) - end - end - - end - - describe "#shell_out_with_systems_locale" 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 } } - expect(shell_out).to receive(:shell_out_command).with(cmd, options).and_return(true) - shell_out.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' } } - expect(shell_out).to receive(:shell_out_command).with(cmd, options).and_return(true) - shell_out.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' } } - expect(shell_out).to receive(:shell_out_command).with(cmd, options).and_return(true) - shell_out.shell_out_with_systems_locale(cmd, options) - end - end - - describe "and env is an option" do - it "should not change env when set to nil" do - options = { :env => { 'LC_ALL' => nil } } - expect(shell_out).to receive(:shell_out_command).with(cmd, options).and_return(true) - shell_out.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'}} - expect(shell_out).to receive(:shell_out_command).with(cmd, options).and_return(true) - shell_out.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' } } - expect(shell_out).to receive(:shell_out_command).with(cmd, options).and_return(true) - shell_out.shell_out_with_systems_locale(cmd, options) - end - end - - 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' } - expect(shell_out).to receive(:shell_out_command).with(cmd, options).and_return(true) - shell_out.shell_out_with_systems_locale(cmd, options) - end - end - end - - describe "when the last argument is not a Hash" do - it "should no longer add environment options and set environment['LC_ALL'] to nil" do - expect(shell_out).to receive(:shell_out_command).with(cmd).and_return(true) - shell_out.shell_out_with_systems_locale(cmd) - end - end - end - - end -end diff --git a/spec/unit/mixin/template_spec.rb b/spec/unit/mixin/template_spec.rb deleted file mode 100644 index 63fa81782e..0000000000 --- a/spec/unit/mixin/template_spec.rb +++ /dev/null @@ -1,269 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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 'cgi' -describe Chef::Mixin::Template, "render_template" do - - let(:sep) { Chef::Platform.windows? ? "\r\n" : "\n" } - - before :each do - @context = Chef::Mixin::Template::TemplateContext.new({}) - end - - it "should render the template evaluated in the given context" do - @context[:foo] = "bar" - output = @context.render_template_from_string("<%= @foo %>") - output.should == "bar" - end - - template_contents = [ "Fancy\r\nTemplate\r\n\r\n", - "Fancy\nTemplate\n\n", - "Fancy\r\nTemplate\n\r\n"] - - describe "when running on windows" do - before do - Chef::Platform.stub(:windows?).and_return(true) - end - - it "should render the templates with windows line endings" do - template_contents.each do |template_content| - output = @context.render_template_from_string(template_content) - output.each_line do |line| - line.should end_with("\r\n") - end - end - end - end - - describe "when running on unix" do - before do - Chef::Platform.stub(:windows?).and_return(false) - end - - it "should render the templates with unix line endings" do - template_contents.each do |template_content| - output = @context.render_template_from_string(template_content) - output.each_line do |line| - line.should end_with("\n") - end - end - end - end - - it "should provide a node method to access @node" do - @context[:node] = "tehShizzle" - output = @context.render_template_from_string("<%= @node %>") - output.should == "tehShizzle" - end - - describe "with a template resource" 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) - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events) - - @rendered_file_location = Dir.tmpdir + '/openldap_stuff.conf' - - @resource = Chef::Resource::Template.new(@rendered_file_location) - @resource.cookbook_name = 'openldap' - @current_resource = @resource.dup - - @content_provider = Chef::Provider::Template::Content.new(@resource, @current_resource, @run_context) - - @template_context = Chef::Mixin::Template::TemplateContext.new({}) - @template_context[:node] = @node - @template_context[:template_finder] = Chef::Provider::TemplateFinder.new(@run_context, @resource.cookbook_name, @node) - end - - it "should provide a render method" do - output = @template_context.render_template_from_string("before {<%= render('test.erb').strip -%>} after") - output.should == "before {We could be diving for pearls!} after" - end - - it "should render local files" do - begin - tf = Tempfile.new("partial") - tf.write "test" - tf.rewind - - output = @template_context.render_template_from_string("before {<%= render '#{tf.path}', :local => true %>} after") - output.should == "before {test} after" - ensure - tf.close - end - end - - it "should render partials from a different cookbook" do - @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") - output.should == "before {We could be diving for pearls!} after" - end - - it "should render using the source argument if provided" do - begin - tf = Tempfile.new("partial") - tf.write "test" - tf.rewind - - output = @template_context.render_template_from_string("before {<%= render 'something', :local => true, :source => '#{tf.path}' %>} after") - output.should == "before {test} after" - ensure - tf.close - end - end - - it "should pass the node to partials" do - @node.normal[:slappiness] = "happiness" - - output = @template_context.render_template_from_string("before {<%= render 'openldap_stuff.conf.erb' %>} after") - output.should == "before {slappiness is happiness} after" - end - - it "should pass the original variables to partials" do - @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 variables to partials" do - output = @template_context.render_template_from_string("before {<%= render 'openldap_variable_stuff.conf.erb', :variables => {:secret => 'whatever' } %>} after") - output.should == "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' - - output = @template_context.render_template_from_string("before {<%= render 'openldap_variable_stuff.conf.erb', :variables => {:secret => 'two' } %>} after <%= @secret %>") - output.should == "before {super secret is two} after one" - end - - it "should pass nil for missing variables in partials" do - output = @template_context.render_template_from_string("before {<%= render 'openldap_variable_stuff.conf.erb', :variables => {} %>} after") - output.should == "before {super secret is } after" - - output = @template_context.render_template_from_string("before {<%= render 'openldap_variable_stuff.conf.erb' %>} after") - output.should == "before {super secret is } after" - end - - it "should render nested partials" do - path = File.expand_path(File.join(CHEF_SPEC_DATA, "partial_one.erb")) - - output = @template_context.render_template_from_string("before {<%= render('#{path}', :local => true).strip %>} after") - output.should == "before {partial one We could be diving for pearls! calling home} after" - end - - describe "when customizing the template context" do - - it "extends the context to include modules" do - mod = Module.new do - def hello - "ohai" - end - end - @template_context._extend_modules([mod]) - output = @template_context.render_template_from_string("<%=hello%>") - output.should == "ohai" - end - - it "emits a warning when overriding 'core' methods" 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| - Chef::Log.should_receive(:warn).with(/^Core template method `#{method_name}' overridden by extension module/) - end - @template_context._extend_modules([mod]) - end - end - - end - - describe "when an exception is raised in the template" do - def do_raise - @context.render_template_from_string("foo\nbar\nbaz\n<%= this_is_not_defined %>\nquin\nqunx\ndunno") - end - - it "should catch and re-raise the exception as a TemplateError" do - lambda { do_raise }.should raise_error(Chef::Mixin::Template::TemplateError) - end - - it "should raise an error if an attempt is made to access node but it is nil" do - lambda {@context.render_template_from_string("<%= node %>") {|r| r}}.should raise_error(Chef::Mixin::Template::TemplateError) - end - - describe "the raised TemplateError" do - before :each do - begin - do_raise - rescue Chef::Mixin::Template::TemplateError => e - @exception = e - end - end - - it "should have the original exception" do - @exception.original_exception.should be - @exception.original_exception.message.should =~ /undefined local variable or method `this_is_not_defined'/ - end - - it "should determine the line number of the exception" do - @exception.line_number.should == 4 - end - - it "should provide a source listing of the template around the exception" do - @exception.source_listing.should == " 2: bar\n 3: baz\n 4: <%= this_is_not_defined %>\n 5: quin\n 6: qunx" - end - - it "should provide the evaluation context of the template" do - @exception.context.should == @context - end - - it "should defer the message to the original exception" do - @exception.message.should =~ /undefined local variable or method `this_is_not_defined'/ - end - - it "should provide a nice source location" do - @exception.source_location.should == "on line #4" - end - - it "should create a pretty output for the terminal" do - @exception.to_s.should =~ /Chef::Mixin::Template::TemplateError/ - @exception.to_s.should =~ /undefined local variable or method `this_is_not_defined'/ - @exception.to_s.should include(" 2: bar\n 3: baz\n 4: <%= this_is_not_defined %>\n 5: quin\n 6: qunx") - @exception.to_s.should include(@exception.original_exception.backtrace.first) - end - end - end -end - diff --git a/spec/unit/mixin/windows_architecture_helper_spec.rb b/spec/unit/mixin/windows_architecture_helper_spec.rb deleted file mode 100644 index f59602d716..0000000000 --- a/spec/unit/mixin/windows_architecture_helper_spec.rb +++ /dev/null @@ -1,83 +0,0 @@ -# -# Author:: Adam Edwards (<adamed@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' -require 'chef/mixin/windows_architecture_helper' - - - -describe Chef::Mixin::WindowsArchitectureHelper do - include Chef::Mixin::WindowsArchitectureHelper - - before do - @valid_architectures = [ :i386, :x86_64 ] - @invalid_architectures = [ "i386", "x86_64", :x64, :x86, :arm ] - - @node_i386 = Chef::Node.new - @node_x86_64 = Chef::Node.new - end - - it "returns true when valid architectures are passed to valid_windows_architecture?" do - @valid_architectures.each do | architecture | - valid_windows_architecture?(architecture).should == true - end - end - - it "returns false when invalid architectures are passed to valid_windows_architecture?" do - @invalid_architectures.each do | architecture | - valid_windows_architecture?(architecture).should == 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 | - 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 | - begin - assert_valid_windows_architecture!(architecture).should raise_error Chef::Exceptions::Win32ArchitectureIncorrect - rescue Chef::Exceptions::Win32ArchitectureIncorrect - end - 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) - 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) - end - - def enumerate_architecture_node_combinations(only_valid_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 | - node_supports_windows_architecture?(new_node, supported_architecture).should == true if only_valid_combinations && (supported_architecture != :x86_64 && node_architecture != :i386 ) - node_supports_windows_architecture?(new_node, supported_architecture).should == false if ! only_valid_combinations && (supported_architecture == :x86_64 && node_architecture == :i386 ) - end - end - end -end diff --git a/spec/unit/mixin/xml_escape_spec.rb b/spec/unit/mixin/xml_escape_spec.rb deleted file mode 100644 index 83debb5907..0000000000 --- a/spec/unit/mixin/xml_escape_spec.rb +++ /dev/null @@ -1,54 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -class XMLEscapingTestHarness - include Chef::Mixin::XMLEscape -end - -describe Chef::Mixin::XMLEscape do - before do - @escaper = XMLEscapingTestHarness.new - end - - it "escapes ampersands to '&'" do - @escaper.xml_escape("&").should == "&" - end - - it "escapes angle brackets to < or >" do - @escaper.xml_escape("<").should == "<" - @escaper.xml_escape(">").should == ">" - end - - it "does not modify ASCII strings" do - @escaper.xml_escape('foobarbaz!@#$%^*()').should == 'foobarbaz!@#$%^*()' - end - - it "converts invalid bytes to asterisks" do - @escaper.xml_escape("\x00").should == "*" - end - - it "converts UTF-8 correctly" do - @escaper.xml_escape("\xC2\xA9").should == '©' - end - - it "converts win 1252 characters correctly" do - @escaper.xml_escape("\x80").should == '€' - end -end diff --git a/spec/unit/monkey_patches/string_spec.rb b/spec/unit/monkey_patches/string_spec.rb deleted file mode 100644 index 8c6710b38e..0000000000 --- a/spec/unit/monkey_patches/string_spec.rb +++ /dev/null @@ -1,37 +0,0 @@ -# -# Author:: Devin Ben-Hur <dbenhur@whitepages.com> -# Copyright:: Copyright (c) 2008, 2011 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/monkey_patches/string' - -describe String do - - describe "#ord" do - it "converts each ASCII-8BIT character to corresponding positive Fixnum" do - (0..0xff).each do |num| - ch = num.chr - ch.force_encoding('ASCII-8BIT') if ch.respond_to? :force_encoding - - ch.ord.should be_a_kind_of(Fixnum) - ch.ord.should == num - end - end - - end - -end diff --git a/spec/unit/monkey_patches/uri_spec.rb b/spec/unit/monkey_patches/uri_spec.rb deleted file mode 100644 index cff252ac3b..0000000000 --- a/spec/unit/monkey_patches/uri_spec.rb +++ /dev/null @@ -1,34 +0,0 @@ -#-- -# Author:: Daniel DeLeo (<dan@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 URI do - - describe "when a URI contains an IPv6 literal" do - - let(:ipv6_uri) do - URI.parse("https://[2a00:1450:4009:809::1008]:8443") - end - - it "returns the hostname without brackets" do - ipv6_uri.hostname.should == "2a00:1450:4009:809::1008" - end - - end - -end diff --git a/spec/unit/monologger_spec.rb b/spec/unit/monologger_spec.rb deleted file mode 100644 index 3babc29218..0000000000 --- a/spec/unit/monologger_spec.rb +++ /dev/null @@ -1,45 +0,0 @@ -# -# Copyright:: Copyright (c) 2014 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/monologger' -require 'tempfile' -require 'spec_helper' - -describe MonoLogger do - it "should disable buffering when passed an IO stream" do - STDOUT.sync = false - MonoLogger.new(STDOUT) - STDOUT.sync.should == true - end - - describe "when given an object that responds to write and close e.g. IO" do - it "should use the object directly" do - stream = StringIO.new - MonoLogger.new(stream).fatal("Houston, we've had a problem.") - stream.string.should =~ /Houston, we've had a problem./ - end - end - - describe "when given an object that is stringable (to_str)" do - it "should open a File object with the given path" do - temp_file = Tempfile.new("rspec-monologger-log") - temp_file.close - MonoLogger.new(temp_file.path).fatal("Do, or do not. There is no try.") - File.read(temp_file.path).should =~ /Do, or do not. There is no try./ - end - end -end diff --git a/spec/unit/node/attribute_spec.rb b/spec/unit/node/attribute_spec.rb deleted file mode 100644 index 5325117d6c..0000000000 --- a/spec/unit/node/attribute_spec.rb +++ /dev/null @@ -1,1188 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: AJ Christensen (<aj@opscode.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/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 } - } - @default_hash = { - "domain" => "opscode.com", - "hot" => { "day" => "saturday" }, - "music" => { - "jimmy_eat_world" => "is fun!", - "mastodon" => "rocks", - "mars_volta" => "is loud and nutty", - "deeper" => { "gates_of_ishtar" => nil }, - "this" => {"apparatus" => {"must" => "be unearthed"}} - } - } - @override_hash = { - "macaddress" => "00:00:00:00:00:00", - "hot" => { "day" => "sunday" }, - "fire" => "still burn", - "music" => { - "mars_volta" => "cicatriz" - } - } - @automatic_hash = {"week" => "friday"} - @attributes = Chef::Node::Attribute.new(@attribute_hash, @default_hash, @override_hash, @automatic_hash) - end - - describe "initialize" do - it "should return a Chef::Node::Attribute" do - @attributes.should be_a_kind_of(Chef::Node::Attribute) - end - - it "should take an Automatioc, Normal, Default and Override hash" do - lambda { Chef::Node::Attribute.new({}, {}, {}, {}) }.should_not raise_error - end - - [ :normal, :default, :override, :automatic ].each do |accessor| - it "should set #{accessor}" do - na = Chef::Node::Attribute.new({ :normal => true }, { :default => true }, { :override => true }, { :automatic => true }) - na.send(accessor).should == { accessor.to_s => true } - end - end - - it "should be enumerable" do - @attributes.should be_is_a(Enumerable) - end - end - - describe "when printing attribute components" do - - it "does not cause a type error" do - # See CHEF-3799; IO#puts implicitly calls #to_ary on its argument. This - # is expected to raise a NoMethodError or return an Array. `to_ary` is - # the "strict" conversion method that should only be implemented by - # things that are truly Array-like, so NoMethodError is the right choice. - # (cf. there is no Hash#to_ary). - lambda { @attributes.default.to_ary }.should raise_error(NoMethodError) - end - - end - - describe "when debugging attributes" do - before do - @attributes.default[:foo][:bar] = "default" - @attributes.env_default[:foo][:bar] = "env_default" - @attributes.role_default[:foo][:bar] = "role_default" - @attributes.force_default[:foo][:bar] = "force_default" - @attributes.normal[:foo][:bar] = "normal" - @attributes.override[:foo][:bar] = "override" - @attributes.role_override[:foo][:bar] = "role_override" - @attributes.env_override[:foo][:bar] = "env_override" - @attributes.force_override[:foo][:bar] = "force_override" - @attributes.automatic[:foo][:bar] = "automatic" - end - - it "gives the value at each level of precedence for a path spec" do - expected = [["set_unless_enabled?", false], - ["default", "default"], - ["env_default", "env_default"], - ["role_default", "role_default"], - ["force_default", "force_default"], - ["normal", "normal"], - ["override", "override"], - ["role_override", "role_override"], - ["env_override", "env_override"], - ["force_override", "force_override"], - ["automatic", "automatic"] - ] - @attributes.debug_value(:foo, :bar).should == expected - end - end - - describe "when fetching values based on precedence" do - before do - @attributes.default["default"] = "cookbook default" - @attributes.override["override"] = "cookbook override" - end - - it "prefers 'forced default' over any other default" do - @attributes.default!["default"] = "force default" - @attributes.role_default["default"] = "role default" - @attributes.env_default["default"] = "environment default" - @attributes["default"].should == "force default" - end - - it "prefers role_default over environment or cookbook default" do - @attributes.role_default["default"] = "role default" - @attributes.env_default["default"] = "environment default" - @attributes["default"].should == "role default" - end - - it "prefers environment default over cookbook default" do - @attributes.env_default["default"] = "environment default" - @attributes["default"].should == "environment default" - end - - it "returns the cookbook default when no other default values are present" do - @attributes["default"].should == "cookbook default" - end - - it "prefers 'forced overrides' over role or cookbook overrides" do - @attributes.override!["override"] = "force override" - @attributes.env_override["override"] = "environment override" - @attributes.role_override["override"] = "role override" - @attributes["override"].should == "force override" - end - - it "prefers environment overrides over role or cookbook overrides" do - @attributes.env_override["override"] = "environment override" - @attributes.role_override["override"] = "role override" - @attributes["override"].should == "environment override" - end - - it "prefers role overrides over cookbook overrides" do - @attributes.role_override["override"] = "role override" - @attributes["override"].should == "role override" - end - - it "returns cookbook overrides when no other overrides are present" do - @attributes["override"].should == "cookbook override" - end - - it "merges arrays within the default precedence" do - @attributes.role_default["array"] = %w{role} - @attributes.env_default["array"] = %w{env} - @attributes["array"].should == %w{env role} - end - - it "merges arrays within the override precedence" do - @attributes.role_override["array"] = %w{role} - @attributes.env_override["array"] = %w{env} - @attributes["array"].should == %w{role env} - end - - it "does not merge arrays between default and normal" do - @attributes.role_default["array"] = %w{role} - @attributes.normal["array"] = %w{normal} - @attributes["array"].should == %w{normal} - end - - it "does not merge arrays between normal and override" do - @attributes.normal["array"] = %w{normal} - @attributes.role_override["array"] = %w{role} - @attributes["array"].should == %w{role} - end - - 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"}} - @attributes["a"].should == {"b"=>{"default"=>"default", "normal"=>"normal"}, - "override"=>"role", - "automatic"=>"auto"} - end - end - - describe "when reading combined default or override values" do - before do - @attributes.default["cd"] = "cookbook default" - @attributes.role_default["rd"] = "role default" - @attributes.env_default["ed"] = "env default" - @attributes.default!["fd"] = "force default" - @attributes.override["co"] = "cookbook override" - @attributes.role_override["ro"] = "role override" - @attributes.env_override["eo"] = "env override" - @attributes.override!["fo"] = "force override" - end - - it "merges all types of overrides into a combined override" do - @attributes.combined_override["co"].should == "cookbook override" - @attributes.combined_override["ro"].should == "role override" - @attributes.combined_override["eo"].should == "env override" - @attributes.combined_override["fo"].should == "force override" - end - - it "merges all types of defaults into a combined default" do - @attributes.combined_default["cd"].should == "cookbook default" - @attributes.combined_default["rd"].should == "role default" - @attributes.combined_default["ed"].should == "env default" - @attributes.combined_default["fd"].should == "force default" - end - - end - - describe "[]" do - it "should return override data if it exists" do - @attributes["macaddress"].should == "00:00:00:00:00:00" - end - - it "should return attribute data if it is not overridden" do - @attributes["platform"].should == "mac_os_x" - end - - it "should return data that doesn't have corresponding keys in every hash" do - @attributes["command"]["ps"].should == "ps -ef" - end - - it "should return default data if it is not overriden or in attribute data" do - @attributes["music"]["mastodon"].should == "rocks" - end - - it "should prefer the override data over an available default" do - @attributes["music"]["mars_volta"].should == "cicatriz" - end - - it "should prefer the attribute data over an available default" do - @attributes["music"]["jimmy_eat_world"].should == "nice" - end - - it "should prefer override data over default data if there is no attribute data" do - @attributes["hot"]["day"].should == "sunday" - end - - it "should return the merged hash if all three have values" do - result = @attributes["music"] - result["mars_volta"].should == "cicatriz" - result["jimmy_eat_world"].should == "nice" - result["mastodon"].should == "rocks" - end - end - - describe "[]=" do - it "should error out when the type of attribute to set has not been specified" do - @attributes.normal["the_ghost"] = { } - lambda { @attributes["the_ghost"]["exterminate"] = false }.should raise_error(Chef::Exceptions::ImmutableAttributeModification) - end - - it "should let you set an attribute value when another hash has an intermediate value" do - @attributes.normal["the_ghost"] = { "exterminate" => "the future" } - lambda { @attributes.normal["the_ghost"]["eviscerate"]["tomorrow"] = false }.should_not raise_error - end - - it "should set the attribute value" do - @attributes.normal["longboard"] = "surfing" - @attributes.normal["longboard"].should == "surfing" - @attributes.normal["longboard"].should == "surfing" - end - - it "should set deeply nested attribute values when a precedence level is specified" do - @attributes.normal["deftones"]["hunters"]["nap"] = "surfing" - @attributes.normal["deftones"]["hunters"]["nap"].should == "surfing" - end - - it "should die if you try and do nested attributes that do not exist without read vivification" do - lambda { @attributes["foo"]["bar"] = :baz }.should raise_error - end - - it "should let you set attributes manually without vivification" do - @attributes.normal["foo"] = Mash.new - @attributes.normal["foo"]["bar"] = :baz - @attributes.normal["foo"]["bar"].should == :baz - end - - it "should optionally skip setting the value if one already exists" do - @attributes.set_unless_value_present = true - @attributes.normal["hostname"] = "bar" - @attributes["hostname"].should == "latte" - end - - it "does not support ||= when setting" do - # This is a limitation of auto-vivification. - # Users who need this behavior can use set_unless and friends - @attributes.normal["foo"] = Mash.new - @attributes.normal["foo"]["bar"] ||= "stop the world" - @attributes.normal["foo"]["bar"].should == {} - end - end - - describe "to_hash" do - it "should convert to a hash" do - @attributes.to_hash.class.should == Hash - end - - it "should convert to a hash based on current state" do - hash = @attributes["hot"].to_hash - hash.class.should == Hash - hash["day"].should == "sunday" - 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].dup - end - end - - describe "has_key?" do - it "should return true if an attribute exists" do - @attributes.has_key?("music").should == true - end - - it "should return false if an attribute does not exist" do - @attributes.has_key?("ninja").should == false - end - - it "should return false if an attribute does not exist using dot notation" do - @attributes.has_key?("does_not_exist_at_all").should == false - end - - it "should return true if an attribute exists but is set to nil using dot notation" do - @attributes.music.deeper.has_key?("gates_of_ishtar").should == true - end - - it "should return true if an attribute exists but is set to false" do - @attributes.has_key?("music") - @attributes["music"].has_key?("apophis").should == true - end - - it "does not find keys above the current nesting level" do - @attributes["music"]["this"]["apparatus"].should_not have_key("this") - end - - it "does not find keys below the current nesting level" do - @attributes["music"]["this"].should_not have_key("must") - end - - [:include?, :key?, :member?].each do |method| - it "should alias the method #{method} to itself" do - @attributes.should respond_to(method) - end - - it "#{method} should behave like has_key?" do - @attributes.send(method, "music").should == true - end - end - end - - describe "attribute?" do - it "should return true if an attribute exists" do - @attributes.attribute?("music").should == true - end - - it "should return false if an attribute does not exist" do - @attributes.attribute?("ninja").should == false - end - - end - - describe "method_missing" do - it "should behave like a [] lookup" do - @attributes.music.mastodon.should == "rocks" - end - - it "should allow the last method to set a value if it has an = sign on the end" do - @attributes.normal.music.mastodon = [ "dream", "still", "shining" ] - @attributes.reset - @attributes.normal.music.mastodon.should == [ "dream", "still", "shining" ] - end - end - - describe "keys" do - before(:each) do - @attributes = Chef::Node::Attribute.new( - { - "one" => { "two" => "three" }, - "hut" => { "two" => "three" }, - "place" => { } - }, - { - "one" => { "four" => "five" }, - "snakes" => "on a plane" - }, - { - "one" => { "six" => "seven" }, - "snack" => "cookies" - }, - {} - ) - end - - it "should yield each top level key" do - collect = Array.new - @attributes.keys.each do |k| - collect << k - end - collect.include?("one").should == true - collect.include?("hut").should == true - collect.include?("snakes").should == true - collect.include?("snack").should == true - collect.include?("place").should == true - collect.length.should == 5 - end - - it "should yield lower if we go deeper" do - collect = Array.new - @attributes.one.keys.each do |k| - collect << k - end - collect.include?("two").should == true - collect.include?("four").should == true - collect.include?("six").should == true - collect.length.should == 3 - end - - it "should not raise an exception if one of the hashes has a nil value on a deep lookup" do - lambda { @attributes.place.keys { |k| } }.should_not raise_error - end - end - - describe "each" do - before(:each) do - @attributes = Chef::Node::Attribute.new( - { - "one" => "two", - "hut" => "three", - }, - { - "one" => "four", - "snakes" => "on a plane" - }, - { - "one" => "six", - "snack" => "cookies" - }, - {} - ) - end - - it "should yield each top level key and value, post merge rules" do - collect = Hash.new - @attributes.each do |k, v| - collect[k] = v - end - - collect["one"].should == "six" - collect["hut"].should == "three" - collect["snakes"].should == "on a plane" - collect["snack"].should == "cookies" - end - - it "should yield as a two-element array" do - @attributes.each do |a| - a.should be_an_instance_of(Array) - end - end - end - - describe "each_key" do - before do - @attributes = Chef::Node::Attribute.new( - { - "one" => "two", - "hut" => "three", - }, - { - "one" => "four", - "snakes" => "on a plane" - }, - { - "one" => "six", - "snack" => "cookies" - }, - {} - ) - end - - it "should respond to each_key" do - @attributes.should respond_to(:each_key) - end - - it "should yield each top level key, post merge rules" do - collect = Array.new - @attributes.each_key do |k| - collect << k - end - - collect.should include("one") - collect.should include("snack") - collect.should include("hut") - collect.should include("snakes") - end - end - - describe "each_pair" do - before do - @attributes = Chef::Node::Attribute.new( - { - "one" => "two", - "hut" => "three", - }, - { - "one" => "four", - "snakes" => "on a plane" - }, - { - "one" => "six", - "snack" => "cookies" - }, - {} - ) - end - - it "should respond to each_pair" do - @attributes.should respond_to(:each_pair) - end - - it "should yield each top level key and value pair, post merge rules" do - collect = Hash.new - @attributes.each_pair do |k, v| - collect[k] = v - end - - collect["one"].should == "six" - collect["hut"].should == "three" - collect["snakes"].should == "on a plane" - collect["snack"].should == "cookies" - end - end - - describe "each_value" do - before do - @attributes = Chef::Node::Attribute.new( - { - "one" => "two", - "hut" => "three", - }, - { - "one" => "four", - "snakes" => "on a plane" - }, - { - "one" => "six", - "snack" => "cookies" - }, - {} - ) - end - - it "should respond to each_value" do - @attributes.should respond_to(:each_value) - end - - it "should yield each value, post merge rules" do - collect = Array.new - @attributes.each_value do |v| - collect << v - end - - collect.should include("cookies") - collect.should include("three") - collect.should include("on a plane") - end - - it "should yield four elements" do - collect = Array.new - @attributes.each_value do |v| - collect << v - end - - collect.length.should == 4 - end - end - - describe "empty?" do - before do - @attributes = Chef::Node::Attribute.new( - { - "one" => "two", - "hut" => "three", - }, - { - "one" => "four", - "snakes" => "on a plane" - }, - { - "one" => "six", - "snack" => "cookies" - }, - {} - ) - @empty = Chef::Node::Attribute.new({}, {}, {}, {}) - end - - it "should respond to empty?" do - @attributes.should respond_to(:empty?) - end - - it "should return true when there are no keys" do - @empty.empty?.should == true - end - - it "should return false when there are keys" do - @attributes.empty?.should == false - end - - end - - describe "fetch" do - before do - @attributes = Chef::Node::Attribute.new( - { - "one" => "two", - "hut" => "three", - }, - { - "one" => "four", - "snakes" => "on a plane" - }, - { - "one" => "six", - "snack" => "cookies" - }, - {} - ) - end - - it "should respond to fetch" do - @attributes.should respond_to(:fetch) - end - - describe "when the key exists" do - it "should return the value of the key, post merge (same result as each)" do - { - "one" => "six", - "hut" => "three", - "snakes" => "on a plane", - "snack" => "cookies" - }.each do |k,v| - @attributes.fetch(k).should == v - end - end - end - - describe "when the key does not exist" do - describe "and no args are passed" do - it "should raise an indexerror" do - lambda { @attributes.fetch("lololol") }.should raise_error(IndexError) - end - end - - describe "and a default arg is passed" do - it "should return the value of the default arg" do - @attributes.fetch("lol", "blah").should == "blah" - end - end - - describe "and a block is passed" do - it "should run the block and return its value" do - @attributes.fetch("lol") { |x| "#{x}, blah" }.should == "lol, blah" - end - end - end - end - - describe "has_value?" do - before do - @attributes = Chef::Node::Attribute.new( - { - "one" => "two", - "hut" => "three", - }, - { - "one" => "four", - "snakes" => "on a plane" - }, - { - "one" => "six", - "snack" => "cookies" - }, - {} - ) - end - - it "should respond to has_value?" do - @attributes.should respond_to(:has_value?) - end - - it "should return true if any key has the value supplied" do - @attributes.has_value?("cookies").should == true - end - - it "should return false no key has the value supplied" do - @attributes.has_value?("lololol").should == false - end - - it "should alias value?" do - @attributes.should respond_to(:value?) - end - end - - describe "index" do - # Hash#index is deprecated and triggers warnings. - def silence - old_verbose = $VERBOSE - $VERBOSE = nil - yield - ensure - $VERBOSE = old_verbose - end - - before do - @attributes = Chef::Node::Attribute.new( - { - "one" => "two", - "hut" => "three", - }, - { - "one" => "four", - "snakes" => "on a plane" - }, - { - "one" => "six", - "snack" => "cookies" - }, - {} - ) - end - - it "should respond to index" do - @attributes.should respond_to(:index) - end - - describe "when the value is indexed" do - it "should return the index" do - silence do - @attributes.index("six").should == "one" - end - end - end - - describe "when the value is not indexed" do - it "should return nil" do - silence do - @attributes.index("lolol").should == nil - end - end - end - - end - - - describe "values" do - before do - @attributes = Chef::Node::Attribute.new( - { - "one" => "two", - "hut" => "three", - }, - { - "one" => "four", - "snakes" => "on a plane" - }, - { - "one" => "six", - "snack" => "cookies" - }, - {} - ) - end - - it "should respond to values" do - @attributes.should respond_to(:values) - end - - it "should return an array of values" do - @attributes.values.length.should == 4 - end - - it "should match the values output from each" do - @attributes.values.should include("six") - @attributes.values.should include("cookies") - @attributes.values.should include("three") - @attributes.values.should include("on a plane") - end - - end - - describe "select" do - before do - @attributes = Chef::Node::Attribute.new( - { - "one" => "two", - "hut" => "three", - }, - { - "one" => "four", - "snakes" => "on a plane" - }, - { - "one" => "six", - "snack" => "cookies" - }, - {} - ) - end - - it "should respond to select" do - @attributes.should respond_to(:select) - end - - if RUBY_VERSION >= "1.8.7" - it "should not raise a LocalJumpError if no block is given" do - lambda { @attributes.select }.should_not raise_error - end - else - it "should raise a LocalJumpError if no block is given" do - lambda{ @attributes.select }.should raise_error(LocalJumpError) - end - end - - it "should return an empty hash/array (ruby-version-dependent) for a block containing nil" do - @attributes.select { nil }.should == {}.select { nil } - end - - # sorted for spec clarity - it "should return a new array of k,v pairs for which the block returns true" do - @attributes.select { true }.sort.should == ( - [ - ["hut", "three"], - ["one", "six"], - ["snack", "cookies"], - ["snakes", "on a plane"] - ] - ) - end - end - - describe "size" do - before do - @attributes = Chef::Node::Attribute.new( - { - "one" => "two", - "hut" => "three", - }, - { - "one" => "four", - "snakes" => "on a plane" - }, - { - "one" => "six", - "snack" => "cookies" - }, - {} - ) - - @empty = Chef::Node::Attribute.new({},{},{},{}) - end - - it "should respond to size" do - @attributes.should respond_to(:size) - end - - it "should alias length to size" do - @attributes.should respond_to(:length) - end - - it "should return 0 for an empty attribute" do - @empty.size.should == 0 - end - - it "should return the number of pairs" do - @attributes.size.should == 4 - end - end - - describe "kind_of?" do - it "should falsely inform you that it is a Hash" do - @attributes.should be_a_kind_of(Hash) - end - - it "should falsely inform you that it is a Mash" do - @attributes.should be_a_kind_of(Mash) - end - - it "should inform you that it is a Chef::Node::Attribute" do - @attributes.should be_a_kind_of(Chef::Node::Attribute) - end - - it "should inform you that it is anything else" do - @attributes.should_not be_a_kind_of(Chef::Node) - end - end - - describe "inspect" do - it "should be readable" do - # NOTE: previous implementation hid the values, showing @automatic={...} - # That is nice and compact, but hides a lot of info, which seems counter - # to the point of calling #inspect... - @attributes.inspect.should =~ /@automatic=\{.*\}/ - @attributes.inspect.should =~ /@normal=\{.*\}/ - end - end - - # For expedience, this test is implementation-heavy. - describe "when a component attribute is mutated" do - [ - :clear, - :shift - ].each do |mutator| - it "resets the cache when the mutator #{mutator} is called" do - @attributes.should_receive(:reset_cache) - @attributes.default.send(mutator) - end - end - - it "resets the cache when the mutator delete is called" do - @attributes.should_receive(:reset_cache) - @attributes.default.delete(:music) - end - - [ - :merge!, - :update, - :replace - ].each do |mutator| - it "resets the cache when the mutator #{mutator} is called" do - # Implementation of Mash means that this could get called many times. That's okay. - @attributes.should_receive(:reset_cache).at_least(1).times - @attributes.default.send(mutator, {:foo => :bar}) - end - end - - [ - :delete_if, - :keep_if, - :reject!, - :select!, - ].each do |mutator| - it "resets the cache when the mutator #{mutator} is called" do - # Implementation of Mash means that this could get called many times. That's okay. - @attributes.should_receive(:reset_cache).at_least(1).times - block = lambda {|k,v| true } - @attributes.default.send(mutator, &block) - end - end - end - - describe "when not mutated" do - - it "does not reset the cache when dup'd [CHEF-3680]" do - @attributes.default[:foo][:bar] = "set on original" - subtree = @attributes[:foo] - @attributes.default[:foo].dup[:bar] = "set on dup" - subtree[:bar].should == "set on original" - end - - end - - describe "when setting a component attribute to a new value" do - it "converts the input in to a VividMash tree (default)" do - @attributes.default = {} - @attributes.default.foo = "bar" - @attributes.merged_attributes[:foo].should == "bar" - end - - it "converts the input in to a VividMash tree (normal)" do - @attributes.normal = {} - @attributes.normal.foo = "bar" - @attributes.merged_attributes[:foo].should == "bar" - end - - it "converts the input in to a VividMash tree (override)" do - @attributes.override = {} - @attributes.override.foo = "bar" - @attributes.merged_attributes[:foo].should == "bar" - end - - it "converts the input in to a VividMash tree (automatic)" do - @attributes.automatic = {} - @attributes.automatic.foo = "bar" - @attributes.merged_attributes[:foo].should == "bar" - end - end - - describe "when attemping to write without specifying precedence" do - it "raises an error when using []=" do - lambda { @attributes[:new_key] = "new value" }.should raise_error(Chef::Exceptions::ImmutableAttributeModification) - end - - it "raises an error when using `attr=value`" do - lambda { @attributes.new_key = "new value" }.should raise_error(Chef::Exceptions::ImmutableAttributeModification) - end - - end - -end - diff --git a/spec/unit/node/immutable_collections_spec.rb b/spec/unit/node/immutable_collections_spec.rb deleted file mode 100644 index 1c216e327a..0000000000 --- a/spec/unit/node/immutable_collections_spec.rb +++ /dev/null @@ -1,198 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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/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"}} - } - @immutable_mash = Chef::Node::ImmutableMash.new(@data_in) - end - - it "element references like regular hash" do - @immutable_mash[:top][:second_level].should == "some value" - end - - it "elelment references like a regular Mash" do - @immutable_mash[:top_level_2].should == %w[array of values] - end - - it "converts Hash-like inputs into ImmutableMash's" do - @immutable_mash[:top].should be_a(Chef::Node::ImmutableMash) - end - - it "converts array inputs into ImmutableArray's" do - @immutable_mash[:top_level_2].should be_a(Chef::Node::ImmutableArray) - end - - it "converts arrays of hashes to ImmutableArray's of ImmutableMashes" do - @immutable_mash[:top_level_3].first.should be_a(Chef::Node::ImmutableMash) - end - - it "converts nested hashes to ImmutableMashes" do - @immutable_mash[:top_level_4].should be_a(Chef::Node::ImmutableMash) - @immutable_mash[:top_level_4][:level2].should be_a(Chef::Node::ImmutableMash) - end - - describe "to_hash" do - before do - @copy = @immutable_mash.to_hash - end - - it "converts an immutable mash to a new mutable hash" do - @copy.should be_instance_of(Hash) - end - - it "converts an immutable nested mash to a new mutable hash" do - @copy['top_level_4']['level2'].should be_instance_of(Hash) - end - - it "converts an immutable nested array to a new mutable array" do - @copy['top_level_2'].should be_instance_of(Array) - end - - it "should create a mash with the same content" do - @copy.should == @immutable_mash - end - - it 'should allow mutation' do - lambda { @copy['m'] = 'm' }.should_not raise_error - end - - end - - [ - :[]=, - :clear, - :default=, - :default_proc=, - :delete, - :delete_if, - :keep_if, - :merge!, - :update, - :reject!, - :replace, - :select!, - :shift - ].each do |mutator| - it "doesn't allow mutation via `#{mutator}'" do - lambda { @immutable_mash.send(mutator) }.should raise_error - end - end - - it "returns a mutable version of itself when duped" do - mutable = @immutable_mash.dup - mutable[:new_key] = :value - mutable[:new_key].should == :value - end - -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",@immutable_array, immutable_mash]) - end - - ## - # Note: other behaviors, such as immutibilizing input data, are tested along - # with ImmutableMash, above - ### - - [ - :<<, - :[]=, - :clear, - :collect!, - :compact!, - :default=, - :default_proc=, - :delete, - :delete_at, - :delete_if, - :fill, - :flatten!, - :insert, - :keep_if, - :map!, - :merge!, - :pop, - :push, - :update, - :reject!, - :reverse!, - :replace, - :select!, - :shift, - :slice!, - :sort!, - :sort_by!, - :uniq!, - :unshift - ].each do |mutator| - it "does not allow mutation via `#{mutator}" do - lambda { @immutable_array.send(mutator)}.should raise_error - end - end - - it "can be duped even if some elements can't" do - @immutable_array.dup - end - - it "returns a mutable version of itself when duped" do - mutable = @immutable_array.dup - mutable[0] = :value - mutable[0].should == :value - end - - describe "to_a" do - before do - @copy = @immutable_nested_array.to_a - end - - it "converts an immutable array to a new mutable array" do - @copy.should be_instance_of(Array) - end - - it "converts an immutable nested array to a new mutable array" do - @copy[1].should be_instance_of(Array) - end - - it "converts an immutable nested mash to a new mutable hash" do - @copy[2].should be_instance_of(Hash) - end - - it "should create an array with the same content" do - @copy.should == @immutable_nested_array - end - - it 'should allow mutation' do - lambda { @copy << 'm' }.should_not raise_error - end - end - -end - diff --git a/spec/unit/node_spec.rb b/spec/unit/node_spec.rb deleted file mode 100644 index 21a978a9c9..0000000000 --- a/spec/unit/node_spec.rb +++ /dev/null @@ -1,923 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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 'ostruct' - -describe Chef::Node do - - let(:node) { Chef::Node.new() } - let(:platform_introspector) { node } - - it_behaves_like "a platform introspector" - - it "creates a node and assigns it a name" do - node = Chef::Node.build('solo-node') - node.name.should == 'solo-node' - end - - it "should validate the name of the node" do - lambda{Chef::Node.build('solo node')}.should 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') - [n3, n1, n2].sort.should == [n1, n2, n3] - end - - describe "when the node does not exist on the server" do - before do - response = OpenStruct.new(:code => '404') - exception = Net::HTTPServerException.new("404 not found", response) - Chef::Node.stub(:load).and_raise(exception) - node.name("created-node") - end - - it "creates a new node for find_or_create" do - Chef::Node.stub(:new).and_return(node) - node.should_receive(:create).and_return(node) - node = Chef::Node.find_or_create("created-node") - node.name.should == 'created-node' - node.should equal(node) - end - end - - describe "when the node exists on the server" do - before do - node.name('existing-node') - Chef::Node.stub(:load).and_return(node) - end - - it "loads the node via the REST API for find_or_create" do - Chef::Node.find_or_create('existing-node').should equal(node) - end - end - - describe "run_state" do - it "is an empty hash" do - node.run_state.should respond_to(:keys) - node.run_state.should be_empty - end - end - - describe "initialize" do - it "should default to the '_default' chef_environment" do - n = Chef::Node.new - n.chef_environment.should == '_default' - end - end - - describe "name" do - it "should allow you to set a name with name(something)" do - lambda { node.name("latte") }.should_not raise_error - end - - it "should return the name with name()" do - node.name("latte") - node.name.should eql("latte") - end - - it "should always have a string for name" do - lambda { node.name(Hash.new) }.should raise_error(ArgumentError) - end - - it "cannot be blank" do - lambda { node.name("")}.should raise_error(Chef::Exceptions::ValidationFailed) - end - - it "should not accept name doesn't match /^[\-[:alnum:]_:.]+$/" do - lambda { node.name("space in it")}.should raise_error(Chef::Exceptions::ValidationFailed) - end - end - - describe "chef_environment" do - it "should set an environment with chef_environment(something)" do - lambda { node.chef_environment("latte") }.should_not raise_error - end - - it "should return the chef_environment with chef_environment()" do - node.chef_environment("latte") - node.chef_environment.should == "latte" - end - - it "should disallow non-strings" do - lambda { node.chef_environment(Hash.new) }.should raise_error(ArgumentError) - lambda { node.chef_environment(42) }.should raise_error(ArgumentError) - end - - it "cannot be blank" do - lambda { node.chef_environment("")}.should raise_error(Chef::Exceptions::ValidationFailed) - end - end - - describe "attributes" do - it "should have attributes" do - node.attribute.should be_a_kind_of(Hash) - end - - it "should allow attributes to be accessed by name or symbol directly on node[]" do - node.default["locust"] = "something" - node[:locust].should eql("something") - node["locust"].should eql("something") - end - - it "should return nil if it cannot find an attribute with node[]" do - node["secret"].should eql(nil) - end - - it "does not allow you to set an attribute via node[]=" do - lambda { node["secret"] = "shush" }.should raise_error(Chef::Exceptions::ImmutableAttributeModification) - end - - it "should allow you to query whether an attribute exists with attribute?" do - node.default["locust"] = "something" - node.attribute?("locust").should eql(true) - node.attribute?("no dice").should eql(false) - end - - it "should let you go deep with attribute?" do - node.set["battles"]["people"]["wonkey"] = true - node["battles"]["people"].attribute?("wonkey").should == true - node["battles"]["people"].attribute?("snozzberry").should == false - end - - it "does not allow you to set an attribute via method_missing" do - lambda { node.sunshine = "is bright"}.should raise_error(Chef::Exceptions::ImmutableAttributeModification) - end - - it "should allow you get get an attribute via method_missing" do - node.default.sunshine = "is bright" - node.sunshine.should eql("is bright") - end - - describe "normal attributes" do - it "should allow you to set an attribute with set, without pre-declaring a hash" do - node.set[:snoopy][:is_a_puppy] = true - node[:snoopy][:is_a_puppy].should == true - end - - it "should allow you to set an attribute with set_unless" do - node.set_unless[:snoopy][:is_a_puppy] = false - node[:snoopy][:is_a_puppy].should == false - end - - it "should not allow you to set an attribute with set_unless if it already exists" do - node.set[:snoopy][:is_a_puppy] = true - node.set_unless[:snoopy][:is_a_puppy] = false - node[:snoopy][:is_a_puppy].should == true - 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 - node.set[:snoopy][:is_a_puppy] = true - node[:snoopy][:is_a_puppy].should == true - end - - it "should let you set a value after a 'dangling' set_unless" do - # this tests for set_unless_present state bleeding between statements CHEF-3806 - node.set[:snoopy][:is_a_puppy] = "what" - node.set_unless[:snoopy][:is_a_puppy] - node.set[:snoopy][:is_a_puppy] = true - node[:snoopy][:is_a_puppy].should == true - end - - it "auto-vivifies attributes created via method syntax" do - node.set.fuu.bahrr.baz = "qux" - node.fuu.bahrr.baz.should == "qux" - 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') - node['tags'].should == ['one', 'two', 'three', 'four'] - end - end - - describe "default attributes" do - it "should be set with default, without pre-declaring a hash" do - node.default[:snoopy][:is_a_puppy] = true - node[:snoopy][:is_a_puppy].should == true - end - - it "should allow you to set with default_unless without pre-declaring a hash" do - node.default_unless[:snoopy][:is_a_puppy] = false - node[:snoopy][:is_a_puppy].should == false - end - - it "should not allow you to set an attribute with default_unless if it already exists" do - node.default[:snoopy][:is_a_puppy] = true - node.default_unless[:snoopy][:is_a_puppy] = false - node[:snoopy][:is_a_puppy].should == true - end - - it "should allow you to set a value after a default_unless" do - # this tests for set_unless_present state bleeding between statements CHEF-3806 - node.default_unless[:snoopy][:is_a_puppy] = false - node.default[:snoopy][:is_a_puppy] = true - node[:snoopy][:is_a_puppy].should == true - end - - it "should allow you to set a value after a 'dangling' default_unless" do - # this tests for set_unless_present state bleeding between statements CHEF-3806 - node.default[:snoopy][:is_a_puppy] = "what" - node.default_unless[:snoopy][:is_a_puppy] - node.default[:snoopy][:is_a_puppy] = true - node[:snoopy][:is_a_puppy].should == true - end - - it "auto-vivifies attributes created via method syntax" do - node.default.fuu.bahrr.baz = "qux" - node.fuu.bahrr.baz.should == "qux" - end - - it "accesses force defaults via default!" do - node.default![:foo] = "wet bar" - node.default[:foo] = "bar" - node[:foo].should == "wet bar" - end - - end - - describe "override attributes" do - it "should be set with override, without pre-declaring a hash" do - node.override[:snoopy][:is_a_puppy] = true - node[:snoopy][:is_a_puppy].should == true - end - - it "should allow you to set with override_unless without pre-declaring a hash" do - node.override_unless[:snoopy][:is_a_puppy] = false - node[:snoopy][:is_a_puppy].should == false - end - - it "should not allow you to set an attribute with override_unless if it already exists" do - node.override[:snoopy][:is_a_puppy] = true - node.override_unless[:snoopy][:is_a_puppy] = false - node[:snoopy][:is_a_puppy].should == true - end - - it "should allow you to set a value after an override_unless" do - # this tests for set_unless_present state bleeding between statements CHEF-3806 - node.override_unless[:snoopy][:is_a_puppy] = false - node.override[:snoopy][:is_a_puppy] = true - node[:snoopy][:is_a_puppy].should == true - end - - it "should allow you to set a value after a 'dangling' override_unless" do - # this tests for set_unless_present state bleeding between statements CHEF-3806 - node.override_unless[:snoopy][:is_a_puppy] = "what" - node.override_unless[:snoopy][:is_a_puppy] - node.override[:snoopy][:is_a_puppy] = true - node[:snoopy][:is_a_puppy].should == true - end - - it "auto-vivifies attributes created via method syntax" do - node.override.fuu.bahrr.baz = "qux" - node.fuu.bahrr.baz.should == "qux" - end - - it "sets force_overrides via override!" do - node.override![:foo] = "wet bar" - node.override[:foo] = "bar" - node[:foo].should == "wet bar" - end - - end - - it "should raise an ArgumentError if you ask for an attribute that doesn't exist via method_missing" do - lambda { node.sunshine }.should raise_error(NoMethodError) - end - - it "should allow you to iterate over attributes with each_attribute" do - node.default.sunshine = "is bright" - node.default.canada = "is a nice place" - seen_attributes = Hash.new - node.each_attribute do |a,v| - seen_attributes[a] = v - end - seen_attributes.should have_key("sunshine") - seen_attributes.should have_key("canada") - seen_attributes["sunshine"].should == "is bright" - seen_attributes["canada"].should == "is a nice place" - end - end - - describe "consuming json" do - - before do - @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"} - node.consume_run_list(attrs).should == {"foo" => "bar"} - node.run_list.should == [ "role[base]", "recipe[chef::server]" ] - 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" ] - node.run_list.should == [ "three" ] - end - - it "should not add duplicate recipes from the json attributes" do - node.run_list << "one" - node.consume_run_list "recipes" => [ "one", "two", "three" ] - node.run_list.should == [ "one", "two", "three" ] - end - - it "doesn't change the run list if no run_list is specified in the json" do - node.run_list << "role[database]" - node.consume_run_list "foo" => "bar" - node.run_list.should == ["role[database]"] - end - - it "raises an exception if you provide both recipe and run_list attributes, since this is ambiguous" do - lambda { node.consume_run_list "recipes" => "stuff", "run_list" => "other_stuff" }.should raise_error(Chef::Exceptions::AmbiguousRunlistSpecification) - end - - it "should add json attributes to the node" do - node.consume_external_attrs(@ohai_data, {"one" => "two", "three" => "four"}) - node.one.should eql("two") - node.three.should eql("four") - end - - it "should set the tags attribute to an empty array if it is not already defined" do - node.consume_external_attrs(@ohai_data, {}) - node.tags.should eql([]) - end - - it "should not set the tags attribute to an empty array if it is already defined" do - node.normal[:tags] = [ "radiohead" ] - node.consume_external_attrs(@ohai_data, {}) - node.tags.should eql([ "radiohead" ]) - end - - it "deep merges attributes instead of overwriting them" do - node.consume_external_attrs(@ohai_data, "one" => {"two" => {"three" => "four"}}) - node.one.to_hash.should == {"two" => {"three" => "four"}} - node.consume_external_attrs(@ohai_data, "one" => {"abc" => "123"}) - node.consume_external_attrs(@ohai_data, "one" => {"two" => {"foo" => "bar"}}) - node.one.to_hash.should == {"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"}}) - node.one.to_hash.should == {"two" => {"three" => "four"}} - node.consume_external_attrs(@ohai_data, "one" => {"two" => {"three" => "forty-two"}}) - node.one.to_hash.should == {"two" => {"three" => "forty-two"}} - end - - end - - describe "preparing for a chef client run" do - before do - @ohai_data = {:platform => 'foobuntu', :platform_version => '23.42'} - end - - it "sets its platform according to platform detection" do - node.consume_external_attrs(@ohai_data, {}) - node.automatic_attrs[:platform].should == 'foobuntu' - node.automatic_attrs[:platform_version].should == '23.42' - end - - it "consumes the run list from provided json attributes" do - node.consume_external_attrs(@ohai_data, {"run_list" => ['recipe[unicorn]']}) - node.run_list.should == ['recipe[unicorn]'] - end - - it "saves non-runlist json attrs for later" do - expansion = Chef::RunList::RunListExpansion.new('_default', []) - node.run_list.stub(:expand).and_return(expansion) - node.consume_external_attrs(@ohai_data, {"foo" => "bar"}) - node.expand! - node.normal_attrs.should == {"foo" => "bar", "tags" => []} - end - - end - - describe "when expanding its run list and merging attributes" do - before do - @environment = Chef::Environment.new.tap do |e| - e.name('rspec_env') - e.default_attributes("env default key" => "env default value") - e.override_attributes("env override key" => "env override value") - end - Chef::Environment.should_receive(:load).with("rspec_env").and_return(@environment) - @expansion = Chef::RunList::RunListExpansion.new("rspec_env", []) - node.chef_environment("rspec_env") - node.run_list.stub(:expand).and_return(@expansion) - end - - it "sets the 'recipes' automatic attribute to the recipes in the expanded run_list" do - @expansion.recipes << 'recipe[chef::client]' << 'recipe[nginx::default]' - node.expand! - node.automatic_attrs[:recipes].should == ['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}) - node.expand! - node.automatic_attrs[:roles].sort.should == ['arf', 'countersnark'] - end - - it "applies default attributes from the environment as environment defaults" do - node.expand! - node.attributes.env_default["env default key"].should == "env default value" - end - - it "applies override attributes from the environment as env overrides" do - node.expand! - node.attributes.env_override["env override key"].should == "env override value" - end - - it "applies default attributes from roles as role defaults" do - @expansion.default_attrs["role default key"] = "role default value" - node.expand! - node.attributes.role_default["role default key"].should == "role default value" - end - - it "applies override attributes from roles as role overrides" do - @expansion.override_attrs["role override key"] = "role override value" - node.expand! - node.attributes.role_override["role override key"].should == "role override value" - end - end - - describe "loaded_recipe" do - it "should not add a recipe that is already in the recipes list" do - node.automatic_attrs[:recipes] = [ "nginx::module" ] - node.loaded_recipe(:nginx, "module") - expect(node.automatic_attrs[:recipes].length).to eq(1) - end - - it "should add a recipe that is not already in the recipes list" do - node.automatic_attrs[:recipes] = [ "nginx::other_module" ] - node.loaded_recipe(:nginx, "module") - expect(node.automatic_attrs[:recipes].length).to eq(2) - expect(node.recipe?("nginx::module")).to be_true - expect(node.recipe?("nginx::other_module")).to be_true - end - end - - describe "when querying for recipes in the run list" do - context "when a recipe is in the top level run list" do - before do - node.run_list << "recipe[nginx::module]" - end - - it "finds the recipe" do - node.recipe?("nginx::module").should be_true - end - - it "does not find a recipe not in the run list" do - node.recipe?("nginx::other_module").should be_false - end - end - context "when a recipe is in the expanded run list only" do - before do - node.run_list << "role[base]" - node.automatic_attrs[:recipes] = [ "nginx::module" ] - end - - it "finds a recipe in the expanded run list" do - node.recipe?("nginx::module").should be_true - end - - it "does not find a recipe that's not in the run list" do - node.recipe?("nginx::other_module").should be_false - end - end - end - - describe "when clearing computed state at the beginning of a run" do - before do - node.default[:foo] = "default" - node.normal[:foo] = "normal" - node.override[:foo] = "override" - node.reset_defaults_and_overrides - end - - it "removes default attributes" do - node.default.should be_empty - end - - it "removes override attributes" do - node.override.should be_empty - end - - it "leaves normal level attributes untouched" do - node[:foo].should == "normal" - end - - end - - describe "when merging environment attributes" 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"}) - - - @environment = Chef::Environment.new - @environment.default_attributes = {:default => "from env", :d_env => "env only" } - @environment.override_attributes = {:override => "from env", :o_env => "env only"} - Chef::Environment.stub(:load).and_return(@environment) - node.apply_expansion_attributes(@expansion) - end - - it "does not nuke role-only default attrs" do - node[:d_role].should == "role only" - end - - it "does not nuke role-only override attrs" do - node[:o_role].should == "role only" - end - - it "does not nuke env-only default attrs" do - node[:o_env].should == "env only" - end - - it "does not nuke role-only override attrs" do - node[:o_env].should == "env only" - end - - it "gives role defaults precedence over env defaults" do - node[:default].should == "from role" - end - - it "gives env overrides precedence over role overrides" do - node[:override].should == "from env" - end - end - - describe "when evaluating attributes files" do - before do - @cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks")) - @cookbook_loader = Chef::CookbookLoader.new(@cookbook_repo) - @cookbook_loader.load_cookbooks - - @cookbook_collection = Chef::CookbookCollection.new(@cookbook_loader.cookbooks_by_name) - - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(node, @cookbook_collection, @events) - - node.include_attribute("openldap::default") - node.include_attribute("openldap::smokey") - end - - it "sets attributes from the files" do - node.ldap_server.should eql("ops1prod") - node.ldap_basedn.should eql("dc=hjksolutions,dc=com") - node.ldap_replication_password.should eql("forsure") - node.smokey.should eql("robinson") - end - - it "gives a sensible error when attempting to load a missing attributes file" do - lambda { node.include_attribute("nope-this::doesnt-exist") }.should raise_error(Chef::Exceptions::CookbookNotFound) - end - end - - describe "roles" do - it "should allow you to query whether or not it has a recipe applied with role?" do - node.run_list << "role[sunrise]" - node.role?("sunrise").should eql(true) - node.role?("not at home").should eql(false) - end - - it "should allow you to set roles with arguments" do - node.run_list << "role[one]" - node.run_list << "role[two]" - node.role?("one").should eql(true) - node.role?("two").should eql(true) - end - end - - describe "run_list" do - it "should have a Chef::RunList of recipes and roles that should be applied" do - node.run_list.should be_a_kind_of(Chef::RunList) - end - - it "should allow you to query the run list with arguments" do - node.run_list "recipe[baz]" - node.run_list?("recipe[baz]").should eql(true) - end - - it "should allow you to set the run list with arguments" do - node.run_list "recipe[baz]", "role[foo]" - node.run_list?("recipe[baz]").should eql(true) - node.run_list?("role[foo]").should eql(true) - end - end - - describe "from file" do - it "should load a node from a ruby file" do - node.from_file(File.expand_path(File.join(CHEF_SPEC_DATA, "nodes", "test.rb"))) - node.name.should eql("test.example.com-short") - node.sunshine.should eql("in") - node.something.should eql("else") - node.run_list.should == ["operations-master", "operations-monitoring"] - end - - it "should raise an exception if the file cannot be found or read" do - lambda { node.from_file("/tmp/monkeydiving") }.should raise_error(IOError) - end - end - - describe "update_from!" do - before(:each) do - node.name("orig") - node.chef_environment("dev") - node.default_attrs = { "one" => { "two" => "three", "four" => "five", "eight" => "nine" } } - node.override_attrs = { "one" => { "two" => "three", "four" => "six" } } - node.normal_attrs = { "one" => { "two" => "seven" } } - node.run_list << "role[marxist]" - node.run_list << "role[leninist]" - node.run_list << "recipe[stalinist]" - - @example = Chef::Node.new() - @example.name("newname") - @example.chef_environment("prod") - @example.default_attrs = { "alpha" => { "bravo" => "charlie", "delta" => "echo" } } - @example.override_attrs = { "alpha" => { "bravo" => "foxtrot", "delta" => "golf" } } - @example.normal_attrs = { "alpha" => { "bravo" => "hotel" } } - @example.run_list << "role[comedy]" - @example.run_list << "role[drama]" - @example.run_list << "recipe[mystery]" - end - - it "allows update of everything except name" do - node.update_from!(@example) - node.name.should == "orig" - node.chef_environment.should == @example.chef_environment - node.default_attrs.should == @example.default_attrs - node.override_attrs.should == @example.override_attrs - node.normal_attrs.should == @example.normal_attrs - node.run_list.should == @example.run_list - end - - it "should not update the name of the node" do - node.should_not_receive(:name).with(@example.name) - node.update_from!(@example) - end - end - - describe "to_hash" do - it "should serialize itself as a hash" do - node.chef_environment("dev") - node.default_attrs = { "one" => { "two" => "three", "four" => "five", "eight" => "nine" } } - node.override_attrs = { "one" => { "two" => "three", "four" => "six" } } - node.normal_attrs = { "one" => { "two" => "seven" } } - node.run_list << "role[marxist]" - node.run_list << "role[leninist]" - node.run_list << "recipe[stalinist]" - h = node.to_hash - h["one"]["two"].should == "three" - h["one"]["four"].should == "six" - h["one"]["eight"].should == "nine" - h["role"].should be_include("marxist") - h["role"].should be_include("leninist") - h["run_list"].should be_include("role[marxist]") - h["run_list"].should be_include("role[leninist]") - h["run_list"].should be_include("recipe[stalinist]") - h["chef_environment"].should == "dev" - end - end - - describe "converting to or from json" do - it "should serialize itself as json", :json => true do - node.from_file(File.expand_path("nodes/test.example.com.rb", CHEF_SPEC_DATA)) - json = Chef::JSONCompat.to_json(node) - json.should =~ /json_class/ - json.should =~ /name/ - json.should =~ /chef_environment/ - json.should =~ /normal/ - json.should =~ /default/ - json.should =~ /override/ - json.should =~ /run_list/ - end - - 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'} - json = Chef::JSONCompat.to_json(node) - json.should =~ /\"run_list\":\[\"role\[Cthulu\]\",\"role\[Hastur\]\"\]/ - end - - it "should serialize the correct run list", :json => true do - node.run_list << "role[marxist]" - node.run_list << "role[leninist]" - node.override_runlist << "role[stalinist]" - node.run_list.should be_include("role[stalinist]") - json = Chef::JSONCompat.to_json(node) - json.should =~ /\"run_list\":\[\"role\[marxist\]\",\"role\[leninist\]\"\]/ - end - - it "merges the override components into a combined override object" do - node.attributes.role_override["role override"] = "role override" - node.attributes.env_override["env override"] = "env override" - node_for_json = node.for_json - node_for_json["override"]["role override"].should == "role override" - node_for_json["override"]["env override"].should == "env override" - end - - it "merges the default components into a combined default object" do - node.attributes.role_default["role default"] = "role default" - node.attributes.env_default["env default"] = "env default" - node_for_json = node.for_json - node_for_json["default"]["role default"].should == "role default" - node_for_json["default"]["env default"].should == "env default" - end - - - 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.should be_a_kind_of(Chef::Node) - serialized_node.name.should eql(node.name) - serialized_node.chef_environment.should eql(node.chef_environment) - node.each_attribute do |k,v| - serialized_node[k].should eql(v) - end - serialized_node.run_list.should == node.run_list - end - end - - describe "to_s" do - it "should turn into a string like node[name]" do - node.name("airplane") - node.to_s.should eql("node[airplane]") - end - end - - describe "api model" do - before(:each) do - @rest = double("Chef::REST") - Chef::REST.stub(:new).and_return(@rest) - @query = double("Chef::Search::Query") - Chef::Search::Query.stub(:new).and_return(@query) - end - - describe "list" do - describe "inflated" do - it "should return a hash of node names and objects" do - n1 = double("Chef::Node", :name => "one") - @query.should_receive(:search).with(:node).and_yield(n1) - r = Chef::Node.list(true) - r["one"].should == n1 - end - end - - it "should return a hash of node names and urls" do - @rest.should_receive(:get_rest).and_return({ "one" => "http://foo" }) - r = Chef::Node.list - r["one"].should == "http://foo" - end - end - - describe "load" do - it "should load a node by name" do - @rest.should_receive(:get_rest).with("nodes/monkey").and_return("foo") - Chef::Node.load("monkey").should == "foo" - end - end - - describe "destroy" do - it "should destroy a node" do - @rest.should_receive(:delete_rest).with("nodes/monkey").and_return("foo") - node.name("monkey") - node.destroy - end - end - - describe "save" do - it "should update a node if it already exists" do - node.name("monkey") - node.stub(:data_for_save).and_return({}) - @rest.should_receive(:put_rest).with("nodes/monkey", {}).and_return("foo") - node.save - end - - it "should not try and create if it can update" do - node.name("monkey") - node.stub(:data_for_save).and_return({}) - @rest.should_receive(:put_rest).with("nodes/monkey", {}).and_return("foo") - @rest.should_not_receive(:post_rest) - node.save - end - - it "should create if it cannot update" do - node.name("monkey") - node.stub(:data_for_save).and_return({}) - exception = double("404 error", :code => "404") - @rest.should_receive(:put_rest).and_raise(Net::HTTPServerException.new("foo", exception)) - @rest.should_receive(:post_rest).with("nodes", {}) - node.save - end - - describe "when whyrun mode is enabled" do - before do - Chef::Config[:why_run] = true - end - after do - Chef::Config[:why_run] = false - end - it "should not save" do - node.name("monkey") - @rest.should_not_receive(:put_rest) - @rest.should_not_receive(:post_rest) - node.save - end - end - - context "with whitelisted attributes configured" do - it "should only save whitelisted attributes (and subattributes)" do - Chef::Config[:automatic_attribute_whitelist] = [ - ["filesystem", "/dev/disk0s2"], - "network/interfaces/eth0" - ] - - data = { - "automatic" => { - "filesystem" => { - "/dev/disk0s2" => { "size" => "10mb" }, - "map - autohome" => { "size" => "10mb" } - }, - "network" => { - "interfaces" => { - "eth0" => {}, - "eth1" => {} - } - } - }, - "default" => {}, "normal" => {}, "override" => {} - } - - selected_data = { - "automatic" => { - "filesystem" => { - "/dev/disk0s2" => { "size" => "10mb" } - }, - "network" => { - "interfaces" => { - "eth0" => {} - } - } - }, - "default" => {}, "normal" => {}, "override" => {} - } - - node.name("picky-monkey") - node.stub(:for_json).and_return(data) - @rest.should_receive(:put_rest).with("nodes/picky-monkey", selected_data).and_return("foo") - node.save - end - - it "should not save any attributes if the whitelist is empty" do - Chef::Config[:automatic_attribute_whitelist] = [] - - data = { - "automatic" => { - "filesystem" => { - "/dev/disk0s2" => { "size" => "10mb" }, - "map - autohome" => { "size" => "10mb" } - } - }, - "default" => {}, "normal" => {}, "override" => {} - } - - selected_data = { - "automatic" => {}, "default" => {}, "normal" => {}, "override" => {} - } - - node.name("picky-monkey") - node.stub(:for_json).and_return(data) - @rest.should_receive(:put_rest).with("nodes/picky-monkey", selected_data).and_return("foo") - node.save - end - end - end - end - -end diff --git a/spec/unit/platform/query_helpers_spec.rb b/spec/unit/platform/query_helpers_spec.rb deleted file mode 100644 index 6adea5eecf..0000000000 --- a/spec/unit/platform/query_helpers_spec.rb +++ /dev/null @@ -1,55 +0,0 @@ -# -# Author:: Bryan McLellan <btm@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 'spec_helper' - -describe "Chef::Platform#windows_server_2003?" do - it "returns false early when not on windows" do - Chef::Platform.stub(:windows?).and_return(false) - expect(Chef::Platform).not_to receive(:require) - expect(Chef::Platform.windows_server_2003?).to be_false - end - - # CHEF-4888: Need to call WIN32OLE.ole_initialize in new threads - it "does not raise an exception" do - expect { Thread.fork { Chef::Platform.windows_server_2003? }.join }.not_to raise_error - end -end - -describe 'Chef::Platform#supports_dsc?' do - it 'returns false if powershell is not present' do - node = Chef::Node.new - Chef::Platform.supports_dsc?(node).should be_false - end - - ['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 - Chef::Platform.supports_dsc?(node).should be_false - end - end - - ['4.0', '5.0'].each do |version| - it "returns true for Powershell #{version}" do - node = Chef::Node.new - node.automatic[:languages][:powershell][:version] = version - Chef::Platform.supports_dsc?(node).should be_true - end - end -end diff --git a/spec/unit/platform_spec.rb b/spec/unit/platform_spec.rb deleted file mode 100644 index 029fc29aae..0000000000 --- a/spec/unit/platform_spec.rb +++ /dev/null @@ -1,283 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe "Chef::Platform supports" do - [ - :mac_os_x, - :mac_os_x_server, - :freebsd, - :ubuntu, - :debian, - :centos, - :fedora, - :suse, - :opensuse, - :redhat, - :oracle, - :gentoo, - :arch, - :solaris, - :mswin, - :mingw32, - :windows, - :gcel, - :ibm_powerkvm - ].each do |platform| - it "#{platform}" do - Chef::Platform.platforms.should have_key(platform) - end - end -end - -describe Chef::Platform do - - context "while testing with fake data" do - - before :all do - @original_platform_map = Chef::Platform.platforms - end - - after :all do || - Chef::Platform.platforms = @original_platform_map - end - - before(:each) do - Chef::Platform.platforms = { - :darwin => { - ">= 10.11" => { - :file => "new_darwinian" - }, - "9.2.2" => { - :file => "darwinian", - :else => "thing" - }, - :default => { - :file => "old school", - :snicker => "snack" - } - }, - :mars_volta => { - }, - :default => { - :file => Chef::Provider::File, - :pax => "brittania", - :cat => "nice" - } - } - @events = Chef::EventDispatch::Dispatcher.new - end - - it "should allow you to look up a platform by name and version, returning the provider map for it" do - pmap = Chef::Platform.find("Darwin", "9.2.2") - pmap.should be_a_kind_of(Hash) - pmap[:file].should eql("darwinian") - end - - it "should allow you to look up a platform by name and version using \"greater than\" style operators" do - pmap = Chef::Platform.find("Darwin", "11.1.0") - pmap.should be_a_kind_of(Hash) - pmap[:file].should eql("new_darwinian") - end - - it "should use the default providers for an os if the specific version does not exist" do - pmap = Chef::Platform.find("Darwin", "1") - pmap.should be_a_kind_of(Hash) - pmap[:file].should eql("old school") - end - - it "should use the default providers if the os doesn't give me a default, but does exist" do - pmap = Chef::Platform.find("mars_volta", "1") - pmap.should be_a_kind_of(Hash) - pmap[:file].should eql(Chef::Provider::File) - end - - it "should use the default provider if the os does not exist" do - pmap = Chef::Platform.find("AIX", "1") - pmap.should be_a_kind_of(Hash) - pmap[:file].should eql(Chef::Provider::File) - end - - it "should merge the defaults for an os with the specific version" do - pmap = Chef::Platform.find("Darwin", "9.2.2") - pmap[:file].should eql("darwinian") - pmap[:snicker].should eql("snack") - end - - it "should merge the defaults for an os with the universal defaults" do - pmap = Chef::Platform.find("Darwin", "9.2.2") - pmap[:file].should eql("darwinian") - pmap[:pax].should eql("brittania") - end - - it "should allow you to look up a provider for a platform directly by symbol" do - Chef::Platform.find_provider("Darwin", "9.2.2", :file).should eql("darwinian") - end - - it "should raise an exception if a provider cannot be found for a resource type" do - lambda { Chef::Platform.find_provider("Darwin", "9.2.2", :coffee) }.should raise_error(ArgumentError) - end - - it "should look up a provider for a resource with a Chef::Resource object" do - kitty = Chef::Resource::Cat.new("loulou") - Chef::Platform.find_provider("Darwin", "9.2.2", kitty).should eql("nice") - end - - it "should look up a provider with a node and a Chef::Resource object" do - kitty = Chef::Resource::Cat.new("loulou") - node = Chef::Node.new - node.name("Intel") - node.automatic_attrs[:platform] = "mac_os_x" - node.automatic_attrs[:platform_version] = "9.2.2" - Chef::Platform.find_provider_for_node(node, kitty).should eql("nice") - end - - it "should not throw an exception when the platform version has an unknown format" do - Chef::Platform.find_provider(:darwin, "bad-version", :file).should eql("old school") - end - - it "should prefer an explicit provider" do - kitty = Chef::Resource::Cat.new("loulou") - kitty.stub(:provider).and_return(Chef::Provider::File) - node = Chef::Node.new - node.name("Intel") - node.automatic_attrs[:platform] = "mac_os_x" - node.automatic_attrs[:platform_version] = "9.2.2" - Chef::Platform.find_provider_for_node(node, kitty).should eql(Chef::Provider::File) - end - - it "should look up a provider based on the resource name if nothing else matches" do - kitty = Chef::Resource::Cat.new("loulou") - class Chef::Provider::Cat < Chef::Provider; end - Chef::Platform.platforms[:default].delete(:cat) - node = Chef::Node.new - node.name("Intel") - node.automatic_attrs[:platform] = "mac_os_x" - node.automatic_attrs[:platform_version] = "8.5" - Chef::Platform.find_provider_for_node(node, kitty).should eql(Chef::Provider::Cat) - end - - def setup_file_resource - node = Chef::Node.new - node.automatic_attrs[:platform] = "mac_os_x" - node.automatic_attrs[:platform_version] = "9.2.2" - run_context = Chef::RunContext.new(node, {}, @events) - [ Chef::Resource::File.new("whateva", run_context), run_context ] - end - - it "returns a provider object given a Chef::Resource object which has a valid run context and an action" do - file, run_context = setup_file_resource - provider = Chef::Platform.provider_for_resource(file, :foo) - provider.should be_an_instance_of(Chef::Provider::File) - provider.new_resource.should equal(file) - provider.run_context.should equal(run_context) - end - - it "returns a provider object given a Chef::Resource object which has a valid run context without an action" do - file, run_context = setup_file_resource - provider = Chef::Platform.provider_for_resource(file) - provider.should be_an_instance_of(Chef::Provider::File) - provider.new_resource.should equal(file) - provider.run_context.should equal(run_context) - end - - it "raises an error when trying to find the provider for a resource with no run context" do - file = Chef::Resource::File.new("whateva") - lambda {Chef::Platform.provider_for_resource(file)}.should raise_error(ArgumentError) - end - - it "does not support finding a provider by resource and node -- a run context is required" do - lambda {Chef::Platform.provider_for_node('node', 'resource')}.should raise_error(NotImplementedError) - end - - it "should update the provider map with map" do - Chef::Platform.set( - :platform => :darwin, - :version => "9.2.2", - :resource => :file, - :provider => "masterful" - ) - Chef::Platform.platforms[:darwin]["9.2.2"][:file].should eql("masterful") - Chef::Platform.set( - :platform => :darwin, - :resource => :file, - :provider => "masterful" - ) - Chef::Platform.platforms[:darwin][:default][:file].should eql("masterful") - Chef::Platform.set( - :resource => :file, - :provider => "masterful" - ) - Chef::Platform.platforms[:default][:file].should eql("masterful") - - Chef::Platform.set( - :platform => :hero, - :version => "9.2.2", - :resource => :file, - :provider => "masterful" - ) - Chef::Platform.platforms[:hero]["9.2.2"][:file].should eql("masterful") - - Chef::Platform.set( - :resource => :file, - :provider => "masterful" - ) - Chef::Platform.platforms[:default][:file].should eql("masterful") - - Chef::Platform.platforms = {} - - Chef::Platform.set( - :resource => :file, - :provider => "masterful" - ) - Chef::Platform.platforms[:default][:file].should eql("masterful") - - Chef::Platform.platforms = { :neurosis => {} } - Chef::Platform.set(:platform => :neurosis, :resource => :package, :provider => "masterful") - Chef::Platform.platforms[:neurosis][:default][:package].should eql("masterful") - - end - - it "does not overwrite the platform map when using :default platform" do - Chef::Platform.set( - :resource => :file, - :platform => :default, - :provider => "new school" - ) - Chef::Platform.platforms[:default][:file].should eql("new school") - Chef::Platform.platforms[:default][:cat].should eql("nice") - end - - 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") - pmap[:package].should eql(Chef::Provider::Package::Solaris) - end - - it "should use the IPS package provider on Solaris 11" do - pmap = Chef::Platform.find("Solaris2", "5.11") - pmap[:package].should eql(Chef::Provider::Package::Ips) - 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 deleted file mode 100644 index a1e0b881d5..0000000000 --- a/spec/unit/policy_builder/expand_node_object_spec.rb +++ /dev/null @@ -1,336 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@getchef.com>) -# Copyright:: Copyright 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 '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(: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) } - - # All methods that Chef::Client calls on this class. - describe "Public API" do - it "implements a node method" do - expect(policy_builder).to respond_to(:node) - end - - it "implements a load_node method" do - expect(policy_builder).to respond_to(:load_node) - end - - it "implements a build_node method" do - expect(policy_builder).to respond_to(:build_node) - end - - it "implements a setup_run_context method that accepts a list of recipe files to run" do - expect(policy_builder).to respond_to(:setup_run_context) - expect(policy_builder.method(:setup_run_context).arity).to eq(-1) #optional argument - end - - it "implements a run_context method" do - expect(policy_builder).to respond_to(:run_context) - end - - it "implements an expand_run_list method" do - expect(policy_builder).to respond_to(:expand_run_list) - end - - it "implements a sync_cookbooks method" do - expect(policy_builder).to respond_to(:sync_cookbooks) - end - - it "implements a temporary_policy? method" 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 - policy_builder.node.name.should == 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 - Chef::Node.should_receive(:find_or_create).with(node_name).and_return(node) - policy_builder.load_node - policy_builder.node.should == node - end - - end - end - - describe "building the node" do - - # 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 - pending - end - - end - - end - - # Implementation specific tests - - describe "when first created" do - - it "has a node_name" do - expect(policy_builder.node_name).to eq(node_name) - end - - it "has ohai data" do - expect(policy_builder.ohai_data).to eq(ohai_data) - end - - it "has a set of attributes from command line option" do - expect(policy_builder.json_attribs).to eq(json_attribs) - end - - it "has an override_runlist" do - expect(policy_builder.override_runlist).to eq(override_runlist) - 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 - Chef::Node.should_receive(:find_or_create).with(node_name).and_return(node) - policy_builder.load_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) - expect(policy_builder.run_list_expansion.recipes).to eq(["a::default", "b::server"]) - end - - end - - describe "building the node" do - - let(:configured_environment) { nil } - let(:json_attribs) { nil } - - 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(:node) do - node = Chef::Node.new - node.name(node_name) - node.default_attrs = original_default_attrs - node.override_attrs = original_override_attrs - node.run_list(primary_runlist) - node - end - - before do - Chef::Config[:environment] = configured_environment - Chef::Node.should_receive(:find_or_create).with(node_name).and_return(node) - policy_builder.load_node - policy_builder.build_node - end - - it "sanity checks test setup" do - expect(node.run_list).to eq(primary_runlist) - end - - it "clears existing default and override attributes from the node" do - expect(node["default_key"]).to be_nil - expect(node["override_key"]).to be_nil - end - - it "applies ohai data to the node" do - expect(node["fqdn"]).to eq(ohai_data["fqdn"]) - end - - it "reports that a temporary_policy is not being used" do - expect(policy_builder.temporary_policy?).to be_false - end - - describe "when the given run list is not in expanded form" do - - # NOTE: for chef-client, the behavior is always to expand the run list, - # but this operation is a no-op when none of the run list items are - # roles. Because of the amount of mocking required to make this work in - # tests, this test is isolated from the others. - - let(:primary_runlist) { ["role[some_role]"] } - let(:expansion) do - recipe_list = Chef::RunList::VersionedRecipeList.new - recipe_list.add_recipe("recipe[from_role::default", "1.0.2") - double("RunListExpansion", :recipes => recipe_list) - end - - let(:node) do - node = Chef::Node.new - node.name(node_name) - node.default_attrs = original_default_attrs - node.override_attrs = original_override_attrs - node.run_list(primary_runlist) - - node.should_receive(:expand!).with("server") do - node.run_list("recipe[from_role::default]") - expansion - end - - node - end - - it "expands run list items via the server API" do - expect(node.run_list).to eq(["recipe[from_role::default]"]) - end - - end - - 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" } } - - it "sets the run list according to the given JSON" do - expect(node.run_list).to eq(["recipe[json_attribs::default]"]) - end - - it "sets node attributes according to the given JSON" do - expect(node["json_attribs_key"]).to eq("json_attribs_value") - end - - end - - context "when an override_runlist is given" do - - let(:override_runlist) { "recipe[foo::default]" } - - it "sets the override run_list on the node" do - expect(node.run_list).to eq([override_runlist]) - expect(node.primary_runlist).to eq(primary_runlist) - end - - it "reports that a temporary policy is being used" do - expect(policy_builder.temporary_policy?).to be_true - end - - end - - context "when no environment is specified" do - - it "does not set the environment" do - expect(node.chef_environment).to eq("_default") - end - - end - - context "when a custom environment is configured" do - - let(:configured_environment) { environment.name } - - let(:environment) do - environment = Chef::Environment.new.tap {|e| e.name("prod") } - Chef::Environment.should_receive(:load).with("prod").and_return(environment) - environment - end - - it "sets the environment as configured" do - expect(node.chef_environment).to eq(environment.name) - end - end - - end - - describe "configuring the run_context" do - let(:json_attribs) { nil } - let(:override_runlist) { nil } - - let(:node) do - node = Chef::Node.new - node.name(node_name) - node.run_list("recipe[first::default]", "recipe[second::default]") - node - end - - let(:chef_http) { double("Chef::REST") } - - let(:cookbook_resolve_url) { "environments/#{node.chef_environment}/cookbook_versions" } - 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_synchronizer) { double("CookbookSynchronizer") } - - before do - Chef::Node.should_receive(:find_or_create).with(node_name).and_return(node) - - policy_builder.stub(:api_service).and_return(chef_http) - - policy_builder.load_node - policy_builder.build_node - - run_list_expansion = policy_builder.run_list_expansion - - chef_http.should_receive(:post).with(cookbook_resolve_url, cookbook_resolve_post_data).and_return(cookbook_hash) - Chef::CookbookSynchronizer.should_receive(:new).with(cookbook_hash, events).and_return(cookbook_synchronizer) - cookbook_synchronizer.should_receive(:sync_cookbooks) - - Chef::RunContext.any_instance.should_receive(:load).with(run_list_expansion) - - policy_builder.setup_run_context - end - - it "configures FileVendor to fetch files remotely" do - manifest = double("cookbook manifest") - Chef::Cookbook::RemoteFileVendor.should_receive(:new).with(manifest, chef_http) - Chef::Cookbook::FileVendor.create_from_manifest(manifest) - end - - it "triggers cookbook compilation in the run_context" do - # Test condition already covered by `Chef::RunContext.any_instance.should_receive(:load).with(run_list_expansion)` - end - - end - -end - diff --git a/spec/unit/policy_builder/policyfile_spec.rb b/spec/unit/policy_builder/policyfile_spec.rb deleted file mode 100644 index f02c79ef12..0000000000 --- a/spec/unit/policy_builder/policyfile_spec.rb +++ /dev/null @@ -1,403 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@getchef.com>) -# Copyright:: Copyright 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 '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(: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) } - - # Convert a SHA1 (160 bit) hex string into an x.y.z version number where the - # maximum value is smaller than a postgres BIGINT (signed 64bit, so 63 usable - # bits). This requires enterprise Chef or open source server 11.1.0+ (currently not released) - # - # The SHA1 is devided as follows: - # * "major": first 14 chars (56 bits) - # * "minor": next 14 chars (56 bits) - # * "patch": last 12 chars (48 bits) - def id_to_dotted(sha1_id) - 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.join(".") - end - - - let(:example1_lock_data) do - # based on https://github.com/danielsdeleo/chef-workflow2-prototype/blob/master/skeletons/basic_policy/Policyfile.lock.json - { - "identifier" => "168d2102fb11c9617cd8a981166c8adc30a6e915", - "version" => "2.3.5", - # 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 - } - } - end - - let(:example2_lock_data) do - { - "identifier" => "feab40e1fca77c7360ccca1481bb8ba5f919ce3a", - "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" } - } - end - - 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 - { - "run_list" => policyfile_run_list, - - "cookbook_locks" => { - "example1" => example1_lock_data, - "example2" => example2_lock_data - }, - - "default_attributes" => policyfile_default_attributes, - "override_attributes" => policyfile_override_attributes - } - end - - let(:err_namespace) { Chef::PolicyBuilder::Policyfile } - - it "configures a Chef HTTP API client" do - http = double("Chef::REST") - server_url = "https://api.opscode.com/organizations/example" - Chef::Config[:chef_server_url] = server_url - Chef::REST.should_receive(:new).with(server_url).and_return(http) - expect(policy_builder.http_api).to eq(http) - end - - describe "reporting unsupported features" do - - def initialize_pb - Chef::PolicyBuilder::Policyfile.new(node_name, ohai_data, json_attribs, override_runlist, events) - end - - it "always gives `false` for #temporary_policy?" do - expect(initialize_pb.temporary_policy?).to be_false - end - - context "chef-solo" do - before { Chef::Config[:solo] = true } - - it "errors on create" do - expect { initialize_pb }.to raise_error(err_namespace::UnsupportedFeature) - end - end - - context "when given an override run_list" do - let(:override_runlist) { "recipe[foo],recipe[bar]" } - - it "errors on create" do - expect { initialize_pb }.to raise_error(err_namespace::UnsupportedFeature) - end - end - - context "when json_attribs contains a run_list" do - let(:json_attribs) { {"run_list" => []} } - - it "errors on create" do - expect { initialize_pb }.to raise_error(err_namespace::UnsupportedFeature) - end - end - - context "when an environment is configured" do - before { Chef::Config[:environment] = "blurch" } - - it "errors when an environment is configured" do - expect { initialize_pb }.to raise_error(err_namespace::UnsupportedFeature) - end - end - - end - - describe "when using compatibility mode" do - - let(:http_api) { double("Chef::REST") } - - 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(:node) do - node = Chef::Node.new - node.name(node_name) - node.default_attrs = original_default_attrs - node.override_attrs = original_override_attrs - node.run_list(primary_runlist) if primary_runlist - node - end - - before do - # TODO: agree on this name and logic. - Chef::Config[:deployment_group] = "example-policy-stage" - policy_builder.stub(:http_api).and_return(http_api) - end - - context "when the deployment group cannot be loaded" do - let(:error404) { Net::HTTPServerException.new("404 message", :body) } - - before do - Chef::Node.should_receive(:find_or_create).with(node_name).and_return(node) - http_api.should_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 - events.should_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) - end - - end - - describe "when the deployment_group is not configured" do - before do - Chef::Config[:deployment_group] = nil - Chef::Node.should_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) - 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 - events.should_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 "and a deployment_group is configured" do - before do - http_api.should_receive(:get).with("data/policyfiles/example-policy-stage").and_return(parsed_policyfile_json) - end - - it "fetches the policy file from a data bag item" do - expect(policy_builder.policy).to eq(parsed_policyfile_json) - end - - it "extracts the run_list from the policyfile" do - expect(policy_builder.run_list).to eq(policyfile_run_list) - end - - it "extracts the cookbooks and versions for display from the policyfile" do - expected = [ - "example1::default@2.3.5 (168d210)", - "example2::server@4.2.0 (feab40e)" - ] - - expect(policy_builder.run_list_with_versions_for_display).to eq(expected) - end - - it "generates a RunListExpansion-alike object for feeding to the CookbookCompiler" do - expect(policy_builder.run_list_expansion_ish).to respond_to(:recipes) - expect(policy_builder.run_list_expansion_ish.recipes).to eq(["example1::default", "example2::server"]) - end - - it "implements #expand_run_list in a manner compatible with ExpandNodeObject" do - Chef::Node.should_receive(:find_or_create).with(node_name).and_return(node) - policy_builder.load_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 - parsed_policyfile_json["run_list"] = ["role[foo]"] - expect { policy_builder.validate_policyfile }.to raise_error(err_namespace::PolicyfileError) - end - - it "errors if the policyfile json contains non-fully qualified recipe items" do - parsed_policyfile_json["run_list"] = ["recipe[foo]"] - expect { policy_builder.validate_policyfile }.to raise_error(err_namespace::PolicyfileError) - end - - it "errors if the policyfile doesn't have a run_list key" do - parsed_policyfile_json.delete("run_list") - expect { policy_builder.validate_policyfile }.to raise_error(err_namespace::PolicyfileError) - end - - it "error if the policyfile doesn't have a cookbook_locks key" do - parsed_policyfile_json.delete("cookbook_locks") - expect { policy_builder.validate_policyfile }.to raise_error(err_namespace::PolicyfileError) - end - - it "accepts a valid policyfile" do - policy_builder.validate_policyfile - end - - end - - describe "building the node object" do - - before do - Chef::Node.should_receive(:find_or_create).with(node_name).and_return(node) - - policy_builder.load_node - policy_builder.build_node - 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) - end - end - - it "applies attributes from json file" do - expect(node["custom_attr"]).to eq("custom_attr_value") - 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 "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 - - - describe "fetching the desired cookbook set" do - - let(:example1_cookbook_object) { double("Chef::CookbookVersion for example1 cookbook") } - let(:example2_cookbook_object) { double("Chef::CookbookVersion for example2 cookbook") } - - let(:expected_cookbook_hash) do - { "example1" => example1_cookbook_object, "example2" => example2_cookbook_object } - end - - let(:example1_xyz_version) { example1_lock_data["dotted_decimal_identifier"] } - let(:example2_xyz_version) { example2_lock_data["dotted_decimal_identifier"] } - - let(:cookbook_synchronizer) { double("Chef::CookbookSynchronizer") } - - context "and a cookbook is missing" do - - let(:error404) { Net::HTTPServerException.new("404 message", :body) } - - before do - Chef::Node.should_receive(:find_or_create).with(node_name).and_return(node) - - # Remove references to example2 cookbook because we're iterating - # over a Hash data structure and on ruby 1.8.7 iteration order will - # not be stable. - parsed_policyfile_json["cookbook_locks"].delete("example2") - parsed_policyfile_json["run_list"].delete("recipe[example2::server]") - - policy_builder.load_node - policy_builder.build_node - - http_api.should_receive(:get).with("cookbooks/example1/#{example1_xyz_version}"). - and_raise(error404) - end - - it "raises an error indicating which cookbook is missing" do - expect { policy_builder.cookbooks_to_sync }.to raise_error(Chef::Exceptions::CookbookNotFound) - end - - end - - context "and the cookbooks can be fetched" do - before do - Chef::Node.should_receive(:find_or_create).with(node_name).and_return(node) - - policy_builder.load_node - policy_builder.build_node - - http_api.should_receive(:get).with("cookbooks/example1/#{example1_xyz_version}"). - and_return(example1_cookbook_object) - http_api.should_receive(:get).with("cookbooks/example2/#{example2_xyz_version}"). - and_return(example2_cookbook_object) - - Chef::CookbookSynchronizer.stub(:new). - with(expected_cookbook_hash, events). - and_return(cookbook_synchronizer) - 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 - - it "syncs the desired cookbooks via CookbookSynchronizer" do - cookbook_synchronizer.should_receive(:sync_cookbooks) - policy_builder.sync_cookbooks - end - - it "builds a run context" do - cookbook_synchronizer.should_receive(:sync_cookbooks) - Chef::RunContext.any_instance.should_receive(:load).with(policy_builder.run_list_expansion_ish) - 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 - - end - end - end - - end - -end diff --git a/spec/unit/policy_builder_spec.rb b/spec/unit/policy_builder_spec.rb deleted file mode 100644 index 506911452c..0000000000 --- a/spec/unit/policy_builder_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@getchef.com>) -# Copyright:: Copyright 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 'chef/policy_builder' - -describe Chef::PolicyBuilder do - - # TODO: test the strategy method - -end diff --git a/spec/unit/provider/breakpoint_spec.rb b/spec/unit/provider/breakpoint_spec.rb deleted file mode 100644 index 05f3e8e0ed..0000000000 --- a/spec/unit/provider/breakpoint_spec.rb +++ /dev/null @@ -1,54 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@kallistec.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' -describe Chef::Provider::Breakpoint do - - before do - @resource = Chef::Resource::Breakpoint.new - @node = Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - @collection = double("resource collection") - @run_context.stub(:resource_collection).and_return(@collection) - @provider = Chef::Provider::Breakpoint.new(@resource, @run_context) - end - - it "responds to load_current_resource" do - @provider.should respond_to(:load_current_resource) - end - - it "gets the iterator from @collection and pauses it" do - Shell.stub(:running?).and_return(true) - @iterator = double("stepable_iterator") - @collection.stub(:iterator).and_return(@iterator) - @iterator.should_receive(:pause) - @provider.action_break - @resource.should be_updated - end - - it "doesn't pause the iterator if chef-shell isn't running" do - Shell.stub(:running?).and_return(false) - @iterator = double("stepable_iterator") - @collection.stub(:iterator).and_return(@iterator) - @iterator.should_not_receive(:pause) - @provider.action_break - end - -end diff --git a/spec/unit/provider/cookbook_file/content_spec.rb b/spec/unit/provider/cookbook_file/content_spec.rb deleted file mode 100644 index ed8942aaf2..0000000000 --- a/spec/unit/provider/cookbook_file/content_spec.rb +++ /dev/null @@ -1,40 +0,0 @@ -# -# Author:: Lamont Granquist (<lamont@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::CookbookFile::Content do - - 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)') - 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 - new_resource.stub(:cookbook).and_return('nginx') - content.send(:resource_cookbook).should == 'nginx' - end - - it "falls back to the implicit cookbook name on the resource" do - content.send(:resource_cookbook).should == 'apache2' - end - -end - diff --git a/spec/unit/provider/cookbook_file_spec.rb b/spec/unit/provider/cookbook_file_spec.rb deleted file mode 100644 index 131fca2ba6..0000000000 --- a/spec/unit/provider/cookbook_file_spec.rb +++ /dev/null @@ -1,58 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@opscode.com>) -# Author:: Lamont Granquist (<lamont@opscode.com>) -# Copyright:: Copyright (c) 2009-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' -require 'ostruct' - -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(:enclosing_directory) { - canonicalize_path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates"))) - } - let(:resource_path) { - canonicalize_path(File.expand_path(File.join(enclosing_directory, "seattle.txt"))) - } - - # Subject - - let(:provider) do - provider = described_class.new(resource, run_context) - provider.stub(:content).and_return(content) - provider - end - - let(:resource) do - resource = Chef::Resource::CookbookFile.new("seattle", @run_context) - resource.path(resource_path) - resource.cookbook_name = 'apache2' - resource - end - - let(:content) do - content = double('Chef::Provider::CookbookFile::Content') - end - - it_behaves_like Chef::Provider::File - - it_behaves_like "a file provider with source field" -end diff --git a/spec/unit/provider/cron/unix_spec.rb b/spec/unit/provider/cron/unix_spec.rb deleted file mode 100644 index 60e09baceb..0000000000 --- a/spec/unit/provider/cron/unix_spec.rb +++ /dev/null @@ -1,121 +0,0 @@ -# -# Author:: Bryan McLellan (btm@loftninjas.org) -# Author:: Toomas Pelberg (toomasp@gmx.net) -# Copyright:: Copyright (c) 2009 Bryan McLellan -# Copyright:: Copyright (c) 2010 Toomas Pelberg -# 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::Cron::Unix do - before do - @node = Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - @new_resource = Chef::Resource::Cron.new("cronhole some stuff") - @new_resource.user "root" - @new_resource.minute "30" - @new_resource.command "/bin/true" - - @provider = Chef::Provider::Cron::Unix.new(@new_resource, @run_context) - end - - it "should inherit from Chef::Provider:Cron" do - @provider.should be_a(Chef::Provider::Cron) - end - - describe "read_crontab" do - before :each do - @status = double("Status", :exitstatus => 0) - @stdout = StringIO.new(<<-CRONTAB) -0 2 * * * /some/other/command - -# Chef Name: something else -* 5 * * * /bin/true - -# Another comment - CRONTAB - @provider.stub(:popen4).and_yield(1234, StringIO.new, @stdout, StringIO.new).and_return(@status) - end - - it "should call crontab -l with the user" do - @provider.should_receive(:popen4).with("crontab -l #{@new_resource.user}").and_return(@status) - @provider.send(:read_crontab) - end - - it "should return the contents of the crontab" do - crontab = @provider.send(:read_crontab) - crontab.should == <<-CRONTAB -0 2 * * * /some/other/command - -# Chef Name: something else -* 5 * * * /bin/true - -# Another comment -CRONTAB - end - - it "should return nil if the user has no crontab" do - status = double("Status", :exitstatus => 1) - @provider.stub(:popen4).and_return(status) - @provider.send(:read_crontab).should == nil - end - - it "should raise an exception if another error occurs" do - status = double("Status", :exitstatus => 2) - @provider.stub(:popen4).and_return(status) - lambda do - @provider.send(:read_crontab) - end.should raise_error(Chef::Exceptions::Cron, "Error determining state of #{@new_resource.name}, exit: 2") - end - end - - describe "write_crontab" do - before :each do - @status = double("Status", :exitstatus => 0) - @provider.stub(:run_command_and_return_stdout_stderr).and_return(@status, String.new, String.new) - @tempfile = double("foo", :path => "/tmp/foo", :close => true) - Tempfile.stub(:new).and_return(@tempfile) - @tempfile.should_receive(:flush) - @tempfile.should_receive(:chmod).with(420) - @tempfile.should_receive(:close!) - end - - it "should call crontab for the user" do - @provider.should_receive(:run_command_and_return_stdout_stderr).with(hash_including(:user => @new_resource.user)) - @tempfile.should_receive(:<<).with("Foo") - @provider.send(:write_crontab, "Foo") - end - - it "should call crontab with a file containing the crontab" do - @provider.should_receive(:run_command_and_return_stdout_stderr) do |args| - (args[:command] =~ %r{\A/usr/bin/crontab (/\S+)\z}).should be_true - $1.should == "/tmp/foo" - @status - end - @tempfile.should_receive(:<<).with("Foo\n# wibble\n wah!!") - @provider.send(:write_crontab, "Foo\n# wibble\n wah!!") - end - - it "should raise an exception if the command returns non-zero" do - @tempfile.should_receive(:<<).with("Foo") - @status.stub(:exitstatus).and_return(1) - lambda do - @provider.send(:write_crontab, "Foo") - end.should raise_error(Chef::Exceptions::Cron, /Error updating state of #{@new_resource.name}, exit: 1/) - end - end -end diff --git a/spec/unit/provider/cron_spec.rb b/spec/unit/provider/cron_spec.rb deleted file mode 100644 index 460fb0ca6a..0000000000 --- a/spec/unit/provider/cron_spec.rb +++ /dev/null @@ -1,1010 +0,0 @@ -# -# Author:: Bryan McLellan (btm@loftninjas.org) -# Copyright:: Copyright (c) 2009 Bryan McLellan -# 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::Cron do - describe "when with special time string" do - before do - @node = Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - - @new_resource = Chef::Resource::Cron.new("cronhole some stuff", @run_context) - @new_resource.user "root" - @new_resource.minute "30" - @new_resource.command "/bin/true" - @new_resource.time :reboot - @provider = Chef::Provider::Cron.new(@new_resource, @run_context) - end - - context "with a matching entry in the user's crontab" do - before :each do - @provider.stub(:read_crontab).and_return(<<-CRONTAB) -0 2 * * * /some/other/command - -# Chef Name: cronhole some stuff -@reboot /bin/true param1 param2 -# Chef Name: something else -2 * 1 * * /bin/false - -# Another comment -CRONTAB - end - - it "should set cron_exists" do - @provider.load_current_resource - @provider.cron_exists.should == true - @provider.cron_empty.should == false - end - - it "should pull the details out of the cron line" do - cron = @provider.load_current_resource - cron.time.should == :reboot - cron.command.should == '/bin/true param1 param2' - end - - it "should pull env vars out" do - @provider.stub(:read_crontab).and_return(<<-CRONTAB) -0 2 * * * /some/other/command - -# Chef Name: cronhole some stuff -MAILTO=foo@example.com -SHELL=/bin/foosh -PATH=/bin:/foo -HOME=/home/foo -@reboot /bin/true param1 param2 -# Chef Name: something else -2 * 1 * * /bin/false - -# Another comment -CRONTAB - cron = @provider.load_current_resource - cron.mailto.should == 'foo@example.com' - cron.shell.should == '/bin/foosh' - cron.path.should == '/bin:/foo' - cron.home.should == '/home/foo' - cron.time.should == :reboot - cron.command.should == '/bin/true param1 param2' - end - - it "should parse and load generic and standard environment variables from cron entry" do - @provider.stub(:read_crontab).and_return(<<-CRONTAB) -# Chef Name: cronhole some stuff -MAILTO=warn@example.com -TEST=lol -FLAG=1 -@reboot /bin/true -CRONTAB - cron = @provider.load_current_resource - - cron.mailto.should == "warn@example.com" - cron.environment.should == {"TEST" => "lol", "FLAG" => "1"} - end - - it "should not break with variables that match the cron resource internals" do - @provider.stub(:read_crontab).and_return(<<-CRONTAB) -# Chef Name: cronhole some stuff -MINUTE=40 -REBOOT=midnight -TEST=lol -ENVIRONMENT=production -@reboot /bin/true -CRONTAB - cron = @provider.load_current_resource - - cron.time.should == :reboot - cron.environment.should == {"MINUTE" => "40", "REBOOT" => "midnight", "TEST" => "lol", "ENVIRONMENT" => "production"} - end - - it "should report the match" do - Chef::Log.should_receive(:debug).with("Found cron '#{@new_resource.name}'") - @provider.load_current_resource - end - - describe "action_create" do - before :each do - @provider.stub(:write_crontab) - @provider.stub(:read_crontab).and_return(nil) - end - - context "when there is no existing crontab" do - before :each do - @provider.cron_exists = false - @provider.cron_empty = true - end - - it "should create a crontab with the entry" do - @provider.should_receive(:write_crontab).with(<<-ENDCRON) -# Chef Name: cronhole some stuff -@reboot /bin/true - ENDCRON - @provider.run_action(:create) - end - end - end - end - end - - before do - @node = Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - - @new_resource = Chef::Resource::Cron.new("cronhole some stuff", @run_context) - @new_resource.user "root" - @new_resource.minute "30" - @new_resource.command "/bin/true" - @provider = Chef::Provider::Cron.new(@new_resource, @run_context) - end - - describe "when examining the current system state" do - context "with no crontab for the user" do - before :each do - @provider.stub(:read_crontab).and_return(nil) - end - - it "should set cron_empty" do - @provider.load_current_resource - @provider.cron_empty.should == true - @provider.cron_exists.should == false - end - - it "should report an empty crontab" do - Chef::Log.should_receive(:debug).with("Cron empty for '#{@new_resource.user}'") - @provider.load_current_resource - end - end - - context "with no matching entry in the user's crontab" do - before :each do - @provider.stub(:read_crontab).and_return(<<-CRONTAB) -0 2 * * * /some/other/command - -# Chef Name: something else -* 5 * * * /bin/true - -# Another comment -CRONTAB - end - - it "should not set cron_exists or cron_empty" do - @provider.load_current_resource - @provider.cron_exists.should == false - @provider.cron_empty.should == false - end - - it "should report no entry found" do - Chef::Log.should_receive(:debug).with("Cron '#{@new_resource.name}' not found") - @provider.load_current_resource - end - - it "should not fail if there's an existing cron with a numerical argument" do - @provider.stub(:read_crontab).and_return(<<-CRONTAB) -# Chef Name: foo[bar] (baz) -21 */4 * * * some_prog 1234567 -CRONTAB - lambda { - @provider.load_current_resource - }.should_not raise_error - end - end - - context "with a matching entry in the user's crontab" do - before :each do - @provider.stub(:read_crontab).and_return(<<-CRONTAB) -0 2 * * * /some/other/command - -# Chef Name: cronhole some stuff -* 5 * 1 * /bin/true param1 param2 -# Chef Name: something else -2 * 1 * * /bin/false - -# Another comment -CRONTAB - end - - it "should set cron_exists" do - @provider.load_current_resource - @provider.cron_exists.should == true - @provider.cron_empty.should == false - end - - it "should pull the details out of the cron line" do - cron = @provider.load_current_resource - cron.minute.should == '*' - cron.hour.should == '5' - cron.day.should == '*' - cron.month.should == '1' - cron.weekday.should == '*' - cron.time.should == nil - cron.command.should == '/bin/true param1 param2' - end - - it "should pull env vars out" do - @provider.stub(:read_crontab).and_return(<<-CRONTAB) -0 2 * * * /some/other/command - -# Chef Name: cronhole some stuff -MAILTO=foo@example.com -SHELL=/bin/foosh -PATH=/bin:/foo -HOME=/home/foo -* 5 * 1 * /bin/true param1 param2 -# Chef Name: something else -2 * 1 * * /bin/false - -# Another comment -CRONTAB - cron = @provider.load_current_resource - cron.mailto.should == 'foo@example.com' - cron.shell.should == '/bin/foosh' - cron.path.should == '/bin:/foo' - cron.home.should == '/home/foo' - cron.minute.should == '*' - cron.hour.should == '5' - cron.day.should == '*' - cron.month.should == '1' - cron.weekday.should == '*' - cron.time.should == nil - cron.command.should == '/bin/true param1 param2' - end - - it "should parse and load generic and standard environment variables from cron entry" do - @provider.stub(:read_crontab).and_return(<<-CRONTAB) -# Chef Name: cronhole some stuff -MAILTO=warn@example.com -TEST=lol -FLAG=1 -* 5 * * * /bin/true -CRONTAB - cron = @provider.load_current_resource - - cron.mailto.should == "warn@example.com" - cron.environment.should == {"TEST" => "lol", "FLAG" => "1"} - end - - it "should not break with variabels that match the cron resource internals" do - @provider.stub(:read_crontab).and_return(<<-CRONTAB) -# Chef Name: cronhole some stuff -MINUTE=40 -HOUR=midnight -TEST=lol -ENVIRONMENT=production -* 5 * * * /bin/true -CRONTAB - cron = @provider.load_current_resource - - cron.minute.should == '*' - cron.hour.should == '5' - cron.environment.should == {"MINUTE" => "40", "HOUR" => "midnight", "TEST" => "lol", "ENVIRONMENT" => "production"} - end - - it "should report the match" do - Chef::Log.should_receive(:debug).with("Found cron '#{@new_resource.name}'") - @provider.load_current_resource - end - end - - context "with a matching entry in the user's crontab using month names and weekday names (#CHEF-3178)" do - before :each do - @provider.stub(:read_crontab).and_return(<<-CRONTAB) -0 2 * * * /some/other/command - -# Chef Name: cronhole some stuff -* 5 * Jan Mon /bin/true param1 param2 -# Chef Name: something else -2 * 1 * * /bin/false - -# Another comment -CRONTAB - end - - it "should set cron_exists" do - @provider.load_current_resource - @provider.cron_exists.should == true - @provider.cron_empty.should == false - end - - it "should pull the details out of the cron line" do - cron = @provider.load_current_resource - cron.minute.should == '*' - cron.hour.should == '5' - cron.day.should == '*' - cron.month.should == 'Jan' - cron.weekday.should == 'Mon' - cron.command.should == '/bin/true param1 param2' - end - - it "should report the match" do - Chef::Log.should_receive(:debug).with("Found cron '#{@new_resource.name}'") - @provider.load_current_resource - end - end - - context "with a matching entry without a crontab line" do - it "should set cron_exists and leave current_resource values at defaults" do - @provider.stub(:read_crontab).and_return(<<-CRONTAB) -0 2 * * * /some/other/command - -# Chef Name: cronhole some stuff -CRONTAB - cron = @provider.load_current_resource - @provider.cron_exists.should == true - cron.minute.should == '*' - cron.hour.should == '*' - cron.day.should == '*' - cron.month.should == '*' - cron.weekday.should == '*' - cron.time.should == nil - cron.command.should == nil - end - - it "should not pick up a commented out crontab line" do - @provider.stub(:read_crontab).and_return(<<-CRONTAB) -0 2 * * * /some/other/command - -# Chef Name: cronhole some stuff -#* 5 * 1 * /bin/true param1 param2 -CRONTAB - cron = @provider.load_current_resource - @provider.cron_exists.should == true - cron.minute.should == '*' - cron.hour.should == '*' - cron.day.should == '*' - cron.month.should == '*' - cron.weekday.should == '*' - cron.time.should == nil - cron.command.should == nil - end - - it "should not pick up a later crontab entry" do - @provider.stub(:read_crontab).and_return(<<-CRONTAB) -0 2 * * * /some/other/command - -# Chef Name: cronhole some stuff -#* 5 * 1 * /bin/true param1 param2 -# Chef Name: something else -2 * 1 * * /bin/false - -# Another comment -CRONTAB - cron = @provider.load_current_resource - @provider.cron_exists.should == true - cron.minute.should == '*' - cron.hour.should == '*' - cron.day.should == '*' - cron.month.should == '*' - cron.weekday.should == '*' - cron.time.should == nil - cron.command.should == nil - end - end - end - - describe "cron_different?" do - before :each do - @current_resource = Chef::Resource::Cron.new("cronhole some stuff") - @current_resource.user "root" - @current_resource.minute "30" - @current_resource.command "/bin/true" - @provider.current_resource = @current_resource - end - - [:minute, :hour, :day, :month, :weekday, :command, :mailto, :path, :shell, :home].each do |attribute| - it "should return true if #{attribute} doesn't match" do - @new_resource.send(attribute, "something_else") - @provider.cron_different?.should eql(true) - end - end - - it "should return true if special time string doesn't match" do - @new_resource.send(:time, :reboot) - @provider.cron_different?.should eql(true) - end - - it "should return true if environment doesn't match" do - @new_resource.environment "FOO" => "something_else" - @provider.cron_different?.should eql(true) - end - - it "should return true if mailto doesn't match" do - @current_resource.mailto "foo@bar.com" - @new_resource.mailto(nil) - @provider.cron_different?.should eql(true) - end - - it "should return false if the objects are identical" do - @provider.cron_different?.should == false - end - end - - describe "action_create" do - before :each do - @provider.stub(:write_crontab) - @provider.stub(:read_crontab).and_return(nil) - end - - context "when there is no existing crontab" do - before :each do - @provider.cron_exists = false - @provider.cron_empty = true - end - - it "should create a crontab with the entry" do - @provider.should_receive(:write_crontab).with(<<-ENDCRON) -# Chef Name: cronhole some stuff -30 * * * * /bin/true - ENDCRON - @provider.run_action(:create) - end - - it "should include env variables that are set" do - @new_resource.mailto 'foo@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" - @provider.should_receive(:write_crontab).with(<<-ENDCRON) -# Chef Name: cronhole some stuff -MAILTO=foo@example.com -PATH=/usr/bin:/my/custom/path -SHELL=/bin/foosh -HOME=/home/foo -TEST=LOL -30 * * * * /bin/true - ENDCRON - @provider.run_action(:create) - end - - it "should mark the resource as updated" do - @provider.run_action(:create) - @new_resource.should be_updated_by_last_action - end - - it "should log the action" do - Chef::Log.should_receive(:info).with("cron[cronhole some stuff] added crontab entry") - @provider.run_action(:create) - end - end - - context "when there is a crontab with no matching section" do - before :each do - @provider.cron_exists = false - @provider.stub(:read_crontab).and_return(<<-CRONTAB) -0 2 * * * /some/other/command - -# Chef Name: something else -2 * 1 * * /bin/false - -# Another comment - CRONTAB - end - - it "should add the entry to the crontab" do - @provider.should_receive(:write_crontab).with(<<-ENDCRON) -0 2 * * * /some/other/command - -# Chef Name: something else -2 * 1 * * /bin/false - -# Another comment -# Chef Name: cronhole some stuff -30 * * * * /bin/true - ENDCRON - @provider.run_action(:create) - end - - it "should include env variables that are set" do - @new_resource.mailto 'foo@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" - @provider.should_receive(:write_crontab).with(<<-ENDCRON) -0 2 * * * /some/other/command - -# Chef Name: something else -2 * 1 * * /bin/false - -# Another comment -# Chef Name: cronhole some stuff -MAILTO=foo@example.com -PATH=/usr/bin:/my/custom/path -SHELL=/bin/foosh -HOME=/home/foo -TEST=LOL -30 * * * * /bin/true - ENDCRON - @provider.run_action(:create) - end - - it "should mark the resource as updated" do - @provider.run_action(:create) - @new_resource.should be_updated_by_last_action - end - - it "should log the action" do - Chef::Log.should_receive(:info).with("cron[cronhole some stuff] added crontab entry") - @provider.run_action(:create) - end - end - - context "when there is a crontab with a matching but different section" do - before :each do - @provider.cron_exists = true - @provider.stub(:cron_different?).and_return(true) - @provider.stub(:read_crontab).and_return(<<-CRONTAB) -0 2 * * * /some/other/command - -# Chef Name: cronhole some stuff -30 * * 3 * /bin/true -# Chef Name: something else -2 * 1 * * /bin/false - -# Another comment - CRONTAB - end - - it "should update the crontab entry" do - @provider.should_receive(:write_crontab).with(<<-ENDCRON) -0 2 * * * /some/other/command - -# Chef Name: cronhole some stuff -30 * * * * /bin/true -# Chef Name: something else -2 * 1 * * /bin/false - -# Another comment - ENDCRON - @provider.run_action(:create) - end - - it "should include env variables that are set" do - @new_resource.mailto 'foo@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" - @provider.should_receive(:write_crontab).with(<<-ENDCRON) -0 2 * * * /some/other/command - -# Chef Name: cronhole some stuff -MAILTO=foo@example.com -PATH=/usr/bin:/my/custom/path -SHELL=/bin/foosh -HOME=/home/foo -TEST=LOL -30 * * * * /bin/true -# Chef Name: something else -2 * 1 * * /bin/false - -# Another comment - ENDCRON - @provider.run_action(:create) - end - - it "should mark the resource as updated" do - @provider.run_action(:create) - @new_resource.should be_updated_by_last_action - end - - it "should log the action" do - Chef::Log.should_receive(:info).with("cron[cronhole some stuff] updated crontab entry") - @provider.run_action(:create) - end - end - - context "when there is a crontab with a matching section with no crontab line in it" do - before :each do - @provider.cron_exists = true - @provider.stub(:cron_different?).and_return(true) - end - - it "should add the crontab to the entry" do - @provider.stub(:read_crontab).and_return(<<-CRONTAB) -0 2 * * * /some/other/command - -# Chef Name: cronhole some stuff - CRONTAB - @provider.should_receive(:write_crontab).with(<<-ENDCRON) -0 2 * * * /some/other/command - -# Chef Name: cronhole some stuff -30 * * * * /bin/true - ENDCRON - @provider.run_action(:create) - end - - it "should not blat any following entries" do - @provider.stub(:read_crontab).and_return(<<-CRONTAB) -0 2 * * * /some/other/command - -# Chef Name: cronhole some stuff -#30 * * * * /bin/true -# Chef Name: something else -2 * 1 * * /bin/false - -# Another comment - CRONTAB - @provider.should_receive(:write_crontab).with(<<-ENDCRON) -0 2 * * * /some/other/command - -# Chef Name: cronhole some stuff -30 * * * * /bin/true -#30 * * * * /bin/true -# Chef Name: something else -2 * 1 * * /bin/false - -# Another comment - ENDCRON - @provider.run_action(:create) - end - - it "should handle env vars with no crontab" do - @provider.stub(:read_crontab).and_return(<<-CRONTAB) -0 2 * * * /some/other/command - -# Chef Name: cronhole some stuff -MAILTO=bar@example.com -PATH=/usr/bin:/my/custom/path -SHELL=/bin/barsh -HOME=/home/foo - -# Chef Name: something else -2 * 1 * * /bin/false - -# Another comment - CRONTAB - @new_resource.mailto 'foo@example.com' - @new_resource.path '/usr/bin:/my/custom/path' - @new_resource.shell '/bin/foosh' - @new_resource.home '/home/foo' - @provider.should_receive(:write_crontab).with(<<-ENDCRON) -0 2 * * * /some/other/command - -# Chef Name: cronhole some stuff -MAILTO=foo@example.com -PATH=/usr/bin:/my/custom/path -SHELL=/bin/foosh -HOME=/home/foo -30 * * * * /bin/true - -# Chef Name: something else -2 * 1 * * /bin/false - -# Another comment - ENDCRON - @provider.run_action(:create) - end - end - - context "when there is a crontab with a matching and identical section" do - before :each do - @provider.cron_exists = true - @provider.stub(:cron_different?).and_return(false) - @provider.stub(:read_crontab).and_return(<<-CRONTAB) -0 2 * * * /some/other/command - -# Chef Name: cronhole some stuff -* 5 * * * /bin/true - -# Another comment -CRONTAB - end - - it "should not update the crontab" do - @provider.should_not_receive(:write_crontab) - @provider.run_action(:create) - end - - it "should not mark the resource as updated" do - @provider.run_action(:create) - @new_resource.should_not be_updated_by_last_action - end - - it "should log nothing changed" do - Chef::Log.should_receive(:debug).with("Found cron '#{@new_resource.name}'") - Chef::Log.should_receive(:debug).with("Skipping existing cron entry '#{@new_resource.name}'") - @provider.run_action(:create) - end - end - end - - describe "action_delete" do - before :each do - @provider.stub(:write_crontab) - @provider.stub(:read_crontab).and_return(nil) - end - - context "when the user's crontab has no matching section" do - before :each do - @provider.cron_exists = false - end - - it "should do nothing" do - @provider.should_not_receive(:write_crontab) - Chef::Log.should_not_receive(:info) - @provider.run_action(:delete) - end - - it "should not mark the resource as updated" do - @provider.run_action(:delete) - @new_resource.should_not be_updated_by_last_action - end - end - - context "when the user has a crontab with a matching section" do - before :each do - @provider.cron_exists = true - @provider.stub(:read_crontab).and_return(<<-CRONTAB) -0 2 * * * /some/other/command - -# Chef Name: cronhole some stuff -30 * * 3 * /bin/true -# Chef Name: something else -2 * 1 * * /bin/false - -# Another comment - CRONTAB - end - - it "should remove the entry" do - @provider.should_receive(:write_crontab).with(<<-ENDCRON) -0 2 * * * /some/other/command - -# Chef Name: something else -2 * 1 * * /bin/false - -# Another comment - ENDCRON - @provider.run_action(:delete) - end - - it "should remove any env vars with the entry" do - @provider.stub(:read_crontab).and_return(<<-CRONTAB) -0 2 * * * /some/other/command - -# Chef Name: cronhole some stuff -MAILTO=foo@example.com -FOO=test -30 * * 3 * /bin/true -# Chef Name: something else -2 * 1 * * /bin/false - -# Another comment - CRONTAB - @provider.should_receive(:write_crontab).with(<<-ENDCRON) -0 2 * * * /some/other/command - -# Chef Name: something else -2 * 1 * * /bin/false - -# Another comment - ENDCRON - @provider.run_action(:delete) - end - - it "should mark the resource as updated" do - @provider.run_action(:delete) - @new_resource.should be_updated_by_last_action - end - - it "should log the action" do - Chef::Log.should_receive(:info).with("#{@new_resource} deleted crontab entry") - @provider.run_action(:delete) - end - end - - context "when the crontab has a matching section with no crontab line" do - before :each do - @provider.cron_exists = true - end - - it "should remove the section" do - @provider.stub(:read_crontab).and_return(<<-CRONTAB) -0 2 * * * /some/other/command - -# Chef Name: cronhole some stuff - CRONTAB - @provider.should_receive(:write_crontab).with(<<-ENDCRON) -0 2 * * * /some/other/command - - ENDCRON - @provider.run_action(:delete) - end - - it "should not blat following sections" do - @provider.stub(:read_crontab).and_return(<<-CRONTAB) -0 2 * * * /some/other/command - -# Chef Name: cronhole some stuff -#30 * * 3 * /bin/true -# Chef Name: something else -2 * 1 * * /bin/false - -# Another comment - CRONTAB - @provider.should_receive(:write_crontab).with(<<-ENDCRON) -0 2 * * * /some/other/command - -#30 * * 3 * /bin/true -# Chef Name: something else -2 * 1 * * /bin/false - -# Another comment - ENDCRON - @provider.run_action(:delete) - end - - it "should remove any envvars with the section" do - @provider.stub(:read_crontab).and_return(<<-CRONTAB) -0 2 * * * /some/other/command - -# Chef Name: cronhole some stuff -MAILTO=foo@example.com -#30 * * 3 * /bin/true -# Chef Name: something else -2 * 1 * * /bin/false - -# Another comment - CRONTAB - @provider.should_receive(:write_crontab).with(<<-ENDCRON) -0 2 * * * /some/other/command - -#30 * * 3 * /bin/true -# Chef Name: something else -2 * 1 * * /bin/false - -# Another comment - ENDCRON - @provider.run_action(:delete) - end - end - end - - describe "read_crontab" do - before :each do - @status = double("Status", :exitstatus => 0) - @stdout = StringIO.new(<<-CRONTAB) -0 2 * * * /some/other/command - -# Chef Name: something else -* 5 * * * /bin/true - -# Another comment - CRONTAB - @provider.stub(:popen4).and_yield(1234, StringIO.new, @stdout, StringIO.new).and_return(@status) - end - - it "should call crontab -l with the user" do - @provider.should_receive(:popen4).with("crontab -l -u #{@new_resource.user}").and_return(@status) - @provider.send(:read_crontab) - end - - it "should return the contents of the crontab" do - crontab = @provider.send(:read_crontab) - crontab.should == <<-CRONTAB -0 2 * * * /some/other/command - -# Chef Name: something else -* 5 * * * /bin/true - -# Another comment - CRONTAB - end - - it "should return nil if the user has no crontab" do - status = double("Status", :exitstatus => 1) - @provider.stub(:popen4).and_return(status) - @provider.send(:read_crontab).should == nil - end - - it "should raise an exception if another error occurs" do - status = double("Status", :exitstatus => 2) - @provider.stub(:popen4).and_return(status) - lambda do - @provider.send(:read_crontab) - end.should raise_error(Chef::Exceptions::Cron, "Error determining state of #{@new_resource.name}, exit: 2") - end - end - - describe "write_crontab" do - before :each do - @status = double("Status", :exitstatus => 0) - @stdin = StringIO.new - @provider.stub(:popen4).and_yield(1234, @stdin, StringIO.new, StringIO.new).and_return(@status) - end - - it "should call crontab for the user" do - @provider.should_receive(:popen4).with("crontab -u #{@new_resource.user} -", :waitlast => true).and_return(@status) - @provider.send(:write_crontab, "Foo") - end - - it "should write the given string to the crontab command" do - @provider.send(:write_crontab, "Foo\n# wibble\n wah!!") - @stdin.string.should == "Foo\n# wibble\n wah!!" - end - - it "should raise an exception if the command returns non-zero" do - @status.stub(:exitstatus).and_return(1) - lambda do - @provider.send(:write_crontab, "Foo") - end.should raise_error(Chef::Exceptions::Cron, "Error updating state of #{@new_resource.name}, exit: 1") - end - - it "should raise an exception if the command die's and parent tries to write" do - class WriteErrPipe - def write(str) - raise Errno::EPIPE, "Test" - end - end - @status.stub(:exitstatus).and_return(1) - @provider.stub(:popen4).and_yield(1234, WriteErrPipe.new, StringIO.new, StringIO.new).and_return(@status) - - Chef::Log.should_receive(:debug).with("Broken pipe - Test") - - lambda do - @provider.send(:write_crontab, "Foo") - end.should raise_error(Chef::Exceptions::Cron, "Error updating state of #{@new_resource.name}, exit: 1") - end - - end - - describe "weekday_in_crontab" do - context "when weekday is symbol" do - it "should return weekday in crontab format" do - @new_resource.weekday :wednesday - @provider.send(:weekday_in_crontab).should eq("3") - end - - it "should raise an error with an unknown weekday" do - expect { @new_resource.weekday :caturday }.to raise_error(RangeError) - end - end - - context "when weekday is a number in a string" do - it "should return the string" do - @new_resource.weekday "3" - @provider.send(:weekday_in_crontab).should eq("3") - end - - it "should raise an error with an out of range number" do - expect { @new_resource.weekday "-1" }.to raise_error(RangeError) - end - end - - context "when weekday is string with the name of the week" do - it "should return the string" do - @new_resource.weekday "mon" - @provider.send(:weekday_in_crontab).should eq("mon") - end - end - - context "when weekday is an integer" do - it "should return the integer" do - @new_resource.weekday 1 - @provider.send(:weekday_in_crontab).should eq("1") - end - - it "should raise an error with an out of range integer" do - expect { @new_resource.weekday 45 }.to raise_error(RangeError) - end - end - end -end diff --git a/spec/unit/provider/deploy/revision_spec.rb b/spec/unit/provider/deploy/revision_spec.rb deleted file mode 100644 index 9fa8bdf826..0000000000 --- a/spec/unit/provider/deploy/revision_spec.rb +++ /dev/null @@ -1,111 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@kallistec.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' - -describe Chef::Provider::Deploy::Revision do - - before do - Chef::Platform.stub(:windows?) { false } - @temp_dir = Dir.mktmpdir - Chef::Config[:file_cache_path] = @temp_dir - @resource = Chef::Resource::Deploy.new("/my/deploy/dir") - @resource.revision("8a3195bf3efa246f743c5dfa83683201880f935c") - @node = Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - @provider = Chef::Provider::Deploy::Revision.new(@resource, @run_context) - @provider.load_current_resource - @runner = double("runnah") - Chef::Runner.stub(:new).and_return(@runner) - @expected_release_dir = "/my/deploy/dir/releases/8a3195bf3efa246f743c5dfa83683201880f935c" - end - - after do - # Make sure we don't keep any state in our tests - FileUtils.rm_rf @temp_dir if File.directory?( @temp_dir ) - end - - - it "uses the resolved revision from the SCM as the release slug" do - @provider.scm_provider.stub(:revision_slug).and_return("uglySlugly") - @provider.send(:release_slug).should == "uglySlugly" - end - - it "deploys to a dir named after the revision" do - @provider.release_path.should == @expected_release_dir - end - - it "stores the release dir in the file cache in the cleanup step" do - FileUtils.stub(:mkdir_p) - FileUtils.stub(:cp_r) - @provider.cleanup! - @provider.stub(:release_slug).and_return("73219b87e977d9c7ba1aa57e9ad1d88fa91a0ec2") - @provider.load_current_resource - @provider.cleanup! - second_release = "/my/deploy/dir/releases/73219b87e977d9c7ba1aa57e9ad1d88fa91a0ec2" - - @provider.all_releases.should == [@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 - FileUtils.stub(:mkdir_p) - FileUtils.stub(:cp_r) - @provider.cleanup! - @provider.stub(:release_slug).and_return("73219b87e977d9c7ba1aa57e9ad1d88fa91a0ec2") - @provider.load_current_resource - @provider.cleanup! - second_release = "/my/deploy/dir/releases/73219b87e977d9c7ba1aa57e9ad1d88fa91a0ec2" - @provider.all_releases.should == [@expected_release_dir,second_release] - @provider.cleanup! - - @provider.stub(:release_slug).and_return("8a3195bf3efa246f743c5dfa83683201880f935c") - @provider.load_current_resource - @provider.cleanup! - @provider.all_releases.should == [second_release, @expected_release_dir] - end - - 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}" - end - release_paths.each do |release_path| - @provider.send(:release_created, release_path) - end - @provider.all_releases.should == release_paths - - FileUtils.stub(:rm_rf) - @provider.cleanup! - - expected_release_paths = (%w{second third fourth fifth} << @resource.revision).map do |release_name| - "/my/deploy/dir/releases/#{release_name}" - end - - @provider.all_releases.should == expected_release_paths - end - - it "regenerates the file cache if it's not available" do - oldest = "/my/deploy/dir/releases/oldest" - latest = "/my/deploy/dir/releases/latest" - Dir.should_receive(:glob).with("/my/deploy/dir/releases/*").and_return([latest, oldest]) - ::File.should_receive(:ctime).with(oldest).and_return(Time.now - 10) - ::File.should_receive(:ctime).with(latest).and_return(Time.now - 1) - @provider.all_releases.should == [oldest, latest] - end - -end diff --git a/spec/unit/provider/deploy/timestamped_spec.rb b/spec/unit/provider/deploy/timestamped_spec.rb deleted file mode 100644 index 1d42abfc05..0000000000 --- a/spec/unit/provider/deploy/timestamped_spec.rb +++ /dev/null @@ -1,40 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@kallistec.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' - -describe Chef::Provider::Deploy::Timestamped do - - before do - @release_time = Time.utc( 2004, 8, 15, 16, 23, 42) - Time.stub(:now).and_return(@release_time) - @expected_release_dir = "/my/deploy/dir/releases/20040815162342" - @resource = Chef::Resource::Deploy.new("/my/deploy/dir") - @node = Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - @timestamped_deploy = Chef::Provider::Deploy::Timestamped.new(@resource, @run_context) - @runner = double("runnah") - Chef::Runner.stub(:new).and_return(@runner) - end - - it "gives a timestamp for release_slug" do - @timestamped_deploy.send(:release_slug).should == "20040815162342" - end - -end diff --git a/spec/unit/provider/deploy_spec.rb b/spec/unit/provider/deploy_spec.rb deleted file mode 100644 index d85ee4c7fd..0000000000 --- a/spec/unit/provider/deploy_spec.rb +++ /dev/null @@ -1,642 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@kallistec.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' - -describe Chef::Provider::Deploy do - - before do - Chef::Platform.stub(:windows?) { false } - @release_time = Time.utc( 2004, 8, 15, 16, 23, 42) - Time.stub(:now).and_return(@release_time) - @expected_release_dir = "/my/deploy/dir/releases/20040815162342" - @resource = Chef::Resource::Deploy.new("/my/deploy/dir") - @node = Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - @provider = Chef::Provider::Deploy.new(@resource, @run_context) - @provider.stub(:release_slug) - @provider.stub(:release_path).and_return(@expected_release_dir) - end - - it "loads scm resource" do - @provider.scm_provider.should_receive(:load_current_resource) - @provider.load_current_resource - end - - it "supports :deploy and :rollback actions" do - @provider.should respond_to(:action_deploy) - @provider.should respond_to(:action_rollback) - end - - context "when the deploy resource has a timeout attribute" do - let(:ten_seconds) { 10 } - before { @resource.timeout(ten_seconds) } - it "relays the timeout to the scm resource" do - @provider.scm_provider.new_resource.timeout.should == ten_seconds - end - end - - context "when the deploy resource has no timeout attribute" do - it "should not set a timeout on the scm resource" do - @provider.scm_provider.new_resource.timeout.should be_nil - end - end - - context "when the deploy_to dir does not exist yet" do - before do - FileUtils.should_receive(:mkdir_p).with(@resource.deploy_to).ordered - FileUtils.should_receive(:mkdir_p).with(@resource.shared_path).ordered - ::File.stub(:directory?).and_return(false) - @provider.stub(:symlink) - @provider.stub(:migrate) - @provider.stub(:copy_cached_repo) - end - - it "creates deploy_to dir" do - ::Dir.should_receive(:chdir).with(@expected_release_dir).exactly(4).times - @provider.should_receive(:enforce_ownership).twice - @provider.stub(:update_cached_repo) - @provider.deploy - end - - end - - it "does not create deploy_to dir if it exists" do - ::File.stub(:directory?).and_return(true) - ::Dir.should_receive(:chdir).with(@expected_release_dir).exactly(4).times - FileUtils.should_not_receive(:mkdir_p).with(@resource.deploy_to) - FileUtils.should_not_receive(:mkdir_p).with(@resource.shared_path) - @provider.should_receive(:enforce_ownership).twice - @provider.stub(:copy_cached_repo) - @provider.stub(:update_cached_repo) - @provider.stub(:symlink) - @provider.stub(:migrate) - @provider.deploy - end - - it "ensures the deploy_to dir ownership after the verfication that it exists" do - ::Dir.should_receive(:chdir).with(@expected_release_dir).exactly(4).times - @provider.should_receive(:verify_directories_exist).ordered - @provider.should_receive(:enforce_ownership).ordered - @provider.stub(:copy_cached_repo) - @provider.stub(:update_cached_repo) - @provider.stub(:install_gems) - @provider.should_receive(:enforce_ownership).ordered - @provider.stub(:enforce_ownership) - @provider.stub(:symlink) - @provider.stub(:migrate) - @provider.deploy - end - - it "updates and copies the repo, then does a migrate, symlink, restart, restart, cleanup on deploy" do - FileUtils.stub(:mkdir_p).with("/my/deploy/dir") - FileUtils.stub(:mkdir_p).with("/my/deploy/dir/shared") - @provider.should_receive(:enforce_ownership).twice - @provider.should_receive(:update_cached_repo) - @provider.should_receive(:copy_cached_repo) - @provider.should_receive(:install_gems) - @provider.should_receive(:callback).with(:before_migrate, nil) - @provider.should_receive(:migrate) - @provider.should_receive(:callback).with(:before_symlink, nil) - @provider.should_receive(:symlink) - @provider.should_receive(:callback).with(:before_restart, nil) - @provider.should_receive(:restart) - @provider.should_receive(:callback).with(:after_restart, nil) - @provider.should_receive(:cleanup!) - @provider.deploy - end - - it "should not deploy if there is already a deploy at release_path, and it is the current release" do - @provider.stub(:all_releases).and_return([@expected_release_dir]) - @provider.stub(:current_release?).with(@expected_release_dir).and_return(true) - @provider.should_not_receive(:deploy) - @provider.run_action(:deploy) - end - - it "should call action_rollback if there is already a deploy of this revision at release_path, and it is not the current release" do - @provider.stub(:all_releases).and_return([@expected_release_dir, "102021"]) - @provider.stub(:current_release?).with(@expected_release_dir).and_return(false) - @provider.should_receive(:rollback_to).with(@expected_release_dir) - @provider.should_receive(:current_release?) - @provider.run_action(:deploy) - end - - it "calls deploy when deploying a new release" do - @provider.stub(:all_releases).and_return([]) - @provider.should_receive(:deploy) - @provider.run_action(:deploy) - end - - it "runs action svn_force_export when new_resource.svn_force_export is true" do - @resource.svn_force_export true - @provider.scm_provider.should_receive(:run_action).with(:force_export) - @provider.update_cached_repo - end - - it "Removes the old release before deploying when force deploying over it" do - @provider.stub(:all_releases).and_return([@expected_release_dir]) - FileUtils.should_receive(:rm_rf).with(@expected_release_dir) - @provider.should_receive(:deploy) - @provider.run_action(:force_deploy) - end - - it "deploys as normal when force deploying and there's no prior release at the same path" do - @provider.stub(:all_releases).and_return([]) - @provider.should_receive(:deploy) - @provider.run_action(:force_deploy) - end - - it "dont care by default if error happens on deploy" do - @provider.stub(:all_releases).and_return(['previous_release']) - @provider.stub(:deploy).and_return{ raise "Unexpected error" } - @provider.stub(:previous_release_path).and_return('previous_release') - @provider.should_not_receive(:rollback) - lambda { - @provider.run_action(:deploy) - }.should raise_exception(RuntimeError, "Unexpected error") - end - - it "rollbacks to previous release if error happens on deploy" do - @resource.rollback_on_error true - @provider.stub(:all_releases).and_return(['previous_release']) - @provider.stub(:deploy).and_return{ raise "Unexpected error" } - @provider.stub(:previous_release_path).and_return('previous_release') - @provider.should_receive(:rollback) - lambda { - @provider.run_action(:deploy) - }.should raise_exception(RuntimeError, "Unexpected error") - end - - describe "on systems without broken Dir.glob results" do - it "sets the release path to the penultimate release when one is not specified, symlinks, and rm's the last release on rollback" do - @provider.stub(:release_path).and_return("/my/deploy/dir/releases/3") - all_releases = ["/my/deploy/dir/releases/1", "/my/deploy/dir/releases/2", "/my/deploy/dir/releases/3", "/my/deploy/dir/releases/4", "/my/deploy/dir/releases/5"] - Dir.stub(:glob).with("/my/deploy/dir/releases/*").and_return(all_releases) - @provider.should_receive(:symlink) - FileUtils.should_receive(:rm_rf).with("/my/deploy/dir/releases/4") - FileUtils.should_receive(:rm_rf).with("/my/deploy/dir/releases/5") - @provider.run_action(:rollback) - @provider.release_path.should eql("/my/deploy/dir/releases/3") - @provider.shared_path.should eql("/my/deploy/dir/shared") - end - - it "sets the release path to the specified release, symlinks, and rm's any newer releases on rollback" do - @provider.unstub(:release_path) - all_releases = ["/my/deploy/dir/releases/20040815162342", "/my/deploy/dir/releases/20040700000000", - "/my/deploy/dir/releases/20040600000000", "/my/deploy/dir/releases/20040500000000"].sort! - Dir.stub(:glob).with("/my/deploy/dir/releases/*").and_return(all_releases) - @provider.should_receive(:symlink) - FileUtils.should_receive(:rm_rf).with("/my/deploy/dir/releases/20040815162342") - @provider.run_action(:rollback) - @provider.release_path.should eql("/my/deploy/dir/releases/20040700000000") - @provider.shared_path.should eql("/my/deploy/dir/shared") - end - - it "sets the release path to the penultimate release, symlinks, and rm's the last release on rollback" do - @provider.unstub(:release_path) - all_releases = [ "/my/deploy/dir/releases/20040815162342", - "/my/deploy/dir/releases/20040700000000", - "/my/deploy/dir/releases/20040600000000", - "/my/deploy/dir/releases/20040500000000"] - Dir.stub(:glob).with("/my/deploy/dir/releases/*").and_return(all_releases) - @provider.should_receive(:symlink) - FileUtils.should_receive(:rm_rf).with("/my/deploy/dir/releases/20040815162342") - @provider.run_action(:rollback) - @provider.release_path.should eql("/my/deploy/dir/releases/20040700000000") - @provider.shared_path.should eql("/my/deploy/dir/shared") - end - - describe "if there are no releases to fallback to" do - - it "an exception is raised when there is only 1 release" do - #@provider.unstub(:release_path) -- unstub the release path on top to feed our own release path - all_releases = [ "/my/deploy/dir/releases/20040815162342"] - Dir.stub(:glob).with("/my/deploy/dir/releases/*").and_return(all_releases) - #@provider.should_receive(:symlink) - #FileUtils.should_receive(:rm_rf).with("/my/deploy/dir/releases/20040815162342") - #@provider.run_action(:rollback) - #@provider.release_path.should eql(NIL) -- no check needed since assertions will fail - lambda { - @provider.run_action(:rollback) - }.should raise_exception(RuntimeError, "There is no release to rollback to!") - end - - it "an exception is raised when there are no releases" do - all_releases = [] - Dir.stub(:glob).with("/my/deploy/dir/releases/*").and_return(all_releases) - lambda { - @provider.run_action(:rollback) - }.should raise_exception(RuntimeError, "There is no release to rollback to!") - end - end - end - - describe "CHEF-628: on systems with broken Dir.glob results" do - it "sets the release path to the penultimate release, symlinks, and rm's the last release on rollback" do - @provider.unstub(:release_path) - all_releases = [ "/my/deploy/dir/releases/20040500000000", - "/my/deploy/dir/releases/20040600000000", - "/my/deploy/dir/releases/20040700000000", - "/my/deploy/dir/releases/20040815162342" ] - Dir.stub(:glob).with("/my/deploy/dir/releases/*").and_return(all_releases) - @provider.should_receive(:symlink) - FileUtils.should_receive(:rm_rf).with("/my/deploy/dir/releases/20040815162342") - @provider.run_action(:rollback) - @provider.release_path.should eql("/my/deploy/dir/releases/20040700000000") - @provider.shared_path.should eql("/my/deploy/dir/shared") - end - end - - it "raises a runtime error when there's no release to rollback to" do - all_releases = [] - Dir.stub(:glob).with("/my/deploy/dir/releases/*").and_return(all_releases) - lambda {@provider.run_action(:rollback)}.should raise_error(RuntimeError) - end - - it "runs the new resource collection in the runner during a callback" do - @runner = double("Runner") - Chef::Runner.stub(:new).and_return(@runner) - @runner.should_receive(:converge) - callback_code = Proc.new { :noop } - @provider.callback(:whatevs, callback_code) - end - - it "loads callback files from the release/ dir if the file exists" do - foo_callback = @expected_release_dir + "/deploy/foo.rb" - ::File.should_receive(:exist?).with(foo_callback).once.and_return(true) - ::Dir.should_receive(:chdir).with(@expected_release_dir).and_yield - @provider.should_receive(:from_file).with(foo_callback) - @provider.callback(:foo, "deploy/foo.rb") - end - - it "raises a runtime error if a callback file is explicitly specified but does not exist" do - baz_callback = "/deploy/baz.rb" - ::File.should_receive(:exist?).with("#{@expected_release_dir}/#{baz_callback}").and_return(false) - @resource.before_migrate baz_callback - @provider.define_resource_requirements - @provider.action = :deploy - lambda {@provider.process_resource_requirements}.should raise_error(RuntimeError) - end - - it "runs a default callback if the callback code is nil" do - bar_callback = @expected_release_dir + "/deploy/bar.rb" - ::File.should_receive(:exist?).with(bar_callback).and_return(true) - ::Dir.should_receive(:chdir).with(@expected_release_dir).and_yield - @provider.should_receive(:from_file).with(bar_callback) - @provider.callback(:bar, nil) - end - - it "skips an eval callback if the file doesn't exist" do - barbaz_callback = @expected_release_dir + "/deploy/barbaz.rb" - ::File.should_receive(:exist?).with(barbaz_callback).and_return(false) - ::Dir.should_receive(:chdir).with(@expected_release_dir).and_yield - @provider.should_not_receive(:from_file) - @provider.callback(:barbaz, nil) - end - - # CHEF-3449 #converge_by is called in #recipe_eval and must happen in sequence - # with the other calls to #converge_by to keep the train on the tracks - it "evaluates a callback file before the corresponding step" do - @provider.should_receive(:verify_directories_exist) - @provider.should_receive(:update_cached_repo) - @provider.should_receive(:enforce_ownership) - @provider.should_receive(:copy_cached_repo) - @provider.should_receive(:install_gems) - @provider.should_receive(:enforce_ownership) - @provider.should_receive(:converge_by).ordered # before_migrate - @provider.should_receive(:migrate).ordered - @provider.should_receive(:converge_by).ordered # before_symlink - @provider.should_receive(:symlink).ordered - @provider.should_receive(:converge_by).ordered # before_restart - @provider.should_receive(:restart).ordered - @provider.should_receive(:converge_by).ordered # after_restart - @provider.should_receive(:cleanup!) - @provider.deploy - end - - it "gets a SCM provider as specified by its resource" do - @provider.scm_provider.should be_an_instance_of(Chef::Provider::Git) - @provider.scm_provider.new_resource.destination.should eql("/my/deploy/dir/shared/cached-copy") - end - - it "syncs the cached copy of the repo" do - @provider.scm_provider.should_receive(:run_action).with(:sync) - @provider.update_cached_repo - end - - it "makes a copy of the cached repo in releases dir" do - FileUtils.should_receive(:mkdir_p).with("/my/deploy/dir/releases") - FileUtils.should_receive(:cp_r).with("/my/deploy/dir/shared/cached-copy/.", @expected_release_dir, :preserve => true) - @provider.copy_cached_repo - end - - it "calls the internal callback :release_created when cleaning up the releases" do - FileUtils.stub(:mkdir_p) - FileUtils.stub(:cp_r) - @provider.should_receive(:release_created) - @provider.cleanup! - end - - it "chowns the whole release dir to user and group specified in the resource" do - @resource.user "foo" - @resource.group "bar" - FileUtils.should_receive(:chown_R).with("foo", "bar", "/my/deploy/dir") - @provider.enforce_ownership - end - - it "skips the migration when resource.migrate => false but runs symlinks before migration" do - @resource.migrate false - @provider.should_not_receive :run_command - @provider.should_receive :run_symlinks_before_migrate - @provider.migrate - end - - it "links the database.yml and runs resource.migration_command when resource.migrate #=> true" do - @resource.migrate true - @resource.migration_command "migration_foo" - @resource.user "deployNinja" - @resource.group "deployNinjas" - @resource.environment "RAILS_ENV" => "production" - FileUtils.should_receive(:ln_sf).with("/my/deploy/dir/shared/config/database.yml", @expected_release_dir + "/config/database.yml") - @provider.should_receive(:enforce_ownership) - - STDOUT.stub(:tty?).and_return(true) - Chef::Log.stub(:info?).and_return(true) - @provider.should_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"}) - @provider.migrate - end - - it "purges the current release's /log /tmp/pids/ and /public/system directories" do - FileUtils.should_receive(:rm_rf).with(@expected_release_dir + "/log") - FileUtils.should_receive(:rm_rf).with(@expected_release_dir + "/tmp/pids") - FileUtils.should_receive(:rm_rf).with(@expected_release_dir + "/public/system") - @provider.purge_tempfiles_from_current_release - end - - it "symlinks temporary files and logs from the shared dir into the current release" do - FileUtils.stub(:mkdir_p).with(@resource.shared_path + "/system") - FileUtils.stub(:mkdir_p).with(@resource.shared_path + "/pids") - FileUtils.stub(:mkdir_p).with(@resource.shared_path + "/log") - FileUtils.should_receive(:mkdir_p).with(@expected_release_dir + "/tmp") - FileUtils.should_receive(:mkdir_p).with(@expected_release_dir + "/public") - FileUtils.should_receive(:mkdir_p).with(@expected_release_dir + "/config") - FileUtils.should_receive(:ln_sf).with("/my/deploy/dir/shared/system", @expected_release_dir + "/public/system") - FileUtils.should_receive(:ln_sf).with("/my/deploy/dir/shared/pids", @expected_release_dir + "/tmp/pids") - FileUtils.should_receive(:ln_sf).with("/my/deploy/dir/shared/log", @expected_release_dir + "/log") - FileUtils.should_receive(:ln_sf).with("/my/deploy/dir/shared/config/database.yml", @expected_release_dir + "/config/database.yml") - @provider.should_receive(:enforce_ownership) - @provider.link_tempfiles_to_current_release - end - - it "symlinks the current release dir into production" do - FileUtils.should_receive(:rm_f).with("/my/deploy/dir/current") - FileUtils.should_receive(:ln_sf).with(@expected_release_dir, "/my/deploy/dir/current") - @provider.should_receive(:enforce_ownership) - @provider.link_current_release_to_production - end - - context "with a customized app layout" do - - before do - @resource.purge_before_symlink(%w{foo bar}) - @resource.create_dirs_before_symlink(%w{baz qux}) - @resource.symlinks "foo/bar" => "foo/bar", "baz" => "qux/baz" - @resource.symlink_before_migrate "radiohead/in_rainbows.yml" => "awesome" - end - - it "purges the purge_before_symlink directories" do - FileUtils.should_receive(:rm_rf).with(@expected_release_dir + "/foo") - FileUtils.should_receive(:rm_rf).with(@expected_release_dir + "/bar") - @provider.purge_tempfiles_from_current_release - end - - it "symlinks files from the shared directory to the current release directory" do - FileUtils.should_receive(:mkdir_p).with(@expected_release_dir + "/baz") - FileUtils.should_receive(:mkdir_p).with(@expected_release_dir + "/qux") - FileUtils.stub(:mkdir_p).with(@resource.shared_path + "/foo/bar") - FileUtils.stub(:mkdir_p).with(@resource.shared_path + "/baz") - FileUtils.should_receive(:ln_sf).with("/my/deploy/dir/shared/foo/bar", @expected_release_dir + "/foo/bar") - FileUtils.should_receive(:ln_sf).with("/my/deploy/dir/shared/baz", @expected_release_dir + "/qux/baz") - FileUtils.should_receive(:ln_sf).with("/my/deploy/dir/shared/radiohead/in_rainbows.yml", @expected_release_dir + "/awesome") - @provider.should_receive(:enforce_ownership) - @provider.link_tempfiles_to_current_release - end - - end - - it "does nothing for restart if restart_command is empty" do - @provider.should_not_receive(:run_command) - @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" - @provider.should_receive(:run_command).with(:command => "restartcmd", :cwd => "/my/deploy/dir/current", :log_tag => "deploy[/my/deploy/dir]", :log_level => :debug) - @provider.restart - end - - it "lists all available releases" do - all_releases = ["/my/deploy/dir/20040815162342", "/my/deploy/dir/20040700000000", - "/my/deploy/dir/20040600000000", "/my/deploy/dir/20040500000000"].sort! - Dir.should_receive(:glob).with("/my/deploy/dir/releases/*").and_return(all_releases) - @provider.all_releases.should eql(all_releases) - end - - it "removes all but the 5 newest releases" do - all_releases = ["/my/deploy/dir/20040815162342", "/my/deploy/dir/20040700000000", - "/my/deploy/dir/20040600000000", "/my/deploy/dir/20040500000000", - "/my/deploy/dir/20040400000000", "/my/deploy/dir/20040300000000", - "/my/deploy/dir/20040200000000", "/my/deploy/dir/20040100000000"].sort! - @provider.stub(:all_releases).and_return(all_releases) - FileUtils.should_receive(:rm_rf).with("/my/deploy/dir/20040100000000") - FileUtils.should_receive(:rm_rf).with("/my/deploy/dir/20040200000000") - FileUtils.should_receive(:rm_rf).with("/my/deploy/dir/20040300000000") - @provider.cleanup! - end - - it "removes all but a certain number of releases when the resource has a keep_releases" do - @resource.keep_releases 7 - all_releases = ["/my/deploy/dir/20040815162342", "/my/deploy/dir/20040700000000", - "/my/deploy/dir/20040600000000", "/my/deploy/dir/20040500000000", - "/my/deploy/dir/20040400000000", "/my/deploy/dir/20040300000000", - "/my/deploy/dir/20040200000000", "/my/deploy/dir/20040100000000"].sort! - @provider.stub(:all_releases).and_return(all_releases) - FileUtils.should_receive(:rm_rf).with("/my/deploy/dir/20040100000000") - @provider.cleanup! - end - - it "fires a callback for :release_deleted when deleting an old release" do - all_releases = ["/my/deploy/dir/20040815162342", "/my/deploy/dir/20040700000000", - "/my/deploy/dir/20040600000000", "/my/deploy/dir/20040500000000", - "/my/deploy/dir/20040400000000", "/my/deploy/dir/20040300000000"].sort! - @provider.stub(:all_releases).and_return(all_releases) - FileUtils.stub(:rm_rf) - @provider.should_receive(:release_deleted).with("/my/deploy/dir/20040300000000") - @provider.cleanup! - end - - it "puts resource.to_hash in @configuration for backwards compat with capistano-esque deploy hooks" do - @provider.instance_variable_get(:@configuration).should == @resource.to_hash - end - - it "sets @configuration[:environment] to the value of RAILS_ENV for backwards compat reasons" do - resource = Chef::Resource::Deploy.new("/my/deploy/dir") - resource.environment "production" - provider = Chef::Provider::Deploy.new(resource, @run_context) - provider.instance_variable_get(:@configuration)[:environment].should eql("production") - end - - it "shouldn't give a no method error on migrate if the environment is nil" do - @provider.stub(:enforce_ownership) - @provider.stub(:run_symlinks_before_migrate) - @provider.stub(:run_command) - @provider.migrate - - end - - context "using inline recipes for callbacks" do - - it "runs an inline recipe with the provided block for :callback_name == {:recipe => &block} " do - snitch = nil - recipe_code = Proc.new {snitch = 42} - #@provider.should_receive(:instance_eval).with(&recipe_code) - @provider.callback(:whateverz, recipe_code) - snitch.should == 42 - end - - it "loads a recipe file from the specified path and from_file evals it" do - ::File.should_receive(:exist?).with(@expected_release_dir + "/chefz/foobar_callback.rb").once.and_return(true) - ::Dir.should_receive(:chdir).with(@expected_release_dir).and_yield - @provider.should_receive(:from_file).with(@expected_release_dir + "/chefz/foobar_callback.rb") - @provider.callback(:whateverz, "chefz/foobar_callback.rb") - end - - it "instance_evals a block/proc for restart command" do - snitch = nil - restart_cmd = Proc.new {snitch = 42} - @resource.restart(&restart_cmd) - @provider.restart - snitch.should == 42 - end - - end - - describe "API bridge to capistrano" do - it "defines sudo as a forwarder to execute" do - @provider.should_receive(:execute).with("the moon, fool") - @provider.sudo("the moon, fool") - end - - it "defines run as a forwarder to execute, setting the user, group, cwd and environment to new_resource.user" do - mock_execution = double("Resource::Execute") - @provider.should_receive(:execute).with("iGoToHell4this").and_return(mock_execution) - @resource.user("notCoolMan") - @resource.group("Ggroup") - @resource.environment("APP_ENV" => 'staging') - @resource.deploy_to("/my/app") - mock_execution.should_receive(:user).with("notCoolMan") - mock_execution.should_receive(:group).with("Ggroup") - mock_execution.should_receive(:cwd){|*args| - if args.empty? - nil - else - args.size.should == 1 - args.first.should == @provider.release_path - end - }.twice - mock_execution.should_receive(:environment){ |*args| - if args.empty? - nil - else - args.size.should == 1 - args.first.should == {"APP_ENV" => "staging"} - end - }.twice - @provider.run("iGoToHell4this") - - end - - it "defines run as a forwarder to execute, setting cwd and environment but not override" do - mock_execution = double("Resource::Execute") - @provider.should_receive(:execute).with("iGoToHell4this").and_return(mock_execution) - @resource.user("notCoolMan") - mock_execution.should_receive(:user).with("notCoolMan") - mock_execution.should_receive(:cwd).with(no_args()).and_return("/some/value") - mock_execution.should_receive(:environment).with(no_args()).and_return({}) - @provider.run("iGoToHell4this") - end - - - it "converts sudo and run to exec resources in hooks" do - runner = double("tehRunner") - Chef::Runner.stub(:new).and_return(runner) - - snitch = nil - @resource.user("tehCat") - - callback_code = Proc.new do - snitch = 42 - temp_collection = self.resource_collection - run("tehMice") - snitch = temp_collection.lookup("execute[tehMice]") - end - - runner.should_receive(:converge) - # - @provider.callback(:phony, callback_code) - snitch.should be_an_instance_of(Chef::Resource::Execute) - snitch.user.should == "tehCat" - end - end - - describe "installing gems from a gems.yml" do - - before do - ::File.stub(:exist?).with("#{@expected_release_dir}/gems.yml").and_return(true) - @gem_list = [{:name=>"eventmachine", :version=>"0.12.9"}] - end - - it "reads a gems.yml file, creating gem providers for each with action :upgrade" do - IO.should_receive(:read).with("#{@expected_release_dir}/gems.yml").and_return("cookie") - YAML.should_receive(:load).with("cookie").and_return(@gem_list) - - gems = @provider.send(:gem_packages) - - gems.map { |g| g.action }.should == [[:install]] - gems.map { |g| g.name }.should == %w{eventmachine} - gems.map { |g| g.version }.should == %w{0.12.9} - end - - it "takes a list of gem providers converges them" do - IO.stub(:read) - YAML.stub(:load).and_return(@gem_list) - expected_gem_resources = @provider.send(:gem_packages).map { |r| [r.name, r.version] } - gem_runner = @provider.send(:gem_resource_collection_runner) - # no one has heard of defining == to be meaningful so I have use this monstrosity - actual = gem_runner.run_context.resource_collection.all_resources.map { |r| [r.name, r.version] } - actual.should == expected_gem_resources - end - - end - -end diff --git a/spec/unit/provider/directory_spec.rb b/spec/unit/provider/directory_spec.rb deleted file mode 100644 index 25ca9e0175..0000000000 --- a/spec/unit/provider/directory_spec.rb +++ /dev/null @@ -1,188 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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 'ostruct' - -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) - 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 "scanning file security metadata on windows" do - before do - end - - it "describes the directory's access rights" do - pending - end - end - - describe "scanning file security metadata on unix" do - before do - Chef::Platform.stub(:windows?).and_return(false) - end - let(:mock_stat) do - cstats = double("stats") - cstats.stub(:uid).and_return(500) - cstats.stub(:gid).and_return(500) - cstats.stub(:mode).and_return(0755) - cstats - end - - it "describes the access mode as a String of octal integers" do - File.stub(:exists?).and_return(true) - File.should_receive(:stat).and_return(mock_stat) - @directory.load_current_resource - @directory.current_resource.mode.should == "0755" - end - - context "when user and group are specified with UID/GID" do - it "describes the current owner and group as UID and GID" do - File.stub(:exists?).and_return(true) - File.should_receive(:stat).and_return(mock_stat) - @directory.load_current_resource - @directory.current_resource.path.should eql(@new_resource.path) - @directory.current_resource.owner.should eql(500) - @directory.current_resource.group.should eql(500) - end - end - - context "when user/group are specified with user/group names" do - 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" - - File.should_receive(:exists?).at_least(:once).and_return(false) - File.should_receive(:directory?).with("/tmp").and_return(true) - Dir.should_receive(:mkdir).with(@new_resource.path).once.and_return(true) - - @directory.should_receive(:do_acl_changes) - @directory.stub(:do_selinux) - @directory.run_action(:create) - @directory.new_resource.should be_updated - 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 - lambda { @directory.run_action(:create) }.should raise_error(Chef::Exceptions::EnclosingDirectoryDoesNotExist) - 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 - File.should_receive(:exists?).with(@new_resource.path).ordered.and_return(false) - - File.should_receive(:exists?).with('/path/to').ordered.and_return(false) - File.should_receive(:exists?).with('/path').ordered.and_return(true) - File.should_receive(:writable?).with('/path').ordered.and_return(true) - File.should_receive(:exists?).with(@new_resource.path).ordered.and_return(false) - - FileUtils.should_receive(:mkdir_p).with(@new_resource.path).and_return(true) - @directory.should_receive(:do_acl_changes) - @directory.stub(:do_selinux) - @directory.run_action(:create) - @new_resource.should be_updated - end - - - it "should raise an error when creating a directory when parent directory is a file" do - File.should_receive(:directory?).and_return(false) - Dir.should_not_receive(:mkdir).with(@new_resource.path) - lambda { @directory.run_action(:create) }.should raise_error(Chef::Exceptions::EnclosingDirectoryDoesNotExist) - @directory.new_resource.should_not be_updated - 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" - File.should_receive(:directory?).at_least(:once).and_return(true) - File.should_receive(:writable?).with("/tmp").and_return(true) - File.should_receive(:exists?).at_least(:once).and_return(true) - Dir.should_not_receive(:mkdir).with(@new_resource.path) - @directory.should_receive(:do_acl_changes) - @directory.run_action(:create) - end - - it "should delete the directory if it exists, and is writable with action_delete" do - File.should_receive(:directory?).and_return(true) - File.should_receive(:writable?).once.and_return(true) - Dir.should_receive(:delete).with(@new_resource.path).once.and_return(true) - @directory.run_action(:delete) - end - - it "should raise an exception if it cannot delete the directory due to bad permissions" do - File.stub(:exists?).and_return(true) - File.stub(:writable?).and_return(false) - lambda { @directory.run_action(:delete) }.should raise_error(RuntimeError) - end - - it "should take no action when deleting a target directory that does not exist" do - @new_resource.path "/an/invalid/path" - File.stub(:exists?).and_return(false) - Dir.should_not_receive(:delete).with(@new_resource.path) - @directory.run_action(:delete) - @directory.new_resource.should_not be_updated - 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" - File.stub(:exists?).and_return(true) - File.should_receive(:directory?).and_return(false) - Dir.should_not_receive(:delete).with(@new_resource.path) - lambda { @directory.run_action(:delete) }.should raise_error(RuntimeError) - @directory.new_resource.should_not be_updated - end - - def stub_file_cstats - cstats = double("stats") - cstats.stub(:uid).and_return(500) - cstats.stub(:gid).and_return(500) - cstats.stub(:mode).and_return(0755) - # File.stat is called in: - # - Chef::Provider::File.load_current_resource_attrs - # - Chef::ScanAccessControl via Chef::Provider::File.setup_acl - File.stub(:stat).and_return(cstats) - end -end diff --git a/spec/unit/provider/dsc_script_spec.rb b/spec/unit/provider/dsc_script_spec.rb deleted file mode 100644 index d8fbee3ff9..0000000000 --- a/spec/unit/provider/dsc_script_spec.rb +++ /dev/null @@ -1,174 +0,0 @@ -# -# Author:: Jay Mundrawala (<jdm@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 'chef' -require 'chef/util/dsc/resource_info' -require 'spec_helper' - -describe Chef::Provider::DscScript do - context 'when DSC is available' do - let (:node) { - node = Chef::Node.new - node.automatic[:languages][:powershell][:version] = '4.0' - node - } - let (:events) { Chef::EventDispatch::Dispatcher.new } - let (:run_context) { Chef::RunContext.new(node, {}, events) } - let (:resource) { Chef::Resource::DscScript.new("script", run_context) } - let (:provider) do - Chef::Provider::DscScript.new(resource, run_context) - end - - describe '#load_current_resource' 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 - provider.instance_variable_get('@resource_converged').should be_true - 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']) - allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info]) - provider.load_current_resource - provider.instance_variable_get('@resource_converged').should be_true - 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']) - allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info]) - provider.load_current_resource - provider.instance_variable_get('@resource_converged').should be_false - 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']) - - allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info1, dsc_resource_info2]) - provider.load_current_resource - provider.instance_variable_get('@resource_converged').should be_false - 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']) - - allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info1, dsc_resource_info2]) - provider.load_current_resource - provider.instance_variable_get('@resource_converged').should be_true - 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 - allow(provider).to receive(:load_current_resource) - resource.command("path_to_script") - generator = double('Chef::Util::DSC::ConfigurationGenerator') - generator.should_receive(:configuration_document_from_script_path) - allow(Chef::Util::DSC::ConfigurationGenerator).to receive(:new).and_return(generator) - provider.send(:generate_configuration_document, 'tmp', nil) - end - - 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.should_receive(:configuration_document_from_script_code) - allow(Chef::Util::DSC::ConfigurationGenerator).to receive(:new).and_return(generator) - provider.send(:generate_configuration_document, 'tmp', nil) - end - - it 'should noop if neither code or command are provided' do - allow(provider).to receive(:load_current_resource) - generator = double('Chef::Util::DSC::ConfigurationGenerator') - generator.should_receive(:configuration_document_from_script_code).with('', anything(), anything()) - allow(Chef::Util::DSC::ConfigurationGenerator).to receive(:new).and_return(generator) - 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']) - allow(provider).to receive(:run_configuration).with(:test).and_return([dsc_resource_info]) - allow(provider).to receive(:run_configuration).with(:set) - - provider.run_action(:run) - resource.should be_updated - end - - 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) - resource.should_not 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]) - provider.send(:generate_description)[1].should 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]) - provider.send(:generate_description)[1].should_not 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]) - provider.send(:generate_description)[1].should match(/converge DSC resource resourcename by doing nothing/) - end - end - end - - 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 (:provider) { Chef::Provider::DscScript.new(resource, run_context) } - - 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) - end - end - - it 'raises an exception if Powershell is not present' do - expect { - provider.run_action(:run) - }.to raise_error(Chef::Exceptions::NoProviderAvailable) - end - - end - end -end - diff --git a/spec/unit/provider/env/windows_spec.rb b/spec/unit/provider/env/windows_spec.rb deleted file mode 100644 index 2ea137c1d9..0000000000 --- a/spec/unit/provider/env/windows_spec.rb +++ /dev/null @@ -1,103 +0,0 @@ -# -# Author:: Sander van Harmelen <svanharmelen@schubergphilis.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' - -describe Chef::Provider::Env::Windows, :windows_only do - let(:node) { Chef::Node.new } - let(:events) {Chef::EventDispatch::Dispatcher.new } - let(:run_context) { Chef::RunContext.new(node, {}, events) } - - 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) - provider.stub(:env_obj).and_return(double('null object').as_null_object) - provider - } - - describe "action_create" do - before do - 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') - end - end - - describe "action_modify" do - before do - ENV['CHEF_WINDOWS_ENV_TEST'] = 'foo' - end - - it "should update the ruby ENV object when it updates the value" do - provider.should_receive(:compare_value).and_return(true) - new_resource.value("foobar") - provider.action_modify - expect(ENV['CHEF_WINDOWS_ENV_TEST']).to eql('foobar') - end - - describe "action_delete" do - before do - 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) - end - end - end - end - - context 'when environment is PATH' do - describe "for PATH" do - let(:system_root) {'%SystemRoot%'} - let(:system_root_value) { 'D:\Windows' } - let(:new_resource) { - 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) - provider.stub(:env_obj).and_return(double('null object').as_null_object) - provider - } - - before do - stub_const('ENV', {'PATH' => ''}) - end - - it "replaces Windows system variables" do - provider.should_receive(:compare_value).and_return(true) - provider.should_receive(:expand_path).with(system_root).and_return(system_root_value) - provider.action_modify - expect(ENV['PATH']).to eql(system_root_value) - end - end - - end -end diff --git a/spec/unit/provider/env_spec.rb b/spec/unit/provider/env_spec.rb deleted file mode 100644 index dc6176d45c..0000000000 --- a/spec/unit/provider/env_spec.rb +++ /dev/null @@ -1,251 +0,0 @@ -# -# Author:: Doug MacEachern (<dougm@vmware.com>) -# Copyright:: Copyright (c) 2010 VMware, 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::Env do - - before do - @node = Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - @new_resource = Chef::Resource::Env.new("FOO") - @new_resource.value("bar") - @provider = Chef::Provider::Env.new(@new_resource, @run_context) - end - - it "assumes the key_name exists by default" do - @provider.key_exists.should be_true - end - - describe "when loading the current status" do - before do - #@current_resource = @new_resource.clone - #Chef::Resource::Env.stub(:new).and_return(@current_resource) - @provider.current_resource = @current_resource - @provider.stub(:env_value).with("FOO").and_return("bar") - @provider.stub(:env_key_exists).and_return(true) - end - - it "should create a current resource with the same name as the new resource" do - @provider.load_current_resource - @provider.new_resource.name.should == "FOO" - end - - it "should set the key_name to the key name of the new resource" do - @provider.load_current_resource - @provider.current_resource.key_name.should == "FOO" - end - - it "should check if the key_name exists" do - @provider.should_receive(:env_key_exists).with("FOO").and_return(true) - @provider.load_current_resource - @provider.key_exists.should be_true - end - - it "should flip the value of exists if the key does not exist" do - @provider.should_receive(:env_key_exists).with("FOO").and_return(false) - @provider.load_current_resource - @provider.key_exists.should be_false - end - - it "should return the current resource" do - @provider.load_current_resource.should be_a_kind_of(Chef::Resource::Env) - end - end - - describe "action_create" do - before do - @provider.key_exists = false - @provider.stub(:create_env).and_return(true) - @provider.stub(:modify_env).and_return(true) - end - - it "should call create_env if the key does not exist" do - @provider.should_receive(:create_env).and_return(true) - @provider.action_create - end - - it "should set the new_resources updated flag when it creates the key" do - @provider.action_create - @new_resource.should be_updated - end - - it "should check to see if the values are the same if the key exists" do - @provider.key_exists = true - @provider.should_receive(:compare_value).and_return(false) - @provider.action_create - end - - it "should call modify_env if the key exists and values are not equal" do - @provider.key_exists = true - @provider.stub(:compare_value).and_return(true) - @provider.should_receive(:modify_env).and_return(true) - @provider.action_create - end - - it "should set the new_resources updated flag when it updates an existing value" do - @provider.key_exists = true - @provider.stub(:compare_value).and_return(true) - @provider.stub(:modify_env).and_return(true) - @provider.action_create - @new_resource.should be_updated - end - end - - describe "action_delete" do - before(:each) do - @provider.current_resource = @current_resource - @provider.key_exists = false - @provider.stub(:delete_element).and_return(false) - @provider.stub(:delete_env).and_return(true) - end - - it "should not call delete_env if the key does not exist" do - @provider.should_not_receive(:delete_env) - @provider.action_delete - end - - it "should not call delete_element if the key does not exist" do - @provider.should_not_receive(:delete_element) - @provider.action_delete - end - - it "should call delete_env if the key exists" do - @provider.key_exists = true - @provider.should_receive(:delete_env) - @provider.action_delete - end - - it "should set the new_resources updated flag to true if the key is deleted" do - @provider.key_exists = true - @provider.action_delete - @new_resource.should be_updated - end - end - - describe "action_modify" do - before(:each) do - @provider.current_resource = @current_resource - @provider.key_exists = true - @provider.stub(:modify_env).and_return(true) - end - - it "should call modify_group if the key exists and values are not equal" do - @provider.should_receive(:compare_value).and_return(true) - @provider.should_receive(:modify_env).and_return(true) - @provider.action_modify - end - - it "should set the new resources updated flag to true if modify_env is called" do - @provider.stub(:compare_value).and_return(true) - @provider.stub(:modify_env).and_return(true) - @provider.action_modify - @new_resource.should be_updated - end - - it "should not call modify_env if the key exists but the values are equal" do - @provider.should_receive(:compare_value).and_return(false) - @provider.should_not_receive(:modify_env) - @provider.action_modify - end - - it "should raise a Chef::Exceptions::Env if the key doesn't exist" do - @provider.key_exists = false - lambda { @provider.action_modify }.should raise_error(Chef::Exceptions::Env) - end - end - - describe "delete_element" do - before(:each) do - @current_resource = Chef::Resource::Env.new("FOO") - - @new_resource.delim ";" - @new_resource.value "C:/bar/bin" - - @current_resource.value "C:/foo/bin;C:/bar/bin" - @provider.current_resource = @current_resource - end - - it "should return true if the element is not found" do - @new_resource.stub(:value).and_return("C:/baz/bin") - @provider.delete_element.should eql(true) - end - - it "should return false if the delim not defined" do - @new_resource.stub(:delim).and_return(nil) - @provider.delete_element.should eql(false) - end - - it "should return true if the element is deleted" do - @new_resource.value("C:/foo/bin") - @provider.should_receive(:create_env) - @provider.delete_element.should eql(true) - @new_resource.should be_updated - end - end - - describe "compare_value" do - before(:each) do - @new_resource.value("C:/bar") - @current_resource = @new_resource.clone - @provider.current_resource = @current_resource - end - - it "should return false if the values are equal" do - @provider.compare_value.should be_false - end - - it "should return true if the values not are equal" do - @new_resource.value("C:/elsewhere") - @provider.compare_value.should be_true - end - - it "should return false if the current value contains the element" do - @new_resource.delim(";") - @current_resource.value("C:/bar;C:/foo;C:/baz") - - @provider.compare_value.should be_false - end - - it "should return true if the current value does not contain the element" do - @new_resource.delim(";") - @current_resource.value("C:/biz;C:/foo/bin;C:/baz") - @provider.compare_value.should be_true - end - end - - describe "modify_env" do - before(:each) do - @provider.stub(:create_env).and_return(true) - @new_resource.delim ";" - - @current_resource = Chef::Resource::Env.new("FOO") - @current_resource.value "C:/foo/bin" - @provider.current_resource = @current_resource - end - - it "should not modify the variable passed to the resource" do - new_value = "C:/bar/bin" - passed_value = new_value.dup - @new_resource.value(passed_value) - @provider.modify_env - passed_value.should == new_value - end - end -end diff --git a/spec/unit/provider/erl_call_spec.rb b/spec/unit/provider/erl_call_spec.rb deleted file mode 100644 index 19e16f282f..0000000000 --- a/spec/unit/provider/erl_call_spec.rb +++ /dev/null @@ -1,86 +0,0 @@ -# -# Author:: Joe Williams (<joe@joetify.com>) -# Copyright:: Copyright (c) 2009 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 'spec_helper' - -describe Chef::Provider::ErlCall do - before(:each) do - @node = Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - - @new_resource = Chef::Resource::ErlCall.new("test", @node) - @new_resource.code("io:format(\"burritos\", []).") - @new_resource.node_name("chef@localhost") - @new_resource.name("test") - - @provider = Chef::Provider::ErlCall.new(@new_resource, @run_context) - - @provider.stub(:popen4).and_return(@status) - @stdin = StringIO.new - @stdout = StringIO.new('{ok, woohoo}') - @stderr = StringIO.new - @pid = 2342999 - end - - it "should return a Chef::Provider::ErlCall object" do - provider = Chef::Provider::ErlCall.new(@new_resource, @run_context) - provider.should be_a_kind_of(Chef::Provider::ErlCall) - end - - it "should return true" do - @provider.load_current_resource.should eql(true) - end - - describe "when running a distributed erl call resource" do - before do - @new_resource.cookie("nomnomnom") - @new_resource.distributed(true) - @new_resource.name_type("sname") - end - - it "should write to stdin of the erl_call command" do - expected_cmd = "erl_call -e -s -sname chef@localhost -c nomnomnom" - @provider.should_receive(:popen4).with(expected_cmd, :waitlast => true).and_return([@pid, @stdin, @stdout, @stderr]) - Process.should_receive(:wait).with(@pid) - - @provider.action_run - - @stdin.string.should == "#{@new_resource.code}\n" - end - end - - describe "when running a local erl call resource" do - before do - @new_resource.cookie(nil) - @new_resource.distributed(false) - @new_resource.name_type("name") - end - - it "should write to stdin of the erl_call command" do - @provider.should_receive(:popen4).with("erl_call -e -name chef@localhost ", :waitlast => true).and_return([@pid, @stdin, @stdout, @stderr]) - Process.should_receive(:wait).with(@pid) - - @provider.action_run - - @stdin.string.should == "#{@new_resource.code}\n" - end - end - -end - diff --git a/spec/unit/provider/execute_spec.rb b/spec/unit/provider/execute_spec.rb deleted file mode 100644 index 78216a89fa..0000000000 --- a/spec/unit/provider/execute_spec.rb +++ /dev/null @@ -1,89 +0,0 @@ -# -# Author:: Prajakta Purohit (<prajakta@opscode.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 File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper")) -#require 'spec_helper' - -describe Chef::Provider::Execute do - before do - @node = Chef::Node.new - @cookbook_collection = Chef::CookbookCollection.new([]) - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events) - @new_resource = Chef::Resource::Execute.new("foo_resource", @run_context) - @new_resource.timeout 3600 - @new_resource.returns 0 - @new_resource.creates "/foo_resource" - @provider = Chef::Provider::Execute.new(@new_resource, @run_context) - @current_resource = Chef::Resource::Ifconfig.new("foo_resource", @run_context) - @provider.current_resource = @current_resource - Chef::Log.level = :info - # FIXME: There should be a test for how STDOUT.tty? changes the live_stream option being passed - STDOUT.stub(:tty?).and_return(true) - end - - - it "should execute foo_resource" do - @provider.stub(:load_current_resource) - opts = {} - opts[:timeout] = @new_resource.timeout - opts[:returns] = @new_resource.returns - opts[:log_level] = :info - opts[:log_tag] = @new_resource.to_s - opts[:live_stream] = STDOUT - @provider.should_receive(:shell_out!).with(@new_resource.command, opts) - Chef::Log.should_not_receive(:warn) - - @provider.run_action(:run) - @new_resource.should be_updated - end - - it "should do nothing if the sentinel file exists" do - @provider.stub(:load_current_resource) - File.should_receive(:exists?).with(@new_resource.creates).and_return(true) - @provider.should_not_receive(:shell_out!) - Chef::Log.should_not_receive(:warn) - - @provider.run_action(:run) - @new_resource.should_not be_updated - end - - it "should respect cwd options for 'creates'" do - @new_resource.cwd "/tmp" - @new_resource.creates "foo_resource" - @provider.stub(:load_current_resource) - File.should_receive(:exists?).with(@new_resource.creates).and_return(false) - File.should_receive(:exists?).with(File.join("/tmp", @new_resource.creates)).and_return(true) - Chef::Log.should_not_receive(:warn) - @provider.should_not_receive(:shell_out!) - - @provider.run_action(:run) - @new_resource.should_not be_updated - end - - it "should warn if user specified relative path without cwd" do - @new_resource.creates "foo_resource" - @provider.stub(:load_current_resource) - Chef::Log.should_receive(:warn).with(/relative path/) - File.should_receive(:exists?).with(@new_resource.creates).and_return(true) - @provider.should_not_receive(:shell_out!) - - @provider.run_action(:run) - @new_resource.should_not be_updated - end -end - diff --git a/spec/unit/provider/file/content_spec.rb b/spec/unit/provider/file/content_spec.rb deleted file mode 100644 index 34d98b6619..0000000000 --- a/spec/unit/provider/file/content_spec.rb +++ /dev/null @@ -1,93 +0,0 @@ -# -# Author:: Lamont Granquist (<lamont@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::File::Content do - - # - # mock setup - # - - let(:current_resource) do - double("Chef::Provider::File::Resource (current)") - end - - let(:enclosing_directory) { - canonicalize_path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates"))) - } - let(:resource_path) { - canonicalize_path(File.expand_path(File.join(enclosing_directory, "seattle.txt"))) - } - - let(:new_resource) do - double("Chef::Provider::File::Resource (new)", :name => "seattle.txt", :path => resource_path) - end - - let(:run_context) do - double("Chef::RunContext") - end - - # - # subject - # - let(:content) do - Chef::Provider::File::Content.new(new_resource, current_resource, run_context) - end - - describe "when the resource has a content attribute set" do - - before do - new_resource.stub(:content).and_return("Do do do do, do do do do, do do do do, do do do do") - end - - it "returns a tempfile" do - content.tempfile.should be_a_kind_of(Tempfile) - end - - it "the tempfile contents should match the resource contents" do - IO.read(content.tempfile.path).should == new_resource.content - end - - it "returns a tempfile in the tempdir when :file_staging_uses_destdir is not set" do - Chef::Config[:file_staging_uses_destdir] = false - content.tempfile.path.start_with?(Dir::tmpdir).should be_true - canonicalize_path(content.tempfile.path).start_with?(enclosing_directory).should be_false - end - - it "returns a tempfile in the destdir when :file_desployment_uses_destdir is not set" do - Chef::Config[:file_staging_uses_destdir] = true - content.tempfile.path.start_with?(Dir::tmpdir).should be_false - canonicalize_path(content.tempfile.path).start_with?(enclosing_directory).should be_true - end - - end - - describe "when the resource does not have a content attribute set" do - - before do - new_resource.stub(:content).and_return(nil) - end - - it "should return nil instead of a tempfile" do - content.tempfile.should be_nil - end - - end -end - diff --git a/spec/unit/provider/file_spec.rb b/spec/unit/provider/file_spec.rb deleted file mode 100644 index 059f1722fb..0000000000 --- a/spec/unit/provider/file_spec.rb +++ /dev/null @@ -1,57 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: Lamont Granquist (<lamont@opscode.com>) -# Copyright:: Copyright (c) 2008-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 'support/shared/unit/provider/file' - -describe Chef::Provider::File do - - let(:resource) do - # need to check for/against mutating state within the new_resource, so don't mock - resource = Chef::Resource::File.new("seattle") - resource.path(resource_path) - resource - end - - let(:content) do - 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(:enclosing_directory) { - canonicalize_path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates"))) - } - let(:resource_path) { - canonicalize_path(File.expand_path(File.join(enclosing_directory, "seattle.txt"))) - } - - # Subject - - let(:provider) do - provider = described_class.new(resource, run_context) - provider.stub(:content).and_return(content) - provider - end - - it_behaves_like Chef::Provider::File - - 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 deleted file mode 100644 index ff1c0b0398..0000000000 --- a/spec/unit/provider/git_spec.rb +++ /dev/null @@ -1,618 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@kallistec.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' -describe Chef::Provider::Git do - - before(:each) do - STDOUT.stub(:tty?).and_return(true) - Chef::Log.level = :info - - @current_resource = Chef::Resource::Git.new("web2.0 app") - @current_resource.revision("d35af14d41ae22b19da05d7d03a0bafc321b244c") - - @resource = Chef::Resource::Git.new("web2.0 app") - @resource.repository "git://github.com/opscode/chef.git" - @resource.destination "/my/deploy/dir" - @resource.revision "d35af14d41ae22b19da05d7d03a0bafc321b244c" - @node = Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - @provider = Chef::Provider::Git.new(@resource, @run_context) - @provider.current_resource = @current_resource - end - - context "determining the revision of the currently deployed checkout" do - - before do - @stdout = double("standard out") - @stderr = double("standard error") - @exitstatus = double("exitstatus") - end - - it "sets the current revision to nil if the deploy dir does not exist" do - ::File.should_receive(:exist?).with("/my/deploy/dir/.git").and_return(false) - @provider.find_current_revision.should be_nil - end - - it "determines the current revision when there is one" do - ::File.should_receive(:exist?).with("/my/deploy/dir/.git").and_return(true) - @stdout = "9b4d8dc38dd471246e7cfb1c3c1ad14b0f2bee13\n" - @provider.should_receive(:shell_out!).with('git rev-parse HEAD', {:cwd => '/my/deploy/dir', :returns => [0,128]}).and_return(double("ShellOut result", :stdout => @stdout)) - @provider.find_current_revision.should eql("9b4d8dc38dd471246e7cfb1c3c1ad14b0f2bee13") - end - - it "gives the current revision as nil when there is no current revision" do - ::File.should_receive(:exist?).with("/my/deploy/dir/.git").and_return(true) - @stderr = "fatal: Not a git repository (or any of the parent directories): .git" - @stdout = "" - @provider.should_receive(:shell_out!).with('git rev-parse HEAD', :cwd => '/my/deploy/dir', :returns => [0,128]).and_return(double("ShellOut result", :stdout => "", :stderr => @stderr)) - @provider.find_current_revision.should be_nil - end - end - - it "creates a current_resource with the currently deployed revision when a clone exists in the destination dir" do - @provider.stub(:find_current_revision).and_return("681c9802d1c62a45b490786c18f0b8216b309440") - @provider.load_current_resource - @provider.current_resource.name.should eql(@resource.name) - @provider.current_resource.revision.should eql("681c9802d1c62a45b490786c18f0b8216b309440") - end - - it "keeps the node and resource passed to it on initialize" do - @provider.node.should equal(@node) - @provider.new_resource.should equal(@resource) - end - - context "resolving revisions to a SHA" do - - before do - @git_ls_remote = "git ls-remote \"git://github.com/opscode/chef.git\" " - end - - it "returns resource.revision as is if revision is already a full SHA" do - @provider.target_revision.should eql("d35af14d41ae22b19da05d7d03a0bafc321b244c") - end - - it "converts resource.revision from a tag to a SHA" do - @resource.revision "v1.0" - @stdout = ("d03c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n" + - "503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/v1.0\n") - @provider.should_receive(:shell_out!).with(@git_ls_remote + "\"v1.0*\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout)) - @provider.target_revision.should eql("503c22a5e41f5ae3193460cca044ed1435029f53") - end - - it "converts resource.revision from an annotated tag to the tagged SHA (not SHA of tag)" do - @resource.revision "v1.0" - @stdout = ("d03c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha\n" + - "503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/v1.0\n" + - "663c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/v1.0^{}\n") - @provider.should_receive(:shell_out!).with(@git_ls_remote + "\"v1.0*\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout)) - @provider.target_revision.should eql("663c22a5e41f5ae3193460cca044ed1435029f53") - end - - it "raises an invalid remote reference error if you try to deploy from ``origin'' and assertions are run" do - @resource.revision "origin/" - @provider.action = :checkout - @provider.define_resource_requirements - ::File.stub(:directory?).with("/my/deploy").and_return(true) - lambda {@provider.process_resource_requirements}.should 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 - @resource.revision "FAIL, that's the revision I want" - @provider.action = :checkout - @provider.should_receive(:shell_out!).and_return(double("ShellOut result", :stdout => "\n")) - @provider.define_resource_requirements - lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::UnresolvableGitReference) - end - - it "does not raise an error if the revision can't be resolved when assertions are not run" do - @resource.revision "FAIL, that's the revision I want" - @provider.should_receive(:shell_out!).and_return(double("ShellOut result", :stdout => "\n")) - @provider.target_revision.should == nil - end - - 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" - @provider.should_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 - ::File.stub(:directory?).with("/my/deploy").and_return(true) - @provider.define_resource_requirements - lambda { @provider.process_resource_requirements }.should_not raise_error - end - - it "gives the latest HEAD revision SHA if nothing is specified" do - @stdout =<<-SHAS -28af684d8460ba4793eda3e7ac238c864a5d029a\tHEAD -503c22a5e41f5ae3193460cca044ed1435029f53\trefs/heads/0.8-alpha -28af684d8460ba4793eda3e7ac238c864a5d029a\trefs/heads/master -c44fe79bb5e36941ce799cee6b9de3a2ef89afee\trefs/tags/0.5.2 -14534f0e0bf133dc9ff6dbe74f8a0c863ff3ac6d\trefs/tags/0.5.4 -d36fddb4291341a1ff2ecc3c560494e398881354\trefs/tags/0.5.6 -9e5ce9031cbee81015de680d010b603bce2dd15f\trefs/tags/0.6.0 -9b4d8dc38dd471246e7cfb1c3c1ad14b0f2bee13\trefs/tags/0.6.2 -014a69af1cdce619de82afaf6cdb4e6ac658fede\trefs/tags/0.7.0 -fa8097ff666af3ce64761d8e1f1c2aa292a11378\trefs/tags/0.7.2 -44f9be0b33ba5c10027ddb030a5b2f0faa3eeb8d\trefs/tags/0.7.4 -d7b9957f67236fa54e660cc3ab45ffecd6e0ba38\trefs/tags/0.7.8 -b7d19519a1c15f1c1a324e2683bd728b6198ce5a\trefs/tags/0.7.8^{} -ebc1b392fe7e8f0fbabc305c299b4d365d2b4d9b\trefs/tags/chef-server-package -SHAS - @resource.revision '' - @provider.should_receive(:shell_out!).with(@git_ls_remote + "\"HEAD\"", {:log_tag=>"git[web2.0 app]"}).and_return(double("ShellOut result", :stdout => @stdout)) - @provider.target_revision.should eql("28af684d8460ba4793eda3e7ac238c864a5d029a") - end - end - - it "responds to :revision_slug as an alias for target_revision" do - @provider.should respond_to(:revision_slug) - end - - context "with an ssh wrapper" do - let(:deploy_user) { "deployNinja" } - let(:wrapper) { "do_it_this_way.sh" } - let(:expected_cmd) { 'git clone "git://github.com/opscode/chef.git" "/my/deploy/dir"' } - let(:default_options) do - { - :user => deploy_user, - :environment => { "GIT_SSH" => wrapper, "HOME" => "/home/deployNinja" }, - :log_tag => "git[web2.0 app]" - } - end - before do - @resource.user deploy_user - @resource.ssh_wrapper wrapper - Etc.stub(:getpwnam).and_return(double("Struct::Passwd", :name => @resource.user, :dir => "/home/deployNinja")) - end - context "without a timeout set" do - it "clones a repo with default git options" do - @provider.should_receive(:shell_out!).with(expected_cmd, default_options) - @provider.clone - end - end - context "with a timeout set" do - let (:seconds) { 10 } - before { @resource.timeout(seconds) } - it "clones a repo with amended git options" do - @provider.should_receive(:shell_out!).with(expected_cmd, default_options.merge(:timeout => seconds)) - @provider.clone - end - end - context "with a specific home" do - let (:override_home) do - {"HOME" => "/home/masterNinja"} - end - let(:overrided_options) do - { - :user => deploy_user, - :environment => { "GIT_SSH" => wrapper, "HOME" => "/home/masterNinja" }, - :log_tag => "git[web2.0 app]" - } - end - before do - @resource.environment(override_home) - end - before { @resource.environment(override_home) } - it "clones a repo with amended git options with specific home" do - @provider.should_receive(:shell_out!).with(expected_cmd, overrided_options) - @provider.clone - end - end - end - - it "runs a clone command with escaped destination" do - @resource.user "deployNinja" - Etc.stub(:getpwnam).and_return(double("Struct::Passwd", :name => @resource.user, :dir => "/home/deployNinja")) - @resource.destination "/Application Support/with/space" - @resource.ssh_wrapper "do_it_this_way.sh" - expected_cmd = "git clone \"git://github.com/opscode/chef.git\" \"/Application Support/with/space\"" - @provider.should_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]") - @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') - version_response.stub(:stdout) { 'git version 1.7.9' } - @provider.should_receive(:shell_out!).with("git --version", - :log_tag => "git[web2.0 app]").and_return(version_response) - @provider.should_receive(:shell_out!).with(expected_cmd, :log_tag => "git[web2.0 app]") - @provider.clone - end - - 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') - version_response.stub(:stdout) { 'git version 1.7.10' } - @provider.should_receive(:shell_out!).with("git --version", - :log_tag => "git[web2.0 app]").and_return(version_response) - @provider.should_receive(:shell_out!).with(expected_cmd, :log_tag => "git[web2.0 app]") - @provider.clone - end - - it "compiles a clone command with a remote other than ``origin''" do - @resource.remote "opscode" - expected_cmd = "git clone -o opscode \"git://github.com/opscode/chef.git\" \"/my/deploy/dir\"" - @provider.should_receive(:shell_out!).with(expected_cmd, :log_tag => "git[web2.0 app]") - @provider.clone - end - - it "runs a checkout command with default options" do - @provider.should_receive(:shell_out!).with('git branch -f deploy d35af14d41ae22b19da05d7d03a0bafc321b244c', :cwd => "/my/deploy/dir", - :log_tag => "git[web2.0 app]").ordered - @provider.should_receive(:shell_out!).with('git checkout deploy', :cwd => "/my/deploy/dir", - :log_tag => "git[web2.0 app]").ordered - @provider.checkout - end - - it "runs an enable_submodule command" do - @resource.enable_submodules true - expected_cmd = "git submodule sync" - @provider.should_receive(:shell_out!).with(expected_cmd, :cwd => "/my/deploy/dir", - :log_tag => "git[web2.0 app]") - expected_cmd = "git submodule update --init --recursive" - @provider.should_receive(:shell_out!).with(expected_cmd, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]") - @provider.enable_submodules - end - - it "does nothing for enable_submodules if resource.enable_submodules #=> false" do - @provider.should_not_receive(:shell_out!) - @provider.enable_submodules - end - - it "runs a sync command with default options" do - @provider.should_receive(:setup_remote_tracking_branches).with(@resource.remote, @resource.repository) - expected_cmd = "git fetch origin && git fetch origin --tags && git reset --hard d35af14d41ae22b19da05d7d03a0bafc321b244c" - @provider.should_receive(:shell_out!).with(expected_cmd, :cwd=> "/my/deploy/dir", :log_tag => "git[web2.0 app]") - @provider.fetch_updates - end - - it "runs a sync command with the user and group specified in the resource" do - @resource.user("whois") - Etc.stub(:getpwnam).and_return(double("Struct::Passwd", :name => @resource.user, :dir => "/home/whois")) - @resource.group("thisis") - @provider.should_receive(:setup_remote_tracking_branches).with(@resource.remote, @resource.repository) - expected_cmd = "git fetch origin && git fetch origin --tags && git reset --hard d35af14d41ae22b19da05d7d03a0bafc321b244c" - @provider.should_receive(:shell_out!).with(expected_cmd, :cwd => "/my/deploy/dir", - :user => "whois", :group => "thisis", - :log_tag => "git[web2.0 app]", - :environment=>{"HOME"=>"/home/whois"}) - @provider.fetch_updates - end - - it "configures remote tracking branches when remote is ``origin''" do - @resource.remote "origin" - @provider.should_receive(:setup_remote_tracking_branches).with(@resource.remote, @resource.repository) - fetch_command = "git fetch origin && git fetch origin --tags && git reset --hard d35af14d41ae22b19da05d7d03a0bafc321b244c" - @provider.should_receive(:shell_out!).with(fetch_command, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]") - @provider.fetch_updates - end - - it "configures remote tracking branches when remote is not ``origin''" do - @resource.remote "opscode" - @provider.should_receive(:setup_remote_tracking_branches).with(@resource.remote, @resource.repository) - fetch_command = "git fetch opscode && git fetch opscode --tags && git reset --hard d35af14d41ae22b19da05d7d03a0bafc321b244c" - @provider.should_receive(:shell_out!).with(fetch_command, :cwd => "/my/deploy/dir", :log_tag => "git[web2.0 app]") - @provider.fetch_updates - end - - context "configuring remote tracking branches" do - - it "checks if a remote with this name already exists" do - command_response = double('shell_out') - command_response.stub(:exitstatus) { 1 } - expected_command = "git config --get remote.#{@resource.remote}.url" - @provider.should_receive(:shell_out!).with(expected_command, - :cwd => "/my/deploy/dir", - :log_tag => "git[web2.0 app]", - :returns => [0,1,2]).and_return(command_response) - add_remote_command = "git remote add #{@resource.remote} #{@resource.repository}" - @provider.should_receive(:shell_out!).with(add_remote_command, - :cwd => "/my/deploy/dir", - :log_tag => "git[web2.0 app]") - @provider.setup_remote_tracking_branches(@resource.remote, @resource.repository) - end - - it "runs the config with the user and group specified in the resource" do - @resource.user("whois") - @resource.group("thisis") - Etc.stub(:getpwnam).and_return(double("Struct::Passwd", :name => @resource.user, :dir => "/home/whois")) - command_response = double('shell_out') - command_response.stub(:exitstatus) { 1 } - expected_command = "git config --get remote.#{@resource.remote}.url" - @provider.should_receive(:shell_out!).with(expected_command, - :cwd => "/my/deploy/dir", - :log_tag => "git[web2.0 app]", - :user => "whois", - :group => "thisis", - :environment=>{"HOME"=>"/home/whois"}, - :returns => [0,1,2]).and_return(command_response) - add_remote_command = "git remote add #{@resource.remote} #{@resource.repository}" - @provider.should_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"}) - @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.stub(:exitstatus) { 1 } - check_remote_command = "git config --get remote.#{@resource.remote}.url" - @provider.should_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) - expected_command = "git remote add #{@resource.remote} #{@resource.repository}" - @provider.should_receive(:shell_out!).with(expected_command, - :cwd => "/my/deploy/dir", - :log_tag => "git[web2.0 app]") - @provider.setup_remote_tracking_branches(@resource.remote, @resource.repository) - end - end - - 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.stub(:exitstatus) { 0 } - command_response.stub(:stdout) { "some_other_url" } - check_remote_command = "git config --get remote.#{@resource.remote}.url" - @provider.should_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) - expected_command = "git config --replace-all remote.#{@resource.remote}.url #{@resource.repository}" - @provider.should_receive(:shell_out!).with(expected_command, - :cwd => "/my/deploy/dir", - :log_tag => "git[web2.0 app]") - @provider.setup_remote_tracking_branches(@resource.remote, @resource.repository) - end - - it "doesn't update remote url when the url is the same" do - command_response = double('shell_out') - command_response.stub(:exitstatus) { 0 } - command_response.stub(:stdout) { @resource.repository } - check_remote_command = "git config --get remote.#{@resource.remote}.url" - @provider.should_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) - unexpected_command = "git config --replace-all remote.#{@resource.remote}.url #{@resource.repository}" - @provider.should_not_receive(:shell_out!).with(unexpected_command, - :cwd => "/my/deploy/dir", - :log_tag => "git[web2.0 app]") - @provider.setup_remote_tracking_branches(@resource.remote, @resource.repository) - end - - it "resets remote url when it has multiple values" do - command_response = double('shell_out') - command_response.stub(:exitstatus) { 2 } - check_remote_command = "git config --get remote.#{@resource.remote}.url" - @provider.should_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) - expected_command = "git config --replace-all remote.#{@resource.remote}.url #{@resource.repository}" - @provider.should_receive(:shell_out!).with(expected_command, - :cwd => "/my/deploy/dir", - :log_tag => "git[web2.0 app]") - @provider.setup_remote_tracking_branches(@resource.remote, @resource.repository) - end - end - end - - it "raises an error if the git clone command would fail because the enclosing directory doesn't exist" do - @provider.stub(:shell_out!) - lambda {@provider.run_action(:sync)}.should raise_error(Chef::Exceptions::MissingParentDirectory) - end - - it "does a checkout by cloning the repo and then enabling submodules" do - # will be invoked in load_current_resource - ::File.stub(:exist?).with("/my/deploy/dir/.git").and_return(false) - - ::File.stub(:exist?).with("/my/deploy/dir").and_return(true) - ::File.stub(:directory?).with("/my/deploy").and_return(true) - ::Dir.stub(:entries).with("/my/deploy/dir").and_return(['.','..']) - @provider.should_receive(:clone) - @provider.should_receive(:checkout) - @provider.should_receive(:enable_submodules) - @provider.run_action(:checkout) - # Even though an actual run will cause an update to occur, the fact that we've stubbed out - # the actions above will prevent updates from registering - # @resource.should be_updated - end - - it "does not call checkout if enable_checkout is false" do - # will be invoked in load_current_resource - ::File.stub(:exist?).with("/my/deploy/dir/.git").and_return(false) - - ::File.stub(:exist?).with("/my/deploy/dir").and_return(true) - ::File.stub(:directory?).with("/my/deploy").and_return(true) - ::Dir.stub(:entries).with("/my/deploy/dir").and_return(['.','..']) - - @resource.enable_checkout false - @provider.should_receive(:clone) - @provider.should_not_receive(:checkout) - @provider.should_receive(:enable_submodules) - @provider.run_action(:checkout) - end - - # REGRESSION TEST: on some OSes, the entries from an empty directory will be listed as - # ['..', '.'] but this shouldn't change the behavior - it "does a checkout by cloning the repo and then enabling submodules when the directory entries are listed as %w{.. .}" do - ::File.stub(:exist?).with("/my/deploy/dir/.git").and_return(false) - ::File.stub(:exist?).with("/my/deploy/dir").and_return(false) - ::File.stub(:directory?).with("/my/deploy").and_return(true) - ::Dir.stub(:entries).with("/my/deploy/dir").and_return(['..','.']) - @provider.should_receive(:clone) - @provider.should_receive(:checkout) - @provider.should_receive(:enable_submodules) - @provider.should_receive(:add_remotes) - @provider.run_action(:checkout) - # @resource.should be_updated - end - - it "should not checkout if the destination exists or is a non empty directory" do - # will be invoked in load_current_resource - ::File.stub(:exist?).with("/my/deploy/dir/.git").and_return(false) - - ::File.stub(:exist?).with("/my/deploy/dir").and_return(true) - ::File.stub(:directory?).with("/my/deploy").and_return(true) - ::Dir.stub(:entries).with("/my/deploy/dir").and_return(['.','..','foo','bar']) - @provider.should_not_receive(:clone) - @provider.should_not_receive(:checkout) - @provider.should_not_receive(:enable_submodules) - @provider.should_not_receive(:add_remotes) - @provider.run_action(:checkout) - @resource.should_not be_updated - end - - it "syncs the code by updating the source when the repo has already been checked out" do - ::File.should_receive(:exist?).with("/my/deploy/dir/.git").and_return(true) - ::File.stub(:directory?).with("/my/deploy").and_return(true) - @provider.should_receive(:find_current_revision).exactly(1).and_return('d35af14d41ae22b19da05d7d03a0bafc321b244c') - @provider.should_not_receive(:fetch_updates) - @provider.should_receive(:add_remotes) - @provider.run_action(:sync) - @resource.should_not be_updated - end - - it "marks the resource as updated when the repo is updated and gets a new version" do - ::File.should_receive(:exist?).with("/my/deploy/dir/.git").and_return(true) - ::File.stub(:directory?).with("/my/deploy").and_return(true) - # invoked twice - first time from load_current_resource - @provider.should_receive(:find_current_revision).exactly(1).and_return('d35af14d41ae22b19da05d7d03a0bafc321b244c') - @provider.stub(:target_revision).and_return('28af684d8460ba4793eda3e7ac238c864a5d029a') - @provider.should_receive(:fetch_updates) - @provider.should_receive(:enable_submodules) - @provider.should_receive(:add_remotes) - @provider.run_action(:sync) - # @resource.should be_updated - end - - it "does not fetch any updates if the remote revision matches the current revision" do - ::File.should_receive(:exist?).with("/my/deploy/dir/.git").and_return(true) - ::File.stub(:directory?).with("/my/deploy").and_return(true) - @provider.stub(:find_current_revision).and_return('d35af14d41ae22b19da05d7d03a0bafc321b244c') - @provider.stub(:target_revision).and_return('d35af14d41ae22b19da05d7d03a0bafc321b244c') - @provider.should_not_receive(:fetch_updates) - @provider.should_receive(:add_remotes) - @provider.run_action(:sync) - @resource.should_not be_updated - end - - it "clones the repo instead of fetching it if the deploy directory doesn't exist" do - ::File.stub(:directory?).with("/my/deploy").and_return(true) - ::File.should_receive(:exist?).with("/my/deploy/dir/.git").exactly(2).and_return(false) - @provider.should_receive(:action_checkout) - @provider.should_not_receive(:shell_out!) - @provider.run_action(:sync) - # @resource.should be_updated - end - - it "clones the repo instead of fetching updates if the deploy directory is empty" do - ::File.should_receive(:exist?).with("/my/deploy/dir/.git").exactly(2).and_return(false) - ::File.stub(:directory?).with("/my/deploy").and_return(true) - ::File.stub(:directory?).with("/my/deploy/dir").and_return(true) - @provider.stub(:sync_command).and_return("huzzah!") - @provider.should_receive(:action_checkout) - @provider.should_not_receive(:shell_out!).with("huzzah!", :cwd => "/my/deploy/dir") - @provider.run_action(:sync) - #@resource.should be_updated - end - - it "does an export by cloning the repo then removing the .git directory" do - @provider.should_receive(:action_checkout) - FileUtils.should_receive(:rm_rf).with(@resource.destination + "/.git") - @provider.run_action(:export) - @resource.should be_updated - end - - 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"}) - STDOUT.stub(:tty?).and_return(false) - command_response = double('shell_out') - command_response.stub(:exitstatus) { 0 } - @resource.additional_remotes.each_pair do |remote_name, remote_url| - @provider.should_receive(:setup_remote_tracking_branches).with(remote_name, remote_url) - end - @provider.add_remotes - end - end - - describe "calling multiple_remotes?" do - before(:each) do - @command_response = double('shell_out') - end - - describe "when check remote command returns with status 2" do - it "returns true" do - @command_response.stub(:exitstatus) { 2 } - @provider.multiple_remotes?(@command_response).should be_true - end - end - - describe "when check remote command returns with status 0" do - it "returns false" do - @command_response.stub(:exitstatus) { 0 } - @provider.multiple_remotes?(@command_response).should be_false - end - end - - describe "when check remote command returns with status 0" do - it "returns false" do - @command_response.stub(:exitstatus) { 1 } - @provider.multiple_remotes?(@command_response).should be_false - end - end - end - - describe "calling remote_matches?" do - before(:each) do - @command_response = double('shell_out') - end - - describe "when output of the check remote command matches the repository url" do - it "returns true" do - @command_response.stub(:exitstatus) { 0 } - @command_response.stub(:stdout) { @resource.repository } - @provider.remote_matches?(@resource.repository, @command_response).should be_true - end - end - - describe "when output of the check remote command doesn't match the repository url" do - it "returns false" do - @command_response.stub(:exitstatus) { 0 } - @command_response.stub(:stdout) { @resource.repository + "test" } - @provider.remote_matches?(@resource.repository, @command_response).should be_false - end - end - end -end diff --git a/spec/unit/provider/group/dscl_spec.rb b/spec/unit/provider/group/dscl_spec.rb deleted file mode 100644 index 8848a01bf2..0000000000 --- a/spec/unit/provider/group/dscl_spec.rb +++ /dev/null @@ -1,333 +0,0 @@ -# -# Author:: Dreamcat4 (<dreamcat4@gmail.com>) -# Copyright:: Copyright (c) 2009 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::Group::Dscl 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("aj") - @current_resource = Chef::Resource::Group.new("aj") - @provider = Chef::Provider::Group::Dscl.new(@new_resource, @run_context) - @provider.current_resource = @current_resource - @status = double("Process::Status", :exitstatus => 0) - @pid = 2342 - @stdin = StringIO.new - @stdout = StringIO.new("\n") - @stderr = StringIO.new("") - @provider.stub(:popen4).and_yield(@pid,@stdin,@stdout,@stderr).and_return(@status) - end - - it "should run popen4 with the supplied array of arguments appended to the dscl command" do - @provider.should_receive(:popen4).with("dscl . -cmd /Path arg1 arg2") - @provider.dscl("cmd", "/Path", "arg1", "arg2") - end - - it "should return an array of four elements - cmd, status, stdout, stderr" do - dscl_retval = @provider.dscl("cmd /Path args") - dscl_retval.should be_a_kind_of(Array) - dscl_retval.should == ["dscl . -cmd /Path args",@status,"\n",""] - end - - describe "safe_dscl" do - before do - @node = Chef::Node.new - @provider = Chef::Provider::Group::Dscl.new(@node, @new_resource) - @provider.stub(:dscl).and_return(["cmd", @status, "stdout", "stderr"]) - end - - it "should run dscl with the supplied cmd /Path args" do - @provider.should_receive(:dscl).with("cmd /Path args") - @provider.safe_dscl("cmd /Path args") - end - - describe "with the dscl command returning a non zero exit status for a delete" do - before do - @status = double("Process::Status", :exitstatus => 1) - @provider.stub(:dscl).and_return(["cmd", @status, "stdout", "stderr"]) - end - - it "should return an empty string of standard output for a delete" do - safe_dscl_retval = @provider.safe_dscl("delete /Path args") - safe_dscl_retval.should be_a_kind_of(String) - safe_dscl_retval.should == "" - end - - it "should raise an exception for any other command" do - lambda { @provider.safe_dscl("cmd /Path arguments") }.should raise_error(Chef::Exceptions::Group) - end - end - - describe "with the dscl command returning no such key" do - before do - @provider.stub(:dscl).and_return(["cmd", @status, "No such key: ", "stderr"]) - end - - it "should raise an exception" do - lambda { @provider.safe_dscl("cmd /Path arguments") }.should raise_error(Chef::Exceptions::Group) - end - end - - describe "with the dscl command returning a zero exit status" do - it "should return the third array element, the string of standard output" do - safe_dscl_retval = @provider.safe_dscl("cmd /Path args") - safe_dscl_retval.should be_a_kind_of(String) - safe_dscl_retval.should == "stdout" - end - end - end - - describe "get_free_gid" do - before do - @node = Chef::Node.new - @provider = Chef::Provider::Group::Dscl.new(@node, @new_resource) - @provider.stub(:safe_dscl).and_return("\naj 200\njt 201\n") - end - - it "should run safe_dscl with list /Groups gid" do - @provider.should_receive(:safe_dscl).with("list /Groups gid") - @provider.get_free_gid - end - - it "should return the first unused gid number on or above 200" do - @provider.get_free_gid.should equal(202) - end - - it "should raise an exception when the search limit is exhausted" do - search_limit = 1 - lambda { @provider.get_free_gid(search_limit) }.should raise_error(RuntimeError) - end - end - - describe "gid_used?" do - before do - @node = Chef::Node.new - @provider = Chef::Provider::Group::Dscl.new(@node, @new_resource) - @provider.stub(:safe_dscl).and_return("\naj 500\n") - end - - it "should run safe_dscl with list /Groups gid" do - @provider.should_receive(:safe_dscl).with("list /Groups gid") - @provider.gid_used?(500) - end - - it "should return true for a used gid number" do - @provider.gid_used?(500).should be_true - end - - it "should return false for an unused gid number" do - @provider.gid_used?(501).should be_false - end - - it "should return false if not given any valid gid number" do - @provider.gid_used?(nil).should be_false - end - end - - describe "set_gid" do - describe "with the new resource and a gid number which is already in use" do - before do - @provider.stub(:gid_used?).and_return(true) - end - - it "should raise an exception if the new resources gid is already in use" do - lambda { @provider.set_gid }.should raise_error(Chef::Exceptions::Group) - end - end - - describe "with no gid number for the new resources" do - it "should run get_free_gid and return a valid, unused gid number" do - @provider.should_receive(:get_free_gid).and_return(501) - @provider.set_gid - end - end - - describe "with blank gid number for the new resources" do - before do - @new_resource.instance_variable_set(:@gid, nil) - @new_resource.stub(:safe_dscl) - end - - it "should run get_free_gid and return a valid, unused gid number" do - @provider.should_receive(:get_free_gid).and_return(501) - @provider.set_gid - end - end - - describe "with a valid gid number which is not already in use" do - it "should run safe_dscl with create /Groups/group PrimaryGroupID gid" do - @provider.stub(:get_free_gid).and_return(50) - @provider.should_receive(:safe_dscl).with("list /Groups gid") - @provider.should_receive(:safe_dscl).with("create /Groups/aj PrimaryGroupID 50").and_return(true) - @provider.set_gid - end - end - end - - describe "set_members" do - - describe "with existing members in the current resource and append set to false in the new resource" do - before do - @new_resource.stub(:members).and_return([]) - @new_resource.stub(:append).and_return(false) - @current_resource.stub(:members).and_return(["all", "your", "base"]) - end - - it "should log an appropriate message" do - Chef::Log.should_receive(:debug).with("group[aj] removing group members all your base") - @provider.set_members - end - - it "should run safe_dscl with create /Groups/group GroupMembership to clear the Group's UID list" do - @provider.should_receive(:safe_dscl).with("create /Groups/aj GroupMembers ''").and_return(true) - @provider.should_receive(:safe_dscl).with("create /Groups/aj GroupMembership ''").and_return(true) - @provider.set_members - end - end - - describe "with supplied members in the new resource" do - before do - @new_resource.members(["all", "your", "base"]) - @current_resource.members([]) - end - - it "should log an appropriate debug message" do - Chef::Log.should_receive(:debug).with("group[aj] setting group members all, your, base") - @provider.set_members - end - - it "should run safe_dscl with append /Groups/group GroupMembership and group members all, your, base" do - @provider.should_receive(:safe_dscl).with("create /Groups/aj GroupMembers ''").and_return(true) - @provider.should_receive(:safe_dscl).with("append /Groups/aj GroupMembership all your base").and_return(true) - @provider.should_receive(:safe_dscl).with("create /Groups/aj GroupMembership ''").and_return(true) - @provider.set_members - end - end - - describe "with no members in the new resource" do - before do - @new_resource.append(true) - @new_resource.members([]) - end - - it "should not call safe_dscl" do - @provider.should_not_receive(:safe_dscl) - @provider.set_members - end - end - end - - describe "when loading the current system state" do - before (:each) do - @provider.action = :create - @provider.load_current_resource - @provider.define_resource_requirements - end - - it "raises an error if the required binary /usr/bin/dscl doesn't exist" do - File.should_receive(:exists?).with("/usr/bin/dscl").and_return(false) - - lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Group) - end - - it "doesn't raise an error if /usr/bin/dscl exists" do - File.stub(:exists?).and_return(true) - lambda { @provider.process_resource_requirements }.should_not raise_error - end - end - - describe "when creating the group" do - it "creates the group, password field, gid, and sets group membership" do - @provider.should_receive(:set_gid).and_return(true) - @provider.should_receive(:set_members).and_return(true) - @provider.should_receive(:safe_dscl).with("create /Groups/aj Password '*'") - @provider.should_receive(:safe_dscl).with("create /Groups/aj") - @provider.create_group - end - end - - describe "managing the group" do - it "should manage the group_name if it changed and the new resources group_name is not null" do - @current_resource.group_name("oldval") - @new_resource.group_name("newname") - @provider.should_receive(:set_members).and_return(true) - @provider.should_receive(:safe_dscl).with("create /Groups/newname") - @provider.should_receive(:safe_dscl).with("create /Groups/newname Password '*'") - @provider.manage_group - end - - it "should manage the gid if it changed and the new resources gid is not null" do - @current_resource.gid(23) - @new_resource.gid(42) - @provider.should_receive(:set_gid) - @provider.manage_group - end - - it "should manage the members if it changed and the new resources members is not null" do - @current_resource.members(%{charlie root}) - @new_resource.members(%{crab revenge}) - @provider.should_receive(:set_members) - @provider.manage_group - end - end - - describe "remove_group" do - it "should run safe_dscl with delete /Groups/group and with the new resources group name" do - @provider.should_receive(:safe_dscl).with("delete /Groups/aj").and_return(true) - @provider.remove_group - end - end -end - -describe 'Test DSCL loading' 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("aj") - @provider = Chef::Provider::Group::Dscl.new(@new_resource, @run_context) - @output = <<-EOF -AppleMetaNodeLocation: /Local/Default -Comment: - Test Group -GeneratedUID: AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA -NestedGroups: AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAB -Password: * -PrimaryGroupID: 999 -RealName: - TestGroup -RecordName: com.apple.aj -RecordType: dsRecTypeStandard:Groups -GroupMembership: waka bar -EOF - @provider.stub(:safe_dscl).with("read /Groups/aj").and_return(@output) - @current_resource = @provider.load_current_resource - - end - - it 'should parse gid properly' do - File.stub(:exists?).and_return(true) - @current_resource.gid.should eq("999") - end - it 'should parse members properly' do - File.stub(:exists?).and_return(true) - @current_resource.members.should eq(['waka', 'bar']) - end -end diff --git a/spec/unit/provider/group/gpasswd_spec.rb b/spec/unit/provider/group/gpasswd_spec.rb deleted file mode 100644 index 5bd7fdc569..0000000000 --- a/spec/unit/provider/group/gpasswd_spec.rb +++ /dev/null @@ -1,116 +0,0 @@ -# -# Author:: AJ Christensen (<aj@opscode.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' - -describe Chef::Provider::Group::Gpasswd, "modify_group_members" 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.members %w{lobster rage fist} - @new_resource.append false - @provider = Chef::Provider::Group::Gpasswd.new(@new_resource, @run_context) - #@provider.stub(:run_command).and_return(true) - end - - describe "when determining the current group state" do - before (:each) do - @provider.action = :create - @provider.load_current_resource - @provider.define_resource_requirements - end - - # Checking for required binaries is already done in the spec - # for Chef::Provider::Group - no need to repeat it here. We'll - # include only what's specific to this provider. - it "should raise an error if the required binary /usr/bin/gpasswd doesn't exist" do - File.stub(:exists?).and_return(true) - File.should_receive(:exists?).with("/usr/bin/gpasswd").and_return(false) - lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Group) - end - - it "shouldn't raise an error if the required binaries exist" do - File.stub(:exists?).and_return(true) - lambda { @provider.process_resource_requirements }.should_not raise_error - end - end - - describe "after the group's current state is known" do - before do - @current_resource = @new_resource.dup - @provider.current_resource = @new_resource - end - - describe "when no group members are specified and append is not set" do - before do - @new_resource.append(false) - @new_resource.members([]) - end - - it "logs a message and sets group's members to 'none'" do - Chef::Log.should_receive(:debug).with("group[wheel] setting group members to: none") - @provider.should_receive(:shell_out!).with("gpasswd -M \"\" wheel") - @provider.modify_group_members - end - end - - describe "when no group members are specified and append is set" do - before do - @new_resource.append(true) - @new_resource.members([]) - end - - it "does not modify group membership" do - @provider.should_not_receive(:shell_out!) - @provider.modify_group_members - end - end - - describe "when the resource specifies group members" do - it "should log an appropriate debug message" do - Chef::Log.should_receive(:debug).with("group[wheel] setting group members to: lobster, rage, fist") - @provider.stub(:shell_out!) - @provider.modify_group_members - end - - it "should run gpasswd with the members joined by ',' followed by the target group" do - @provider.should_receive(:shell_out!).with("gpasswd -M lobster,rage,fist wheel") - @provider.modify_group_members - end - - describe "when no user exists in the system" do - before do - current_resource = @new_resource.dup - current_resource.members([ ]) - @provider.current_resource = current_resource - end - - it "should run gpasswd individually for each user when the append option is set" do - @new_resource.append(true) - @provider.should_receive(:shell_out!).with("gpasswd -a lobster wheel") - @provider.should_receive(:shell_out!).with("gpasswd -a rage wheel") - @provider.should_receive(:shell_out!).with("gpasswd -a fist wheel") - @provider.modify_group_members - end - end - - end - end -end diff --git a/spec/unit/provider/group/groupadd_spec.rb b/spec/unit/provider/group/groupadd_spec.rb deleted file mode 100644 index 793615d04c..0000000000 --- a/spec/unit/provider/group/groupadd_spec.rb +++ /dev/null @@ -1,174 +0,0 @@ -# -# Author:: AJ Christensen (<aj@opscode.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' - -describe Chef::Provider::Group::Groupadd, "set_options" 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("aj") - @new_resource.gid(50) - @new_resource.members(["root", "aj"]) - @new_resource.system false - @new_resource.non_unique false - @current_resource = Chef::Resource::Group.new("aj") - @current_resource.gid(50) - @current_resource.members(["root", "aj"]) - @current_resource.system false - @current_resource.non_unique false - @provider = Chef::Provider::Group::Groupadd.new(@new_resource, @run_context) - @provider.current_resource = @current_resource - end - - field_list = { - :gid => "-g" - } - - field_list.each do |attribute, option| - it "should check for differences in #{attribute.to_s} between the current and new resources" do - @new_resource.should_receive(attribute) - @current_resource.should_receive(attribute) - @provider.set_options - end - it "should set the option for #{attribute} if the new resources #{attribute} is not null" do - @new_resource.stub(attribute).and_return("wowaweea") - @provider.set_options.should eql(" #{option} '#{@new_resource.send(attribute)}' #{@new_resource.group_name}") - end - end - - it "should combine all the possible options" do - match_string = "" - field_list.sort{ |a,b| a[0] <=> b[0] }.each do |attribute, option| - @new_resource.stub(attribute).and_return("hola") - match_string << " #{option} 'hola'" - end - match_string << " aj" - @provider.set_options.should eql(match_string) - end - - describe "when we want to create a system group" do - it "should not set groupadd_options '-r' when system is false" do - @new_resource.system(false) - @provider.groupadd_options.should_not =~ /-r/ - end - - it "should set groupadd -r if system is true" do - @new_resource.system(true) - @provider.groupadd_options.should == " -r" - end - end - - describe "when we want to create a non_unique gid group" do - it "should not set groupadd_options '-o' when non_unique is false" do - @new_resource.non_unique(false) - @provider.groupadd_options.should_not =~ /-o/ - end - - it "should set groupadd -o if non_unique is true" do - @new_resource.non_unique(true) - @provider.groupadd_options.should == " -o" - end - end -end - -describe Chef::Provider::Group::Groupadd, "create_group" do - before do - @node = Chef::Node.new - @new_resource = Chef::Resource::Group.new("aj") - @provider = Chef::Provider::Group::Groupadd.new(@node, @new_resource) - @provider.stub(:run_command).and_return(true) - @provider.stub(:set_options).and_return(" monkey") - @provider.stub(:groupadd_options).and_return("") - @provider.stub(:modify_group_members).and_return(true) - end - - it "should run groupadd with the return of set_options" do - @provider.should_receive(:run_command).with({ :command => "groupadd monkey" }).and_return(true) - @provider.create_group - end - - it "should modify the group members" do - @provider.should_receive(:modify_group_members).and_return(true) - @provider.create_group - end -end - -describe Chef::Provider::Group::Groupadd 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("aj") - @provider = Chef::Provider::Group::Groupadd.new(@new_resource, @run_context) - @provider.stub(:run_command).and_return(true) - @provider.stub(:set_options).and_return(" monkey") - end - - describe "manage group" do - - it "should run groupmod with the return of set_options" do - @provider.stub(:modify_group_members).and_return(true) - @provider.should_receive(:run_command).with({ :command => "groupmod monkey" }).and_return(true) - @provider.manage_group - end - - it "should modify the group members" do - @provider.should_receive(:modify_group_members).and_return(true) - @provider.manage_group - end - end - - describe "remove_group" do - - it "should run groupdel with the new resources group name" do - @provider.should_receive(:run_command).with({ :command => "groupdel aj" }).and_return(true) - @provider.remove_group - end - end - - [:add_member, :remove_member, :set_members].each do |m| - it "should raise an error when calling #{m}" do - lambda { @provider.send(m, [ ]) }.should raise_error(Chef::Exceptions::Group, "you must override #{m} in #{@provider.to_s}") - end - end - - describe "load_current_resource" do - before do - File.stub(:exists?).and_return(false) - @provider.define_resource_requirements - end - it "should raise an error if the required binary /usr/sbin/groupadd doesn't exist" do - File.should_receive(:exists?).with("/usr/sbin/groupadd").and_return(false) - lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Group) - end - it "should raise an error if the required binary /usr/sbin/groupmod doesn't exist" do - File.should_receive(:exists?).with("/usr/sbin/groupadd").and_return(true) - File.should_receive(:exists?).with("/usr/sbin/groupmod").and_return(false) - lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Group) - end - it "should raise an error if the required binary /usr/sbin/groupdel doesn't exist" do - File.should_receive(:exists?).with("/usr/sbin/groupadd").and_return(true) - File.should_receive(:exists?).with("/usr/sbin/groupmod").and_return(true) - File.should_receive(:exists?).with("/usr/sbin/groupdel").and_return(false) - lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Group) - end - - end -end diff --git a/spec/unit/provider/group/groupmod_spec.rb b/spec/unit/provider/group/groupmod_spec.rb deleted file mode 100644 index 001f9c66e8..0000000000 --- a/spec/unit/provider/group/groupmod_spec.rb +++ /dev/null @@ -1,133 +0,0 @@ -# -# Author:: Dan Crosta (<dcrosta@late.am>) -# 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::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 - - describe "manage_group" do - describe "when determining the current group state" do - it "should raise an error if the required binary /usr/sbin/group doesn't exist" do - File.should_receive(:exists?).with("/usr/sbin/group").and_return(false) - lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Group) - end - it "should raise an error if the required binary /usr/sbin/user doesn't exist" do - File.should_receive(:exists?).with("/usr/sbin/group").and_return(true) - File.should_receive(:exists?).with("/usr/sbin/user").and_return(false) - lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Group) - end - - it "shouldn't raise an error if the required binaries exist" do - File.stub(:exists?).and_return(true) - lambda { @provider.load_current_resource }.should_not raise_error - end - end - - describe "after the group's current state is known" do - before do - @current_resource = @new_resource.dup - @provider.current_resource = @current_resource - end - - describe "when no group members are specified and append is not set" do - before do - @new_resource.append(false) - @new_resource.members([]) - end - - it "logs a message and sets group's members to 'none', then removes existing group members" do - Chef::Log.should_receive(:debug).with("group[wheel] setting group members to: none") - @provider.should_receive(:shell_out!).with("group mod -n wheel_bak wheel") - @provider.should_receive(:shell_out!).with("group add -g '123' -o wheel") - @provider.should_receive(:shell_out!).with("group del wheel_bak") - @provider.manage_group - end - end - - describe "when no group members are specified and append is set" do - before do - @new_resource.append(true) - @new_resource.members([]) - end - - it "logs a message and does not modify group membership" do - Chef::Log.should_receive(:debug).with("group[wheel] not changing group members, the group has no members to add") - @provider.should_not_receive(:shell_out!) - @provider.manage_group - end - end - - describe "when removing some group members" do - before do - @new_resource.append(false) - @new_resource.members(%w{ lobster }) - end - - it "updates group membership correctly" do - Chef::Log.stub(:debug) - @provider.should_receive(:shell_out!).with("group mod -n wheel_bak wheel") - @provider.should_receive(:shell_out!).with("user mod -G wheel lobster") - @provider.should_receive(:shell_out!).with("group add -g '123' -o wheel") - @provider.should_receive(:shell_out!).with("group del wheel_bak") - @provider.manage_group - end - end - end - end - - describe "create_group" do - describe "when creating a new group" do - before do - @current_resource = Chef::Resource::Group.new("wheel") - @provider.current_resource = @current_resource - end - - it "should run a group add command and some user mod commands" do - @provider.should_receive(:shell_out!).with("group add -g '123' wheel") - @provider.should_receive(:shell_out!).with("user mod -G wheel lobster") - @provider.should_receive(:shell_out!).with("user mod -G wheel rage") - @provider.should_receive(:shell_out!).with("user mod -G wheel fist") - @provider.create_group - end - end - end - - describe "remove_group" do - describe "when removing an existing group" do - before do - @current_resource = @new_resource.dup - @provider.current_resource = @current_resource - end - - it "should run a group del command" do - @provider.should_receive(:shell_out!).with("group del wheel") - @provider.remove_group - end - end - end -end diff --git a/spec/unit/provider/group/pw_spec.rb b/spec/unit/provider/group/pw_spec.rb deleted file mode 100644 index fdc2e35746..0000000000 --- a/spec/unit/provider/group/pw_spec.rb +++ /dev/null @@ -1,138 +0,0 @@ -# -# Author:: Stephen Haynes (<sh@nomitor.com>) -# Copyright:: Copyright (c) 2009 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::Group::Pw 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 50 - @new_resource.members [ "root", "aj"] - - @current_resource = Chef::Resource::Group.new("aj") - @current_resource.gid 50 - @current_resource.members [ "root", "aj"] - @provider = Chef::Provider::Group::Pw.new(@new_resource, @run_context) - @provider.current_resource = @current_resource - end - - describe "when setting options for the pw command" do - it "does not set the gid option if gids match or are unmanaged" do - @provider.set_options.should == " wheel" - end - - it "sets the option for gid if it is not nil" do - @new_resource.gid(42) - @provider.set_options.should eql(" wheel -g '42'") - end - end - - describe "when creating a group" do - it "should run pw groupadd with the return of set_options and set_members_option" do - @new_resource.gid(23) - @provider.should_receive(:run_command).with({ :command => "pw groupadd wheel -g '23' -M root,aj" }).and_return(true) - @provider.create_group - end - end - - describe "when managing the group" do - - it "should run pw groupmod with the return of set_options" do - @new_resource.gid(42) - @new_resource.members(["someone"]) - @provider.should_receive(:run_command).with({ :command => "pw groupmod wheel -g '42' -m someone" }).and_return(true) - @provider.should_receive(:run_command).with({ :command => "pw groupmod wheel -g '42' -d root,aj" }).and_return(true) - @provider.manage_group - end - - end - - describe "when removing the group" do - it "should run pw groupdel with the new resources group name" do - @provider.should_receive(:run_command).with({ :command => "pw groupdel wheel" }).and_return(true) - @provider.remove_group - end - end - - describe "when setting group membership" do - - describe "with an empty members array in both the new and current resource" do - before do - @new_resource.stub(:members).and_return([]) - @current_resource.stub(:members).and_return([]) - end - - it "should set no options" do - @provider.set_members_options.should eql([ ]) - end - end - - describe "with an empty members array in the new resource and existing members in the current resource" do - before do - @new_resource.stub(:members).and_return([]) - @current_resource.stub(:members).and_return(["all", "your", "base"]) - end - - it "should log an appropriate message" do - Chef::Log.should_receive(:debug).with("group[wheel] removing group members: all,your,base") - @provider.set_members_options - end - - it "should set the -d option with the members joined by ','" do - @provider.set_members_options.should eql([ " -d all,your,base" ]) - end - end - - describe "with supplied members array in the new resource and an empty members array in the current resource" do - before do - @new_resource.stub(:members).and_return(["all", "your", "base"]) - @current_resource.stub(:members).and_return([]) - end - - it "should log an appropriate debug message" do - Chef::Log.should_receive(:debug).with("group[wheel] adding group members: all,your,base") - @provider.set_members_options - end - - it "should set the -m option with the members joined by ','" do - @provider.set_members_options.should eql([ " -m all,your,base" ]) - end - end - end - - describe"load_current_resource" do - before (:each) do - @provider.action = :create - @provider.load_current_resource - @provider.define_resource_requirements - end - it "should raise an error if the required binary /usr/sbin/pw doesn't exist" do - File.should_receive(:exists?).with("/usr/sbin/pw").and_return(false) - lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Group) - end - - it "shouldn't raise an error if /usr/sbin/pw exists" do - File.stub(:exists?).and_return(true) - lambda { @provider.process_resource_requirements }.should_not raise_error - end - end -end diff --git a/spec/unit/provider/group/usermod_spec.rb b/spec/unit/provider/group/usermod_spec.rb deleted file mode 100644 index bd9eac4ede..0000000000 --- a/spec/unit/provider/group/usermod_spec.rb +++ /dev/null @@ -1,115 +0,0 @@ -# -# Author:: AJ Christensen (<aj@opscode.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' - -describe Chef::Provider::Group::Usermod 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.members [ "all", "your", "base" ] - @new_resource.excluded_members [ ] - @provider = Chef::Provider::Group::Usermod.new(@new_resource, @run_context) - @provider.stub(:run_command) - end - - describe "modify_group_members" do - - describe "with an empty members array" do - before do - @new_resource.stub(:append).and_return(true) - @new_resource.stub(:members).and_return([]) - end - - it "should log an appropriate message" do - @provider.should_not_receive(:shell_out!) - @provider.modify_group_members - end - end - - describe "with supplied members" do - platforms = { - "openbsd" => "-G", - "netbsd" => "-G", - "solaris" => "-a -G", - "suse" => "-a -G", - "opensuse" => "-a -G", - "smartos" => "-G", - "omnios" => "-G" - } - - before do - @new_resource.stub(:members).and_return(["all", "your", "base"]) - File.stub(:exists?).and_return(true) - end - - it "should raise an error when setting the entire group directly" do - @provider.define_resource_requirements - @provider.load_current_resource - @provider.instance_variable_set("@group_exists", true) - @provider.action = :modify - lambda { @provider.run_action(@provider.process_resource_requirements) }.should raise_error(Chef::Exceptions::Group, "setting group members directly is not supported by #{@provider.to_s}, must set append true in group") - end - - it "should raise an error when excluded_members are set" do - @provider.define_resource_requirements - @provider.load_current_resource - @provider.instance_variable_set("@group_exists", true) - @provider.action = :modify - @new_resource.stub(:append).and_return(true) - @new_resource.stub(:excluded_members).and_return(["someone"]) - lambda { @provider.run_action(@provider.process_resource_requirements) }.should raise_error(Chef::Exceptions::Group, "excluded_members is not supported by #{@provider.to_s}") - end - - platforms.each do |platform, flags| - it "should usermod each user when the append option is set on #{platform}" do - current_resource = @new_resource.dup - current_resource.members([ ]) - @provider.current_resource = current_resource - @node.automatic_attrs[:platform] = platform - @new_resource.stub(:append).and_return(true) - @provider.should_receive(:shell_out!).with("usermod #{flags} wheel all") - @provider.should_receive(:shell_out!).with("usermod #{flags} wheel your") - @provider.should_receive(:shell_out!).with("usermod #{flags} wheel base") - @provider.modify_group_members - end - end - end - end - - describe "when loading the current resource" do - before(:each) do - File.stub(:exists?).and_return(false) - @provider.action = :create - @provider.define_resource_requirements - end - - it "should raise an error if the required binary /usr/sbin/usermod doesn't exist" do - File.stub(:exists?).and_return(true) - File.should_receive(:exists?).with("/usr/sbin/usermod").and_return(false) - lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Group) - end - - it "shouldn't raise an error if the required binaries exist" do - File.stub(:exists?).and_return(true) - lambda { @provider.process_resource_requirements }.should_not raise_error - end - end -end diff --git a/spec/unit/provider/group/windows_spec.rb b/spec/unit/provider/group/windows_spec.rb deleted file mode 100644 index 6888c750f5..0000000000 --- a/spec/unit/provider/group/windows_spec.rb +++ /dev/null @@ -1,101 +0,0 @@ -# -# Author:: Doug MacEachern (<dougm@vmware.com>) -# Copyright:: Copyright (c) 2010 VMware, 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 Chef - class Util - class Windows - class NetGroup - end - end - end -end - -describe Chef::Provider::Group::Windows 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("staff") - @net_group = double("Chef::Util::Windows::NetGroup") - Chef::Util::Windows::NetGroup.stub(:new).and_return(@net_group) - @provider = Chef::Provider::Group::Windows.new(@new_resource, @run_context) - end - - describe "when creating the group" do - it "should call @net_group.local_add" do - @net_group.should_receive(:local_set_members).with([]) - @net_group.should_receive(:local_add) - @provider.create_group - end - end - - describe "manage_group" do - before do - @new_resource.members([ "us" ]) - @current_resource = Chef::Resource::Group.new("staff") - @current_resource.members [ "all", "your", "base" ] - - Chef::Util::Windows::NetGroup.stub(:new).and_return(@net_group) - @net_group.stub(:local_add_members) - @net_group.stub(:local_set_members) - @provider.stub(:local_group_name_to_sid) - @provider.current_resource = @current_resource - end - - it "should call @net_group.local_set_members" do - @new_resource.stub(:append).and_return(false) - @net_group.should_receive(:local_set_members).with(@new_resource.members) - @provider.manage_group - end - - it "should call @net_group.local_add_members" do - @new_resource.stub(:append).and_return(true) - @net_group.should_receive(:local_add_members).with(@new_resource.members) - @provider.manage_group - end - - end - - describe "remove_group" do - before do - Chef::Util::Windows::NetGroup.stub(:new).and_return(@net_group) - @provider.stub(:run_command).and_return(true) - end - - it "should call @net_group.local_delete" do - @net_group.should_receive(:local_delete) - @provider.remove_group - end - end -end - -describe Chef::Provider::Group::Windows, "NetGroup" 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("Creating a new group") - @new_resource.group_name "Remote Desktop Users" - end - it 'sets group_name correctly' do - Chef::Util::Windows::NetGroup.should_receive(:new).with("Remote Desktop Users") - Chef::Provider::Group::Windows.new(@new_resource, @run_context) - end -end diff --git a/spec/unit/provider/group_spec.rb b/spec/unit/provider/group_spec.rb deleted file mode 100644 index e467da751f..0000000000 --- a/spec/unit/provider/group_spec.rb +++ /dev/null @@ -1,286 +0,0 @@ -# -# Author:: AJ Christensen (<aj@opscode.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' - -describe Chef::Provider::User 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", @run_context) - @new_resource.gid 500 - @new_resource.members "aj" - - @provider = Chef::Provider::Group.new(@new_resource, @run_context) - - @current_resource = Chef::Resource::Group.new("aj", @run_context) - @current_resource.gid 500 - @current_resource.members "aj" - - @provider.current_resource = @current_resource - - @pw_group = double("Struct::Group", - :name => "wheel", - :gid => 20, - :mem => [ "root", "aj" ] - ) - Etc.stub(:getgrnam).with('wheel').and_return(@pw_group) - end - - it "assumes the group exists by default" do - @provider.group_exists.should be_true - end - - describe "when establishing the current state of the group" do - - it "sets the group name of the current resource to the group name of the new resource" do - @provider.load_current_resource - @provider.current_resource.group_name.should == 'wheel' - end - - it "does not modify the desired gid if set" do - @provider.load_current_resource - @new_resource.gid.should == 500 - end - - it "sets the desired gid to the current gid if none is set" do - @new_resource.instance_variable_set(:@gid, nil) - @provider.load_current_resource - @new_resource.gid.should == 20 - end - - it "looks up the group in /etc/group with getgrnam" do - Etc.should_receive(:getgrnam).with(@new_resource.group_name).and_return(@pw_group) - @provider.load_current_resource - @provider.current_resource.gid.should == 20 - @provider.current_resource.members.should == %w{root aj} - end - - it "should flip the value of exists if it cannot be found in /etc/group" do - Etc.stub(:getgrnam).and_raise(ArgumentError) - @provider.load_current_resource - @provider.group_exists.should be_false - end - - it "should return the current resource" do - @provider.load_current_resource.should equal(@provider.current_resource) - end - end - - describe "when determining if the system is already in the target state" do - [ :gid, :members ].each do |attribute| - it "should return true if #{attribute} doesn't match" do - @current_resource.stub(attribute).and_return("looooooooooooooooooool") - @provider.compare_group.should be_true - end - end - - it "should return false if gid and members are equal" do - @provider.compare_group.should be_false - end - - it "should coerce an integer to a string for comparison" do - @current_resource.stub(:gid).and_return("500") - @provider.compare_group.should be_false - end - - it "should return false if append is true and the group member(s) already exists" do - @current_resource.members << "extra_user" - @new_resource.stub(:append).and_return(true) - @provider.compare_group.should be_false - end - - it "should return true if append is true and the group member(s) do not already exist" do - @new_resource.members << "extra_user" - @new_resource.stub(:append).and_return(true) - @provider.compare_group.should be_true - end - - it "should return false if append is true and excluded_members include a non existing member" do - @new_resource.excluded_members << "extra_user" - @new_resource.stub(:append).and_return(true) - @provider.compare_group.should be_false - 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.clear - @new_resource.stub(:append).and_return(true) - @provider.compare_group.should be_true - end - - end - - describe "when creating a group" do - it "should call create_group if the group does not exist" do - @provider.group_exists = false - @provider.should_receive(:create_group).and_return(true) - @provider.run_action(:create) - end - - it "should set the new_resources updated flag when it creates the group" do - @provider.group_exists = false - @provider.stub(:create_group) - @provider.run_action(:create) - @provider.new_resource.should be_updated - end - - it "should check to see if the group has mismatched attributes if the group exists" do - @provider.group_exists = true - @provider.stub(:compare_group).and_return(false) - @provider.stub(:change_desc).and_return([ ]) - @provider.run_action(:create) - @provider.new_resource.should_not be_updated - end - - it "should call manage_group if the group exists and has mismatched attributes" do - @provider.group_exists = true - @provider.stub(:compare_group).and_return(true) - @provider.stub(:change_desc).and_return([ ]) - @provider.should_receive(:manage_group).and_return(true) - @provider.run_action(:create) - end - - it "should set the new_resources updated flag when it creates the group if we call manage_group" do - @provider.group_exists = true - @provider.stub(:compare_group).and_return(true) - @provider.stub(:change_desc).and_return(["Some changes are going to be done."]) - @provider.stub(:manage_group).and_return(true) - @provider.run_action(:create) - @new_resource.should be_updated - end - end - - describe "when removing a group" do - - it "should not call remove_group if the group does not exist" do - @provider.group_exists = false - @provider.should_not_receive(:remove_group) - @provider.run_action(:remove) - @provider.new_resource.should_not be_updated - end - - it "should call remove_group if the group exists" do - @provider.group_exists = true - @provider.should_receive(:remove_group) - @provider.run_action(:remove) - @provider.new_resource.should be_updated - end - end - - describe "when updating a group" do - before(:each) do - @provider.group_exists = true - @provider.stub(:manage_group).and_return(true) - end - - it "should run manage_group if the group exists and has mismatched attributes" do - @provider.should_receive(:compare_group).and_return(true) - @provider.stub(:change_desc).and_return(["Some changes are going to be done."]) - @provider.should_receive(:manage_group).and_return(true) - @provider.run_action(:manage) - end - - it "should set the new resources updated flag to true if manage_group is called" do - @provider.stub(:compare_group).and_return(true) - @provider.stub(:change_desc).and_return(["Some changes are going to be done."]) - @provider.stub(:manage_group).and_return(true) - @provider.run_action(:manage) - @new_resource.should be_updated - end - - it "should not run manage_group if the group does not exist" do - @provider.group_exists = false - @provider.should_not_receive(:manage_group) - @provider.run_action(:manage) - end - - it "should not run manage_group if the group exists but has no differing attributes" do - @provider.should_receive(:compare_group).and_return(false) - @provider.stub(:change_desc).and_return(["Some changes are going to be done."]) - @provider.should_not_receive(:manage_group) - @provider.run_action(:manage) - end - end - - describe "when modifying the group" do - before(:each) do - @provider.group_exists = true - @provider.stub(:manage_group).and_return(true) - end - - it "should run manage_group if the group exists and has mismatched attributes" do - @provider.should_receive(:compare_group).and_return(true) - @provider.stub(:change_desc).and_return(["Some changes are going to be done."]) - @provider.should_receive(:manage_group).and_return(true) - @provider.run_action(:modify) - end - - it "should set the new resources updated flag to true if manage_group is called" do - @provider.stub(:compare_group).and_return(true) - @provider.stub(:change_desc).and_return(["Some changes are going to be done."]) - @provider.stub(:manage_group).and_return(true) - @provider.run_action(:modify) - @new_resource.should be_updated - end - - it "should not run manage_group if the group exists but has no differing attributes" do - @provider.should_receive(:compare_group).and_return(false) - @provider.stub(:change_desc).and_return(["Some changes are going to be done."]) - @provider.should_not_receive(:manage_group) - @provider.run_action(:modify) - end - - it "should raise a Chef::Exceptions::Group if the group doesn't exist" do - @provider.group_exists = false - lambda { @provider.run_action(:modify) }.should raise_error(Chef::Exceptions::Group) - end - end - - 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" - @new_resource.stub(:append).and_return true - @provider.compare_group.should be_true - @provider.change_desc.should == [ "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" - @new_resource.stub(:append).and_return false - @provider.compare_group.should be_true - @provider.change_desc.should == [ "replace group members with new list of members" ] - end - - it "should report the gid will be changed when it does not match" do - @current_resource.stub(:gid).and_return("BADF00D") - @provider.compare_group.should be_true - @provider.change_desc.should == [ "change gid #{@current_resource.gid} to #{@new_resource.gid}" ] - - end - - it "should report no change reason when no change is required" do - @provider.compare_group.should be_false - @provider.change_desc.should == [ ] - end - end - -end diff --git a/spec/unit/provider/http_request_spec.rb b/spec/unit/provider/http_request_spec.rb deleted file mode 100644 index 3077685b97..0000000000 --- a/spec/unit/provider/http_request_spec.rb +++ /dev/null @@ -1,159 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef::Provider::HttpRequest do - before(:each) do - @node = Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - - @new_resource = Chef::Resource::HttpRequest.new('adam') - @new_resource.name "adam" - @new_resource.url "http://www.opscode.com/" - @new_resource.message "is cool" - - @provider = Chef::Provider::HttpRequest.new(@new_resource, @run_context) - end - - describe "load_current_resource" do - - it "should set up a Chef::REST client, with no authentication" do - Chef::HTTP::Simple.should_receive(:new).with(@new_resource.url) - @provider.load_current_resource - end - end - - describe "when making REST calls" do - before(:each) do - # run_action(x) forces load_current_resource to run; - # that would overwrite our supplied mock Chef::Rest # object - @provider.stub(:load_current_resource).and_return(true) - @http = double("Chef::REST") - @provider.http = @http - end - - describe "action_get" do - - it "should inflate a message block at runtime" do - @new_resource.message { "return" } - @http.should_receive(:get).with("http://www.opscode.com/", {}) - @provider.run_action(:get) - @new_resource.should be_updated - end - - it "should run a GET request" do - @http.should_receive(:get).with("http://www.opscode.com/", {}) - @provider.run_action(:get) - @new_resource.should be_updated - end - end - - describe "action_put" do - it "should run a PUT request with the message as the payload" do - @http.should_receive(:put).with("http://www.opscode.com/", @new_resource.message, {}) - @provider.run_action(:put) - @new_resource.should be_updated - end - - it "should inflate a message block at runtime" do - @new_resource.stub(:message).and_return(lambda { "return" }) - @http.should_receive(:put).with("http://www.opscode.com/", "return", {}) - @provider.run_action(:put) - @new_resource.should be_updated - end - end - - describe "action_post" do - it "should run a PUT request with the message as the payload" do - @http.should_receive(:post).with("http://www.opscode.com/", @new_resource.message, {}) - @provider.run_action(:post) - @new_resource.should be_updated - end - - it "should inflate a message block at runtime" do - @new_resource.message { "return" } - @http.should_receive(:post).with("http://www.opscode.com/", "return", {}) - @provider.run_action(:post) - @new_resource.should be_updated - end - end - - describe "action_delete" do - it "should run a DELETE request" do - @http.should_receive(:delete).with("http://www.opscode.com/", {}) - @provider.run_action(:delete) - @new_resource.should be_updated - end - end - - # CHEF-4762: we expect a nil return value for a "200 Success" response - # and false for a "304 Not Modified" response - describe "action_head" do - before do - @provider.http = @http - end - - it "should inflate a message block at runtime" do - @new_resource.message { "return" } - @http.should_receive(:head).with("http://www.opscode.com/", {}).and_return(nil) - @provider.run_action(:head) - @new_resource.should be_updated - end - - it "should run a HEAD request" do - @http.should_receive(:head).with("http://www.opscode.com/", {}).and_return(nil) - @provider.run_action(:head) - @new_resource.should be_updated - end - - it "should update a HEAD request with empty string response body (CHEF-4762)" do - @http.should_receive(:head).with("http://www.opscode.com/", {}).and_return("") - @provider.run_action(:head) - @new_resource.should be_updated - end - - it "should update a HEAD request with nil response body (CHEF-4762)" do - @http.should_receive(:head).with("http://www.opscode.com/", {}).and_return(nil) - @provider.run_action(:head) - @new_resource.should be_updated - end - - 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 - @http.should_receive(:head).with("http://www.opscode.com/", {"If-Modified-Since" => if_modified_since}).and_return(false) - @provider.run_action(:head) - @new_resource.should_not be_updated - end - - it "should run a HEAD request with If-Modified-Since header" do - @new_resource.headers "If-Modified-Since" => File.mtime(__FILE__).httpdate - @http.should_receive(:head).with("http://www.opscode.com/", @new_resource.headers) - @provider.run_action(:head) - end - - it "doesn't call converge_by if HEAD does not return modified" do - @http.should_receive(:head).and_return(false) - @provider.should_not_receive(:converge_by) - @provider.run_action(:head) - end - end - end -end diff --git a/spec/unit/provider/ifconfig/aix_spec.rb b/spec/unit/provider/ifconfig/aix_spec.rb deleted file mode 100644 index 24f5fb18f3..0000000000 --- a/spec/unit/provider/ifconfig/aix_spec.rb +++ /dev/null @@ -1,180 +0,0 @@ -# -# Author:: Kaustubh Deorukhkar (<kaustubh@clogeny.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' -require 'chef/exceptions' - -describe Chef::Provider::Ifconfig::Aix do - - before(:all) do - @ifconfig_output = <<-IFCONFIG -en1: flags=1e080863,480<UP,BROADCAST,NOTRAILERS,RUNNING,SIMPLEX,MULTICAST,GROUPRT,64BIT,CHECKSUM_OFFLOAD(ACTIVE),CHAIN> - inet 10.153.11.59 netmask 0xffff0000 broadcast 10.153.255.255 - tcp_sendspace 262144 tcp_recvspace 262144 rfc1323 1 -en0: flags=1e080863,480<UP,BROADCAST,NOTRAILERS,RUNNING,SIMPLEX,MULTICAST,GROUPRT,64BIT,CHECKSUM_OFFLOAD(ACTIVE),CHAIN> metric 1 - inet 172.29.174.58 netmask 0xffffc000 broadcast 172.29.191.255 - tcp_sendspace 262144 tcp_recvspace 262144 rfc1323 1 -lo0: flags=e08084b,c0<UP,BROADCAST,LOOPBACK,RUNNING,SIMPLEX,MULTICAST,GROUPRT,64BIT,LARGESEND,CHAIN> - inet 127.0.0.1 netmask 0xff000000 broadcast 127.255.255.255 - inet6 ::1%1/0 -IFCONFIG - end - - - before(:each) do - @node = Chef::Node.new - @cookbook_collection = Chef::CookbookCollection.new([]) - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events) - - @new_resource = Chef::Resource::Ifconfig.new("10.0.0.1", @run_context) - - @provider = Chef::Provider::Ifconfig::Aix.new(@new_resource, @run_context) - end - - describe "#load_current_resource" do - before do - status = double("Status", :exitstatus => 0) - @provider.should_receive(:popen4).with("ifconfig -a").and_yield(@pid,@stdin,StringIO.new(@ifconfig_output),@stderr).and_return(status) - @new_resource.device "en0" - end - it "should load given interface with attributes." do - current_resource = @provider.load_current_resource - expect(current_resource.inet_addr).to eq("172.29.174.58") - expect(current_resource.target).to eq(@new_resource.target) - expect(current_resource.mask).to eq("255.255.192.0") - expect(current_resource.bcast).to eq("172.29.191.255") - expect(current_resource.metric).to eq("1") - end - end - - describe "#action_add" do - - it "should add an interface if it does not exist" do - @new_resource.device "en10" - @provider.stub(:load_current_resource) do - @provider.instance_variable_set("@status", double("Status", :exitstatus => 0)) - @provider.instance_variable_set("@current_resource", Chef::Resource::Ifconfig.new("10.0.0.1", @run_context)) - end - command = "chdev -l #{@new_resource.device} -a netaddr=#{@new_resource.name}" - @provider.should_receive(:run_command).with(:command => command) - - @provider.run_action(:add) - @new_resource.should be_updated - end - - it "should raise exception if metric attribute is set" do - @new_resource.device "en0" - @new_resource.metric "1" - @provider.stub(:load_current_resource) do - @provider.instance_variable_set("@status", double("Status", :exitstatus => 0)) - @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") - end - end - - describe "#action_enable" do - it "should enable an interface if it does not exist" do - @new_resource.device "en10" - @provider.stub(:load_current_resource) do - @provider.instance_variable_set("@status", double("Status", :exitstatus => 0)) - @provider.instance_variable_set("@current_resource", Chef::Resource::Ifconfig.new("10.0.0.1", @run_context)) - end - command = "ifconfig #{@new_resource.device} #{@new_resource.name}" - @provider.should_receive(:run_command).with(:command => command) - - @provider.run_action(:enable) - @new_resource.should be_updated - end - end - - describe "#action_disable" do - - it "should not disable an interface if it does not exist" do - @new_resource.device "en10" - @provider.stub(:load_current_resource) do - @provider.instance_variable_set("@status", double("Status", :exitstatus => 0)) - @provider.instance_variable_set("@current_resource", Chef::Resource::Ifconfig.new("10.0.0.1", @run_context)) - end - - @provider.should_not_receive(:run_command) - - @provider.run_action(:disable) - @new_resource.should_not be_updated - end - - context "interface exists" do - before do - @new_resource.device "en10" - @provider.stub(:load_current_resource) do - @provider.instance_variable_set("@status", double("Status", :exitstatus => 0)) - current_resource = Chef::Resource::Ifconfig.new("10.0.0.1", @run_context) - current_resource.device @new_resource.device - @provider.instance_variable_set("@current_resource", current_resource) - end - end - - it "should disable an interface if it exists" do - command = "ifconfig #{@new_resource.device} down" - @provider.should_receive(:run_command).with(:command => command) - - @provider.run_action(:disable) - @new_resource.should be_updated - end - - end - end - - describe "#action_delete" do - - it "should not delete an interface if it does not exist" do - @new_resource.device "en10" - @provider.stub(:load_current_resource) do - @provider.instance_variable_set("@status", double("Status", :exitstatus => 0)) - @provider.instance_variable_set("@current_resource", Chef::Resource::Ifconfig.new("10.0.0.1", @run_context)) - end - - @provider.should_not_receive(:run_command) - - @provider.run_action(:delete) - @new_resource.should_not be_updated - end - - context "interface exists" do - before do - @new_resource.device "en10" - @provider.stub(:load_current_resource) do - @provider.instance_variable_set("@status", double("Status", :exitstatus => 0)) - current_resource = Chef::Resource::Ifconfig.new("10.0.0.1", @run_context) - current_resource.device @new_resource.device - @provider.instance_variable_set("@current_resource", current_resource) - end - end - - it "should delete an interface if it exists" do - command = "chdev -l #{@new_resource.device} -a state=down" - @provider.should_receive(:run_command).with(:command => command) - - @provider.run_action(:delete) - @new_resource.should be_updated - end - end - end -end diff --git a/spec/unit/provider/ifconfig/debian_spec.rb b/spec/unit/provider/ifconfig/debian_spec.rb deleted file mode 100644 index ebb16e22af..0000000000 --- a/spec/unit/provider/ifconfig/debian_spec.rb +++ /dev/null @@ -1,354 +0,0 @@ -# -# Author:: Xabier de Zuazo (xabier@onddo.com) -# Copyright:: Copyright (c) 2013 Onddo Labs, SL. -# 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' - -describe Chef::Provider::Ifconfig::Debian do - - let(:run_context) do - node = Chef::Node.new - cookbook_collection = Chef::CookbookCollection.new([]) - events = Chef::EventDispatch::Dispatcher.new - Chef::RunContext.new(node, cookbook_collection, events) - end - - let(:new_resource) do - new_resource = Chef::Resource::Ifconfig.new("10.0.0.1", run_context) - new_resource.mask "255.255.254.0" - new_resource.metric "1" - new_resource.mtu "1500" - new_resource.device "eth0" - new_resource - end - - let(:current_resource) { Chef::Resource::Ifconfig.new("10.0.0.1", run_context) } - - let(:provider) do - status = double("Status", :exitstatus => 0) - provider = Chef::Provider::Ifconfig::Debian.new(new_resource, run_context) - provider.instance_variable_set("@status", status) - provider.current_resource = current_resource - allow(provider).to receive(:load_current_resource) - allow(provider).to receive(:run_command) - provider - end - - let(:config_filename_ifaces) { "/etc/network/interfaces" } - - let(:config_filename_ifcfg) { "/etc/network/interfaces.d/ifcfg-#{new_resource.device}" } - - describe "generate_config" do - - context "when writing a file" do - let(:tempfile) { Tempfile.new("rspec-chef-ifconfig-debian") } - - let(:tempdir_path) { Dir.mktmpdir("rspec-chef-ifconfig-debian-dir") } - - let(:config_filename_ifcfg) { "#{tempdir_path}/ifcfg-#{new_resource.device}" } - - before do - stub_const("Chef::Provider::Ifconfig::Debian::INTERFACES_FILE", tempfile.path) - stub_const("Chef::Provider::Ifconfig::Debian::INTERFACES_DOT_D_DIR", tempdir_path) - end - - it "should write a network-script" do - provider.run_action(:add) - expect(File.read(config_filename_ifcfg)).to match(/^iface eth0 inet static\s*$/) - expect(File.read(config_filename_ifcfg)).to match(/^\s+address 10\.0\.0\.1\s*$/) - expect(File.read(config_filename_ifcfg)).to match(/^\s+netmask 255\.255\.254\.0\s*$/) - end - - context "when the interface_dot_d directory does not exist" do - before do - FileUtils.rmdir tempdir_path - expect(File.exists?(tempdir_path)).to be_false - end - - it "should create the /etc/network/interfaces.d directory" do - provider.run_action(:add) - expect(File.exists?(tempdir_path)).to be_true - expect(File.directory?(tempdir_path)).to be_true - end - - it "should mark the resource as updated" do - provider.run_action(:add) - expect(new_resource.updated_by_last_action?).to be_true - end - end - - context "when the interface_dot_d directory exists" do - before do - expect(File.exists?(tempdir_path)).to be_true - end - - it "should still mark the resource as updated (we still write a file to it)" do - provider.run_action(:add) - expect(new_resource.updated_by_last_action?).to be_true - end - end - end - - context "when the file is up-to-date" do - let(:tempfile) { Tempfile.new("rspec-chef-ifconfig-debian") } - - let(:tempdir_path) { Dir.mktmpdir("rspec-chef-ifconfig-debian-dir") } - - let(:config_filename_ifcfg) { "#{tempdir_path}/ifcfg-#{new_resource.device}" } - - before do - stub_const("Chef::Provider::Ifconfig::Debian::INTERFACES_FILE", tempfile.path) - stub_const("Chef::Provider::Ifconfig::Debian::INTERFACES_DOT_D_DIR", tempdir_path) - config_file_ifcfg = StringIO.new(<<-EOF -iface eth0 inet static - address 10.0.0.1 - netmask 255.255.254.0 -EOF - ) - expect(File.exists?(tempdir_path)).to be_true # since the file exists, the enclosing dir must also exist - end - - context "when the /etc/network/interfaces file has the source line" do - let(:expected_string) do - <<-EOF -a line -source #{tempdir_path}/* -another line -EOF - end - - before do - tempfile.write(expected_string) - tempfile.close - - expect(provider).not_to receive(:converge_by).with(/modifying #{tempfile.path} to source #{tempdir_path}/) - end - - it "should preserve all the contents" do - provider.run_action(:add) - 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_false - end - end - - context "when the /etc/network/interfaces file does not have the source line" do - let(:expected_string) do - <<-EOF -a line -another line -source #{tempdir_path}/* -EOF - end - - before do - tempfile.write("a line\nanother line\n") - tempfile.close - - allow(provider).to receive(:converge_by).and_call_original - expect(provider).to receive(:converge_by).with(/modifying #{tempfile.path} to source #{tempdir_path}/).and_call_original - end - - it "should preserve the original contents and add the source line" do - provider.run_action(:add) - expect(IO.read(tempfile.path)).to eq(expected_string) - end - - it "should mark the resource as updated" do - provider.run_action(:add) - expect(new_resource.updated_by_last_action?).to be_true - end - end - end - - describe "when running under why run" do - - before do - Chef::Config[:why_run] = true - end - - after do - Chef::Config[:why_run] = false - end - - context "when writing a file" do - let(:config_file_ifcfg) { StringIO.new } - - let(:tempfile) { Tempfile.new("rspec-chef-ifconfig-debian") } - - let(:tempdir_path) { Dir.mktmpdir("rspec-chef-ifconfig-debian-dir") } - - let(:config_filename_ifcfg) { "#{tempdir_path}/ifcfg-#{new_resource.device}" } - - before do - stub_const("Chef::Provider::Ifconfig::Debian::INTERFACES_FILE", tempfile.path) - stub_const("Chef::Provider::Ifconfig::Debian::INTERFACES_DOT_D_DIR", tempdir_path) - expect(File).not_to receive(:new).with(config_filename_ifcfg, "w") - end - - it "should write a network-script" do - provider.run_action(:add) - expect(config_file_ifcfg.string).not_to match(/^iface eth0 inet static\s*$/) - expect(config_file_ifcfg.string).not_to match(/^\s+address 10\.0\.0\.1\s*$/) - expect(config_file_ifcfg.string).not_to match(/^\s+netmask 255\.255\.254\.0\s*$/) - end - - context "when the interface_dot_d directory does not exist" do - before do - FileUtils.rmdir tempdir_path - expect(File.exists?(tempdir_path)).to be_false - end - - it "should not create the /etc/network/interfaces.d directory" do - provider.run_action(:add) - expect(File.exists?(tempdir_path)).not_to be_true - end - - it "should mark the resource as updated" do - provider.run_action(:add) - expect(new_resource.updated_by_last_action?).to be_true - end - end - - context "when the interface_dot_d directory exists" do - before do - expect(File.exists?(tempdir_path)).to be_true - end - - it "should still mark the resource as updated (we still write a file to it)" do - provider.run_action(:add) - expect(new_resource.updated_by_last_action?).to be_true - end - end - end - - context "when the file is up-to-date" do - let(:tempfile) { Tempfile.new("rspec-chef-ifconfig-debian") } - - let(:tempdir_path) { Dir.mktmpdir("rspec-chef-ifconfig-debian-dir") } - - let(:config_filename_ifcfg) { "#{tempdir_path}/ifcfg-#{new_resource.device}" } - - before do - stub_const("Chef::Provider::Ifconfig::Debian::INTERFACES_FILE", tempfile.path) - stub_const("Chef::Provider::Ifconfig::Debian::INTERFACES_DOT_D_DIR", tempdir_path) - config_file_ifcfg = StringIO.new(<<-EOF -iface eth0 inet static - address 10.0.0.1 - netmask 255.255.254.0 - EOF - ) - expect(File).not_to receive(:new).with(config_filename_ifcfg, "w") - expect(File.exists?(tempdir_path)).to be_true # since the file exists, the enclosing dir must also exist - end - - context "when the /etc/network/interfaces file has the source line" do - let(:expected_string) do - <<-EOF -a line -source #{tempdir_path}/* -another line - EOF - end - - before do - tempfile.write(expected_string) - tempfile.close - end - - it "should preserve all the contents" do - provider.run_action(:add) - 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_false - end - end - - context "when the /etc/network/interfaces file does not have the source line" do - let(:expected_string) do - <<-EOF -a line -another line -source #{tempdir_path}/* - EOF - end - - before do - tempfile.write("a line\nanother line\n") - tempfile.close - end - - it "should preserve the original contents and not add the source line" do - provider.run_action(:add) - expect(IO.read(tempfile.path)).to eq("a line\nanother line\n") - end - - it "should mark the resource as updated" do - provider.run_action(:add) - expect(new_resource.updated_by_last_action?).to be_true - end - end - end - end - end - - describe "delete_config for action_delete" do - - let(:tempfile) { Tempfile.new("rspec-chef-ifconfig-debian") } - - let(:tempdir_path) { Dir.mktmpdir("rspec-chef-ifconfig-debian-dir") } - - let(:config_filename_ifcfg) { "#{tempdir_path}/ifcfg-#{new_resource.device}" } - - before do - stub_const("Chef::Provider::Ifconfig::Debian::INTERFACES_FILE", tempfile.path) - stub_const("Chef::Provider::Ifconfig::Debian::INTERFACES_DOT_D_DIR", tempdir_path) - File.open(config_filename_ifcfg, "w") do |fh| - fh.write "arbitrary text\n" - fh.close - end - end - - after do - Dir.rmdir(tempdir_path) - end - - it "should delete network-script if it exists" do - current_resource.device new_resource.device - - # belt and suspenders testing? - Chef::Util::Backup.any_instance.should_receive(:do_backup).and_call_original - - # internal implementation detail of Ifconfig. - Chef::Provider::File.any_instance.should_receive(:action_delete).and_call_original - - expect(File.exist?(config_filename_ifcfg)).to be_true - provider.run_action(:delete) - expect(File.exist?(config_filename_ifcfg)).to be_false - end - end - -end diff --git a/spec/unit/provider/ifconfig/redhat_spec.rb b/spec/unit/provider/ifconfig/redhat_spec.rb deleted file mode 100644 index 138c2a389d..0000000000 --- a/spec/unit/provider/ifconfig/redhat_spec.rb +++ /dev/null @@ -1,73 +0,0 @@ -# -# Author:: Xabier de Zuazo (xabier@onddo.com) -# Copyright:: Copyright (c) 2013 Onddo Labs, SL. -# 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' - -describe Chef::Provider::Ifconfig::Redhat do - before do - @node = Chef::Node.new - @cookbook_collection = Chef::CookbookCollection.new([]) - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events) - #This new_resource can be called anything --> it is not the same as in ifconfig.rb - @new_resource = Chef::Resource::Ifconfig.new("10.0.0.1", @run_context) - @new_resource.mask "255.255.254.0" - @new_resource.metric "1" - @new_resource.mtu "1500" - @new_resource.device "eth0" - @provider = Chef::Provider::Ifconfig::Redhat.new(@new_resource, @run_context) - @current_resource = Chef::Resource::Ifconfig.new("10.0.0.1", @run_context) - - status = double("Status", :exitstatus => 0) - @provider.instance_variable_set("@status", status) - @provider.current_resource = @current_resource - - config_filename = "/etc/sysconfig/network-scripts/ifcfg-#{@new_resource.device}" - @config = double("chef-resource-file") - @provider.should_receive(:resource_for_config).with(config_filename).and_return(@config) - end - - describe "generate_config for action_add" do - - it "should write network-script for centos" do - @provider.stub(:load_current_resource) - @provider.stub(:run_command) - @config.should_receive(:content) do |arg| - arg.should match(/^\s*DEVICE=eth0\s*$/) - arg.should match(/^\s*IPADDR=10\.0\.0\.1\s*$/) - arg.should match(/^\s*NETMASK=255\.255\.254\.0\s*$/) - end - @config.should_receive(:run_action).with(:create) - @config.should_receive(:updated?).and_return(true) - @provider.run_action(:add) - end - end - - describe "delete_config for action_delete" do - - it "should delete network-script if it exists for centos" do - @current_resource.device @new_resource.device - @provider.stub(:load_current_resource) - @provider.stub(:run_command) - @config.should_receive(:run_action).with(:delete) - @config.should_receive(:updated?).and_return(true) - @provider.run_action(:delete) - end - end -end diff --git a/spec/unit/provider/ifconfig_spec.rb b/spec/unit/provider/ifconfig_spec.rb deleted file mode 100644 index b09e365c65..0000000000 --- a/spec/unit/provider/ifconfig_spec.rb +++ /dev/null @@ -1,180 +0,0 @@ -# -# Author:: Prajakta Purohit (prajakta@opscode.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 File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper")) -require 'spec_helper' -require 'chef/exceptions' - -describe Chef::Provider::Ifconfig do - before do - @node = Chef::Node.new - @cookbook_collection = Chef::CookbookCollection.new([]) - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events) - #This new_resource can be called anything --> it is not the same as in ifconfig.rb - @new_resource = Chef::Resource::Ifconfig.new("10.0.0.1", @run_context) - @new_resource.mask "255.255.254.0" - @new_resource.metric "1" - @new_resource.mtu "1500" - @new_resource.device "eth0" - @provider = Chef::Provider::Ifconfig.new(@new_resource, @run_context) - @current_resource = Chef::Resource::Ifconfig.new("10.0.0.1", @run_context) - - status = double("Status", :exitstatus => 0) - @provider.instance_variable_set("@status", status) - @provider.current_resource = @current_resource - - end - describe Chef::Provider::Ifconfig, "load_current_resource" do - before do - status = double("Status", :exitstatus => 1) - @provider.should_receive(:popen4).and_return status - @provider.load_current_resource - end - it "should track state of ifconfig failure." do - @provider.instance_variable_get("@status").exitstatus.should_not == 0 - end - it "should thrown an exception when ifconfig fails" do - @provider.define_resource_requirements - lambda { @provider.process_resource_requirements }.should raise_error Chef::Exceptions::Ifconfig - end - end - describe Chef::Provider::Ifconfig, "action_add" do - - it "should add an interface if it does not exist" do - #@provider.stub(:run_command).and_return(true) - @provider.stub(:load_current_resource) - @current_resource.inet_addr nil - command = "ifconfig eth0 10.0.0.1 netmask 255.255.254.0 metric 1 mtu 1500" - @provider.should_receive(:run_command).with(:command => command) - @provider.should_receive(:generate_config) - - @provider.run_action(:add) - @new_resource.should be_updated - end - - it "should not add an interface if it already exists" do - @provider.stub(:load_current_resource) - @provider.should_not_receive(:run_command) - @current_resource.inet_addr "10.0.0.1" - @provider.should_receive(:generate_config) - - @provider.run_action(:add) - @new_resource.should_not be_updated - end - - #We are not testing this case with the assumption that anyone writing the cookbook would not make a typo == lo - #it "should add a blank command if the #{@new_resource.device} == lo" do - #end - end - - describe Chef::Provider::Ifconfig, "action_enable" do - - it "should enable interface if does not exist" do - @provider.stub(:load_current_resource) - @current_resource.inet_addr nil - command = "ifconfig eth0 10.0.0.1 netmask 255.255.254.0 metric 1 mtu 1500" - @provider.should_receive(:run_command).with(:command => command) - @provider.should_not_receive(:generate_config) - - @provider.run_action(:enable) - @new_resource.should be_updated - end - - it "should not enable interface if it already exists" do - @provider.stub(:load_current_resource) - @provider.should_not_receive(:run_command) - @current_resource.inet_addr "10.0.0.1" - @provider.should_not_receive(:generate_config) - - @provider.run_action(:enable) - @new_resource.should_not be_updated - end - end - - describe Chef::Provider::Ifconfig, "action_delete" do - - it "should delete interface if it exists" do - @provider.stub(:load_current_resource) - @current_resource.device "eth0" - command = "ifconfig #{@new_resource.device} down" - @provider.should_receive(:run_command).with(:command => command) - @provider.should_receive(:delete_config) - - @provider.run_action(:delete) - @new_resource.should be_updated - end - - it "should not delete interface if it does not exist" do - @provider.stub(:load_current_resource) - @provider.should_not_receive(:run_command) - @provider.should_receive(:delete_config) - - @provider.run_action(:delete) - @new_resource.should_not be_updated - end - end - - describe Chef::Provider::Ifconfig, "action_disable" do - - it "should disable interface if it exists" do - @provider.stub(:load_current_resource) - @current_resource.device "eth0" - command = "ifconfig #{@new_resource.device} down" - @provider.should_receive(:run_command).with(:command => command) - @provider.should_not_receive(:delete_config) - - @provider.run_action(:disable) - @new_resource.should be_updated - end - - it "should not delete interface if it does not exist" do - @provider.stub(:load_current_resource) - @provider.should_not_receive(:run_command) - @provider.should_not_receive(:delete_config) - - @provider.run_action(:disable) - @new_resource.should_not be_updated - end - end - - describe Chef::Provider::Ifconfig, "action_delete" do - - it "should delete interface of it exists" do - @provider.stub(:load_current_resource) - @current_resource.device "eth0" - command = "ifconfig #{@new_resource.device} down" - @provider.should_receive(:run_command).with(:command => command) - @provider.should_receive(:delete_config) - - @provider.run_action(:delete) - @new_resource.should be_updated - end - - it "should not delete interface if it does not exist" do - # This is so that our fake values do not get overwritten - @provider.stub(:load_current_resource) - # This is so that nothing actually runs - @provider.should_not_receive(:run_command) - @provider.should_receive(:delete_config) - - @provider.run_action(:delete) - @new_resource.should_not be_updated - end - end -end diff --git a/spec/unit/provider/link_spec.rb b/spec/unit/provider/link_spec.rb deleted file mode 100644 index 2f0a5f2020..0000000000 --- a/spec/unit/provider/link_spec.rb +++ /dev/null @@ -1,252 +0,0 @@ -# -# Author:: AJ Christensen (<aj@junglist.gen.nz>) -# Author:: John Keiser (<jkeiser@opscode.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 'ostruct' - -require 'spec_helper' - -if Chef::Platform.windows? - require 'chef/win32/file' #probably need this in spec_helper -end - -describe Chef::Resource::Link, :not_supported_on_win2k3 do - let(:provider) do - node = Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - run_context = Chef::RunContext.new(node, {}, @events) - Chef::Provider::Link.new(new_resource, run_context) - end - let(:new_resource) do - result = Chef::Resource::Link.new("#{CHEF_SPEC_DATA}/fofile-link") - result.to "#{CHEF_SPEC_DATA}/fofile" - result - end - - def paths_eql?(path1, path2) - Chef::Util::PathHelper.paths_eql?(path1, path2) - end - - describe "when the target is a symlink" do - before(:each) do - lstat = double("stats", :ino => 5) - lstat.stub(:uid).and_return(501) - lstat.stub(:gid).and_return(501) - lstat.stub(:mode).and_return(0777) - File.stub(:lstat).with("#{CHEF_SPEC_DATA}/fofile-link").and_return(lstat) - provider.file_class.stub(:symlink?).with("#{CHEF_SPEC_DATA}/fofile-link").and_return(true) - provider.file_class.stub(:readlink).with("#{CHEF_SPEC_DATA}/fofile-link").and_return("#{CHEF_SPEC_DATA}/fofile") - end - - describe "to a file that exists" do - before do - File.stub(:exist?).with("#{CHEF_SPEC_DATA}/fofile-link").and_return(true) - new_resource.owner 501 # only loaded in current_resource if present in new - new_resource.group 501 - provider.load_current_resource - end - - it "should set the symlink target" do - provider.current_resource.target_file.should == "#{CHEF_SPEC_DATA}/fofile-link" - end - it "should set the link type" do - provider.current_resource.link_type.should == :symbolic - end - it "should update the source of the existing link with the links target" do - paths_eql?(provider.current_resource.to, "#{CHEF_SPEC_DATA}/fofile").should be_true - end - it "should set the owner" do - provider.current_resource.owner.should == 501 - end - it "should set the group" do - provider.current_resource.group.should == 501 - end - - # 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 - 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 - provider.access_controls.should_not_receive(:set_all) - provider.run_action(:create) - end - end - end - - describe "to a file that doesn't exist" do - before do - File.stub(:exist?).with("#{CHEF_SPEC_DATA}/fofile-link").and_return(false) - provider.file_class.stub(:symlink?).with("#{CHEF_SPEC_DATA}/fofile-link").and_return(true) - provider.file_class.stub(:readlink).with("#{CHEF_SPEC_DATA}/fofile-link").and_return("#{CHEF_SPEC_DATA}/fofile") - new_resource.owner "501" # only loaded in current_resource if present in new - new_resource.group "501" - provider.load_current_resource - end - - it "should set the symlink target" do - provider.current_resource.target_file.should == "#{CHEF_SPEC_DATA}/fofile-link" - end - it "should set the link type" do - provider.current_resource.link_type.should == :symbolic - end - it "should update the source of the existing link to the link's target" do - paths_eql?(provider.current_resource.to, "#{CHEF_SPEC_DATA}/fofile").should be_true - end - it "should not set the owner" do - provider.current_resource.owner.should be_nil - end - it "should not set the group" do - provider.current_resource.group.should be_nil - end - end - end - - describe "when the target doesn't exist" do - before do - File.stub(:exists?).with("#{CHEF_SPEC_DATA}/fofile-link").and_return(false) - provider.file_class.stub(:symlink?).with("#{CHEF_SPEC_DATA}/fofile-link").and_return(false) - provider.load_current_resource - end - - it "should set the symlink target" do - provider.current_resource.target_file.should == "#{CHEF_SPEC_DATA}/fofile-link" - end - it "should update the source of the existing link to nil" do - provider.current_resource.to.should be_nil - end - it "should not set the owner" do - provider.current_resource.owner.should == nil - end - it "should not set the group" do - provider.current_resource.group.should == nil - end - end - - describe "when the target is a regular old file" do - before do - stat = double("stats", :ino => 5) - stat.stub(:uid).and_return(501) - stat.stub(:gid).and_return(501) - stat.stub(:mode).and_return(0755) - provider.file_class.stub(:stat).with("#{CHEF_SPEC_DATA}/fofile-link").and_return(stat) - - File.stub(:exists?).with("#{CHEF_SPEC_DATA}/fofile-link").and_return(true) - provider.file_class.stub(:symlink?).with("#{CHEF_SPEC_DATA}/fofile-link").and_return(false) - end - - describe "and the source does not exist" do - before do - File.stub(:exists?).with("#{CHEF_SPEC_DATA}/fofile").and_return(false) - provider.load_current_resource - end - - it "should set the symlink target" do - provider.current_resource.target_file.should == "#{CHEF_SPEC_DATA}/fofile-link" - end - it "should update the current source of the existing link with an empty string" do - provider.current_resource.to.should == '' - end - it "should not set the owner" do - provider.current_resource.owner.should == nil - end - it "should not set the group" do - provider.current_resource.group.should == nil - end - end - - describe "and the source exists" do - before do - stat = double("stats", :ino => 6) - stat.stub(:uid).and_return(502) - stat.stub(:gid).and_return(502) - stat.stub(:mode).and_return(0644) - - provider.file_class.stub(:stat).with("#{CHEF_SPEC_DATA}/fofile").and_return(stat) - - File.stub(:exists?).with("#{CHEF_SPEC_DATA}/fofile").and_return(true) - provider.load_current_resource - end - - it "should set the symlink target" do - provider.current_resource.target_file.should == "#{CHEF_SPEC_DATA}/fofile-link" - end - it "should update the current source of the existing link with an empty string" do - provider.current_resource.to.should == '' - end - it "should not set the owner" do - provider.current_resource.owner.should == nil - end - it "should not set the group" do - provider.current_resource.group.should == nil - end - end - - describe "and is hardlinked to the source" do - before do - stat = double("stats", :ino => 5) - stat.stub(:uid).and_return(502) - stat.stub(:gid).and_return(502) - stat.stub(:mode).and_return(0644) - - provider.file_class.stub(:stat).with("#{CHEF_SPEC_DATA}/fofile").and_return(stat) - - File.stub(:exists?).with("#{CHEF_SPEC_DATA}/fofile").and_return(true) - provider.load_current_resource - end - - it "should set the symlink target" do - provider.current_resource.target_file.should == "#{CHEF_SPEC_DATA}/fofile-link" - end - it "should set the link type" do - provider.current_resource.link_type.should == :hard - end - it "should update the source of the existing link to the link's target" do - paths_eql?(provider.current_resource.to, "#{CHEF_SPEC_DATA}/fofile").should be_true - end - it "should not set the owner" do - provider.current_resource.owner.should == nil - end - it "should not set the group" do - provider.current_resource.group.should == nil - end - - # 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 - 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 - provider.file_class.should_not_receive(:symlink) - provider.file_class.should_not_receive(:link) - provider.access_controls.should_not_receive(:set_all) - provider.run_action(:create) - end - end - end - end -end diff --git a/spec/unit/provider/log_spec.rb b/spec/unit/provider/log_spec.rb deleted file mode 100644 index a270ee4822..0000000000 --- a/spec/unit/provider/log_spec.rb +++ /dev/null @@ -1,79 +0,0 @@ -# -# Author:: Cary Penniman (<cary@rightscale.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' - -describe Chef::Provider::Log::ChefLog do - - let(:log_str) { "this is my test string to log" } - - let(:node) { Chef::Node.new } - - let(:events) { Chef::EventDispatch::Dispatcher.new } - - let(:run_context) { Chef::RunContext.new(node, {}, events) } - - let(:new_resource) { Chef::Resource::Log.new(log_str) } - - let(:provider) { Chef::Provider::Log::ChefLog.new(new_resource, run_context) } - - it "should be registered with the default platform hash" do - expect(Chef::Platform.platforms[:default][:log]).not_to be_nil - end - - it "should write the string to the Chef::Log object at default level (info)" do - expect(Chef::Log).to receive(:info).with(log_str).and_return(true) - provider.run_action(:write) - end - - it "should write the string to the Chef::Log object at debug level" do - new_resource.level :debug - expect(Chef::Log).to receive(:debug).with(log_str).and_return(true) - provider.run_action(:write) - end - - it "should write the string to the Chef::Log object at info level" do - new_resource.level :info - expect(Chef::Log).to receive(:info).with(log_str).and_return(true) - provider.run_action(:write) - end - - it "should write the string to the Chef::Log object at warn level" do - new_resource.level :warn - expect(Chef::Log).to receive(:warn).with(log_str).and_return(true) - provider.run_action(:write) - end - - it "should write the string to the Chef::Log object at error level" do - new_resource.level :error - expect(Chef::Log).to receive(:error).with(log_str).and_return(true) - provider.run_action(:write) - end - - it "should write the string to the Chef::Log object at fatal level" do - new_resource.level :fatal - expect(Chef::Log).to receive(:fatal).with(log_str).and_return(true) - provider.run_action(:write) - end - - it "should print the string in why-run mode" do - Chef::Config[:why_run] = true - expect(Chef::Log).to receive(:info).with(log_str).and_return(true) - provider.run_action(:write) - end -end diff --git a/spec/unit/provider/mdadm_spec.rb b/spec/unit/provider/mdadm_spec.rb deleted file mode 100644 index 6595728741..0000000000 --- a/spec/unit/provider/mdadm_spec.rb +++ /dev/null @@ -1,131 +0,0 @@ -# -# Author:: Joe Williams (<joe@joetify.com>) -# Copyright:: Copyright (c) 2009 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 'spec_helper' -require 'ostruct' - -describe Chef::Provider::Mdadm do - - before(:each) 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"] - @provider = Chef::Provider::Mdadm.new(@new_resource, @run_context) - end - - describe "when determining the current metadevice status" do - it "should set the current resources mount point to the new resources mount point" do - @provider.stub(:shell_out!).and_return(OpenStruct.new(:status => 0)) - @provider.load_current_resource - @provider.current_resource.name.should == '/dev/md1' - @provider.current_resource.raid_device.should == '/dev/md1' - end - - it "determines that the metadevice exists when mdadm exit code is zero" do - @provider.stub(:shell_out!).with("mdadm --detail --test /dev/md1", :returns => [0,4]).and_return(OpenStruct.new(:status => 0)) - @provider.load_current_resource - @provider.current_resource.exists.should be_true - end - - it "determines that the metadevice does not exist when mdadm exit code is 4" do - @provider.stub(:shell_out!).with("mdadm --detail --test /dev/md1", :returns => [0,4]).and_return(OpenStruct.new(:status => 4)) - @provider.load_current_resource - @provider.current_resource.exists.should be_false - end - end - - describe "after the metadevice status is known" do - before(:each) do - @current_resource = Chef::Resource::Mdadm.new('/dev/md1') - @new_resource.level 5 - @provider.stub(:load_current_resource).and_return(true) - @provider.current_resource = @current_resource - end - - describe "when creating the metadevice" do - it "should create the raid device if it doesnt exist" do - @current_resource.exists(false) - expected_command = "yes | mdadm --create /dev/md1 --level 5 --chunk=16 --metadata=0.90 --raid-devices 3 /dev/sdz1 /dev/sdz2 /dev/sdz3" - @provider.should_receive(:shell_out!).with(expected_command) - @provider.run_action(:create) - end - - it "should specify a bitmap only if set" do - @current_resource.exists(false) - @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" - @provider.should_receive(:shell_out!).with(expected_command) - @provider.run_action(:create) - @new_resource.should be_updated_by_last_action - end - - it "should not specify a chunksize if raid level 1" do - @current_resource.exists(false) - @new_resource.level 1 - expected_command = "yes | mdadm --create /dev/md1 --level 1 --metadata=0.90 --raid-devices 3 /dev/sdz1 /dev/sdz2 /dev/sdz3" - @provider.should_receive(:shell_out!).with(expected_command) - @provider.run_action(:create) - @new_resource.should be_updated_by_last_action - end - - it "should not create the raid device if it does exist" do - @current_resource.exists(true) - @provider.should_not_receive(:shell_out!) - @provider.run_action(:create) - @new_resource.should_not be_updated_by_last_action - end - end - - describe "when asembling the metadevice" do - it "should assemble the raid device if it doesnt exist" do - @current_resource.exists(false) - expected_mdadm_cmd = "yes | mdadm --assemble /dev/md1 /dev/sdz1 /dev/sdz2 /dev/sdz3" - @provider.should_receive(:shell_out!).with(expected_mdadm_cmd) - @provider.run_action(:assemble) - @new_resource.should be_updated_by_last_action - end - - it "should not assemble the raid device if it doesnt exist" do - @current_resource.exists(true) - @provider.should_not_receive(:shell_out!) - @provider.run_action(:assemble) - @new_resource.should_not be_updated_by_last_action - end - end - - describe "when stopping the metadevice" do - - it "should stop the raid device if it exists" do - @current_resource.exists(true) - expected_mdadm_cmd = "yes | mdadm --stop /dev/md1" - @provider.should_receive(:shell_out!).with(expected_mdadm_cmd) - @provider.run_action(:stop) - @new_resource.should be_updated_by_last_action - end - - it "should not attempt to stop the raid device if it does not exist" do - @current_resource.exists(false) - @provider.should_not_receive(:shell_out!) - @provider.run_action(:stop) - @new_resource.should_not be_updated_by_last_action - end - end - end -end diff --git a/spec/unit/provider/mount/aix_spec.rb b/spec/unit/provider/mount/aix_spec.rb deleted file mode 100644 index dcd9170e1f..0000000000 --- a/spec/unit/provider/mount/aix_spec.rb +++ /dev/null @@ -1,237 +0,0 @@ -# -# Author:: Kaustubh Deorukhkar (<kaustubh@clogeny.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' -require 'ostruct' - -describe Chef::Provider::Mount::Aix do - - before(:all) do - @mounted_output = <<-MOUNT - node mounted mounted over vfs date options --------- --------------- --------------- ------ ------------ --------------- - /dev/sdz1 /tmp/foo jfs2 Jul 17 13:22 rw,log=/dev/hd8 -MOUNT - - @unmounted_output = <<-UNMOUNTED - node mounted mounted over vfs date options --------- --------------- --------------- ------ ------------ --------------- - /dev/sdz2 / jfs2 Jul 17 13:22 rw,log=/dev/hd8 -UNMOUNTED - - @conflict_mounted_output = <<-MOUNT - node mounted mounted over vfs date options --------- --------------- --------------- ------ ------------ --------------- - /dev/sdz3 /tmp/foo jfs2 Jul 17 13:22 rw,log=/dev/hd8 -MOUNT - - @enabled_output = <<-ENABLED -#MountPoint:Device:Vfs:Nodename:Type:Size:Options:AutoMount:Acct -/tmp/foo:/dev/sdz1:jfs2::bootfs:10485760:rw:yes:no -ENABLED - end - - before(:each) do - @node = Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - - @new_resource = Chef::Resource::Mount.new("/tmp/foo") - @new_resource.device "/dev/sdz1" - @new_resource.device_type :device - @new_resource.fstype "jfs2" - - @new_resource.supports :remount => false - - @provider = Chef::Provider::Mount::Aix.new(@new_resource, @run_context) - - ::File.stub(:exists?).with("/dev/sdz1").and_return true - ::File.stub(:exists?).with("/tmp/foo").and_return true - end - - def stub_mounted(provider, mounted_output) - response = double("Mixlib::ShellOut command", :exitstatus => 0, :stdout => mounted_output, :stderr => "") - provider.should_receive(:shell_out!).with("mount").and_return(response) - end - - def stub_enabled(provider, enabled_output) - response = double("Mixlib::ShellOut command", :exitstatus => 0, :stdout => enabled_output, :stderr => "") - provider.should_receive(:shell_out).with("lsfs -c #{@new_resource.mount_point}").and_return(response) - end - - def stub_mounted_enabled(provider, mounted_output, enabled_output) - stub_mounted(provider, mounted_output) - stub_enabled(provider, enabled_output) - end - - describe "when discovering the current fs state" do - it "should set current_resource.mounted to true if device is already mounted" do - stub_mounted_enabled(@provider, @mounted_output, "") - @provider.load_current_resource - - expect(@provider.current_resource.mounted).to be_true - end - - it "should set current_resource.mounted to false if device is not mounted" do - stub_mounted_enabled(@provider, @unmounted_output, "") - - @provider.load_current_resource - - expect(@provider.current_resource.mounted).to be_false - end - - it "should set current_resource.mounted to false if the mount point is used for another device" do - stub_mounted_enabled(@provider, @conflict_mounted_output, "") - - @provider.load_current_resource - - expect(@provider.current_resource.mounted).to be_false - end - end - - # tests for #enabled? - it "should load current_resource with properties if device is already mounted and enabled" do - stub_mounted_enabled(@provider, @mounted_output, @enabled_output) - - @provider.load_current_resource - - expect(@provider.current_resource.enabled).to be_true - expect(@provider.current_resource.mounted).to be_true - 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']) - end - - describe "mount_fs" do - it "should mount resource if it is not mounted" do - stub_mounted_enabled(@provider, @unmounted_output, "") - - @provider.should_receive(:shell_out!).with("mount -v #{@new_resource.fstype} #{@new_resource.device} #{@new_resource.mount_point}") - - @provider.run_action(:mount) - end - - it "should not mount resource if it is already mounted" do - stub_mounted_enabled(@provider, @mounted_output, "") - - @provider.should_not_receive(:mount_fs) - - @provider.run_action(:mount) - end - end - - describe "umount_fs" do - it "should umount resource if it is already mounted" do - stub_mounted_enabled(@provider, @mounted_output, "") - - @provider.should_receive(:shell_out!).with("umount #{@new_resource.mount_point}") - - @provider.run_action(:umount) - end - - it "should not umount resource if it is not mounted" do - stub_mounted_enabled(@provider, @unmounted_output, "") - - @provider.should_not_receive(:umount_fs) - - @provider.run_action(:umount) - end - end - - describe "remount_fs" do - it "should remount resource if it is already mounted and it supports remounting" do - @new_resource.supports({:remount => true}) - stub_mounted_enabled(@provider, @mounted_output, "") - - @provider.should_receive(:shell_out!).with("mount -o remount #{@new_resource.device} #{@new_resource.mount_point}") - - @provider.run_action(:remount) - 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.options("nodev,rw") - stub_mounted_enabled(@provider, @mounted_output, "") - - @provider.should_receive(:shell_out!).with("mount -o remount,nodev,rw #{@new_resource.device} #{@new_resource.mount_point}") - - @provider.run_action(:remount) - end - end - - describe "enable_fs" do - it "should enable mount if it is mounted and not enabled" do - @new_resource.options("nodev,rw") - stub_mounted_enabled(@provider, @mounted_output, "") - filesystems = StringIO.new - ::File.stub(:open).with("/etc/filesystems", "a").and_yield(filesystems) - - @provider.run_action(:enable) - - filesystems.string.should match(%r{^/tmp/foo:\n\tdev\t\t= /dev/sdz1\n\tvfs\t\t= jfs2\n\tmount\t\t= false\n\toptions\t\t= nodev,rw\n$}) - end - - it "should not enable mount if it is mounted and already enabled and mount options are unchanged" do - stub_mounted_enabled(@provider, @mounted_output, @enabled_output) - @new_resource.options "rw" - - @provider.should_not_receive(:enable_fs) - - @provider.run_action(:enable) - end - end - - describe "disable_fs" do - it "should disable mount if it is mounted and enabled" do - stub_mounted_enabled(@provider, @mounted_output, @enabled_output) - - ::File.stub(:open).with("/etc/filesystems", "r").and_return(<<-ETCFILESYSTEMS) -/tmp/foo: - dev = /dev/sdz1 - vfs = jfs2 - log = /dev/hd8 - mount = true - check = true - vol = /opt - free = false - quota = no - -/tmp/abc: - dev = /dev/sdz2 - vfs = jfs2 - mount = true - options = rw -ETCFILESYSTEMS - - filesystems = StringIO.new - ::File.stub(:open).with("/etc/filesystems", "w").and_yield(filesystems) - - @provider.run_action(:disable) - - filesystems.string.should match(%r{^/tmp/abc:\s+dev\s+= /dev/sdz2\s+vfs\s+= jfs2\s+mount\s+= true\s+options\s+= rw\n$}) - end - - it "should not disable mount if it is not mounted" do - stub_mounted_enabled(@provider, @unmounted_output, "") - - @provider.should_not_receive(:disable_fs) - - @provider.run_action(:disable) - end - end -end diff --git a/spec/unit/provider/mount/mount_spec.rb b/spec/unit/provider/mount/mount_spec.rb deleted file mode 100644 index d6f71bc613..0000000000 --- a/spec/unit/provider/mount/mount_spec.rb +++ /dev/null @@ -1,478 +0,0 @@ -# -# Author:: Joshua Timberman (<joshua@opscode.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 'ostruct' - -describe Chef::Provider::Mount::Mount do - before(:each) do - @node = Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - - @new_resource = Chef::Resource::Mount.new("/tmp/foo") - @new_resource.device "/dev/sdz1" - @new_resource.device_type :device - @new_resource.fstype "ext3" - - @new_resource.supports :remount => false - - @provider = Chef::Provider::Mount::Mount.new(@new_resource, @run_context) - - ::File.stub(:exists?).with("/dev/sdz1").and_return true - ::File.stub(:exists?).with("/tmp/foo").and_return true - ::File.stub(:realpath).with("/dev/sdz1").and_return "/dev/sdz1" - ::File.stub(:realpath).with("/tmp/foo").and_return "/tmp/foo" - end - - describe "when discovering the current fs state" do - before do - @provider.stub(:shell_out!).and_return(OpenStruct.new(:stdout => '')) - ::File.stub(:foreach).with("/etc/fstab") - end - - it "should create a current resource with the same mount point and device" do - @provider.load_current_resource - @provider.current_resource.name.should == '/tmp/foo' - @provider.current_resource.mount_point.should == '/tmp/foo' - @provider.current_resource.device.should == '/dev/sdz1' - end - - it "should accecpt device_type :uuid", :not_supported_on_solaris do - @new_resource.device_type :uuid - @new_resource.device "d21afe51-a0fe-4dc6-9152-ac733763ae0a" - @stdout_findfs = double("STDOUT", :first => "/dev/sdz1") - @provider.should_receive(:popen4).with("/sbin/findfs UUID=d21afe51-a0fe-4dc6-9152-ac733763ae0a").and_yield(@pid,@stdin,@stdout_findfs,@stderr).and_return(@status) - @provider.load_current_resource() - @provider.mountable? - end - - describe "when dealing with network mounts" do - { "nfs" => "nfsserver:/vol/path", - "cifs" => "//cifsserver/share" }.each do |type, fs_spec| - it "should detect network fs_spec (#{type})" do - @new_resource.device fs_spec - @provider.network_device?.should be_true - end - - it "should ignore trailing slash and set mounted to true for network mount (#{type})" do - @new_resource.device fs_spec - @provider.stub(:shell_out!).and_return(OpenStruct.new(:stdout => "#{fs_spec}/ on /tmp/foo type #{type} (rw)\n")) - @provider.load_current_resource - @provider.current_resource.mounted.should be_true - end - end - end - - it "should raise an error if the mount device does not exist" do - ::File.stub(:exists?).with("/dev/sdz1").and_return false - lambda { @provider.load_current_resource();@provider.mountable? }.should raise_error(Chef::Exceptions::Mount) - end - - it "should not call mountable? with load_current_resource - CHEF-1565" do - ::File.stub(:exists?).with("/dev/sdz1").and_return false - @provider.should_receive(:mounted?).and_return(true) - @provider.should_receive(:enabled?).and_return(true) - @provider.should_not_receive(:mountable?) - @provider.load_current_resource - end - - it "should raise an error if the mount device (uuid) does not exist", :not_supported_on_solaris do - @new_resource.device_type :uuid - @new_resource.device "d21afe51-a0fe-4dc6-9152-ac733763ae0a" - status_findfs = double("Status", :exitstatus => 1) - stdout_findfs = double("STDOUT", :first => nil) - @provider.should_receive(:popen4).with("/sbin/findfs UUID=d21afe51-a0fe-4dc6-9152-ac733763ae0a").and_yield(@pid,@stdin,stdout_findfs,@stderr).and_return(status_findfs) - ::File.should_receive(:exists?).with("").and_return(false) - lambda { @provider.load_current_resource();@provider.mountable? }.should raise_error(Chef::Exceptions::Mount) - end - - it "should raise an error if the mount point does not exist" do - ::File.stub(:exists?).with("/tmp/foo").and_return false - lambda { @provider.load_current_resource();@provider.mountable? }.should raise_error(Chef::Exceptions::Mount) - end - - it "does not expect the device to exist for tmpfs" do - @new_resource.fstype("tmpfs") - @new_resource.device("whatever") - lambda { @provider.load_current_resource();@provider.mountable? }.should_not raise_error - end - - it "does not expect the device to exist for Fuse filesystems" do - @new_resource.fstype("fuse") - @new_resource.device("nilfs#xxx") - lambda { @provider.load_current_resource();@provider.mountable? }.should_not raise_error - end - - it "does not expect the device to exist if it's none" do - @new_resource.device("none") - lambda { @provider.load_current_resource();@provider.mountable? }.should_not raise_error - end - - it "should set mounted true if the mount point is found in the mounts list" do - @provider.stub(:shell_out!).and_return(OpenStruct.new(:stdout => "/dev/sdz1 on /tmp/foo type ext3 (rw)\n")) - @provider.load_current_resource() - @provider.current_resource.mounted.should be_true - end - - it "should set mounted false if another mount point beginning with the same path is found in the mounts list" do - @provider.stub(:shell_out!).and_return(OpenStruct.new(:stdout => "/dev/sdz1 on /tmp/foobar type ext3 (rw)\n")) - @provider.load_current_resource() - @provider.current_resource.mounted.should be_false - end - - 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') - - ::File.stub(:symlink?).with("#{@new_resource.device}").and_return(true) - ::File.stub(:readlink).with("#{@new_resource.device}").and_return(target) - - @provider.stub(:shell_out!).and_return(OpenStruct.new(:stdout => "#{target} on /tmp/foo type ext3 (rw)\n")) - @provider.load_current_resource() - @provider.current_resource.mounted.should be_true - end - - it "should set mounted true if the symlink target of the device is relative and is found in the mounts list - CHEF-4957" do - target = "xsdz1" - - # expand the target path to correct specs on Windows - absolute_target = ::File.expand_path("/dev/xsdz1") - - ::File.stub(:symlink?).with("#{@new_resource.device}").and_return(true) - ::File.stub(:readlink).with("#{@new_resource.device}").and_return(target) - - @provider.stub(:shell_out!).and_return(OpenStruct.new(:stdout => "#{absolute_target} on /tmp/foo type ext3 (rw)\n")) - @provider.load_current_resource() - @provider.current_resource.mounted.should be_true - end - - it "should set mounted true if the mount point is found last in the mounts list" do - mount = "/dev/sdy1 on #{@new_resource.mount_point} type ext3 (rw)\n" - mount << "#{@new_resource.device} on #{@new_resource.mount_point} type ext3 (rw)\n" - - @provider.stub(:shell_out!).and_return(OpenStruct.new(:stdout => mount)) - @provider.load_current_resource() - @provider.current_resource.mounted.should be_true - end - - it "should set mounted false if the mount point is not last in the mounts list" do - mount = "#{@new_resource.device} on #{@new_resource.mount_point} type ext3 (rw)\n" - mount << "/dev/sdy1 on #{@new_resource.mount_point} type ext3 (rw)\n" - - @provider.stub(:shell_out!).and_return(OpenStruct.new(:stdout => mount)) - @provider.load_current_resource() - @provider.current_resource.mounted.should be_false - end - - it "mounted should be false if the mount point is not found in the mounts list" do - @provider.stub(:shell_out!).and_return(OpenStruct.new(:stdout => "/dev/sdy1 on /tmp/foo type ext3 (rw)\n")) - @provider.load_current_resource() - @provider.current_resource.mounted.should be_false - end - - it "should set enabled to true if the mount point is last in fstab" do - fstab1 = "/dev/sdy1 /tmp/foo ext3 defaults 1 2\n" - fstab2 = "#{@new_resource.device} #{@new_resource.mount_point} ext3 defaults 1 2\n" - - ::File.stub(:foreach).with("/etc/fstab").and_yield(fstab1).and_yield(fstab2) - - @provider.load_current_resource - @provider.current_resource.enabled.should be_true - end - - it "should set enabled to true if the mount point is not last in fstab and mount_point is a substring of another mount" do - fstab1 = "#{@new_resource.device} #{@new_resource.mount_point} ext3 defaults 1 2\n" - fstab2 = "/dev/sdy1 /tmp/foo/bar ext3 defaults 1 2\n" - - ::File.stub(:foreach).with("/etc/fstab").and_yield(fstab1).and_yield(fstab2) - - @provider.load_current_resource - @provider.current_resource.enabled.should be_true - end - - it "should set enabled to true if the symlink target is in fstab" do - target = "/dev/mapper/target" - - ::File.stub(:symlink?).with("#{@new_resource.device}").and_return(true) - ::File.stub(:readlink).with("#{@new_resource.device}").and_return(target) - - fstab = "/dev/sdz1 /tmp/foo ext3 defaults 1 2\n" - - ::File.stub(:foreach).with("/etc/fstab").and_yield fstab - - @provider.load_current_resource - @provider.current_resource.enabled.should be_true - end - - it "should set enabled to true if the symlink target is relative and is in fstab - CHEF-4957" do - target = "xsdz1" - - ::File.stub(:symlink?).with("#{@new_resource.device}").and_return(true) - ::File.stub(:readlink).with("#{@new_resource.device}").and_return(target) - - fstab = "/dev/sdz1 /tmp/foo ext3 defaults 1 2\n" - - ::File.stub(:foreach).with("/etc/fstab").and_yield fstab - - @provider.load_current_resource - @provider.current_resource.enabled.should be_true - end - - it "should set enabled to false if the mount point is not in fstab" do - fstab = "/dev/sdy1 #{@new_resource.mount_point} ext3 defaults 1 2\n" - ::File.stub(:foreach).with("/etc/fstab").and_yield fstab - - @provider.load_current_resource - @provider.current_resource.enabled.should be_false - end - - it "should ignore commented lines in fstab " do - fstab = "\# #{@new_resource.device} #{@new_resource.mount_point} ext3 defaults 1 2\n" - ::File.stub(:foreach).with("/etc/fstab").and_yield fstab - - @provider.load_current_resource - @provider.current_resource.enabled.should be_false - 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" - line_2 = "/dev/sdy1 #{@new_resource.mount_point} ext3 defaults 1 2\n" - ::File.stub(:foreach).with("/etc/fstab").and_yield(line_1).and_yield(line_2) - - @provider.load_current_resource - @provider.current_resource.enabled.should be_false - end - - it "should not mangle the mount options if the device in fstab is a symlink" do - # expand the target path to correct specs on Windows - target = "/dev/mapper/target" - options = "rw,noexec,noauto" - - ::File.stub(:symlink?).with(@new_resource.device).and_return(true) - ::File.stub(:readlink).with(@new_resource.device).and_return(target) - - fstab = "#{@new_resource.device} #{@new_resource.mount_point} #{@new_resource.fstype} #{options} 1 2\n" - ::File.stub(:foreach).with("/etc/fstab").and_yield fstab - @provider.load_current_resource - @provider.current_resource.options.should eq(options.split(',')) - end - - it "should not mangle the mount options if the symlink target is in fstab" do - target = ::File.expand_path("/dev/mapper/target") - options = "rw,noexec,noauto" - - ::File.stub(:symlink?).with(@new_resource.device).and_return(true) - ::File.stub(:readlink).with(@new_resource.device).and_return(target) - - fstab = "#{target} #{@new_resource.mount_point} #{@new_resource.fstype} #{options} 1 2\n" - ::File.stub(:foreach).with("/etc/fstab").and_yield fstab - @provider.load_current_resource - @provider.current_resource.options.should eq(options.split(',')) - end - end - - context "after the mount's state has been discovered" do - before do - @current_resource = Chef::Resource::Mount.new("/tmp/foo") - @current_resource.device "/dev/sdz1" - @current_resource.device_type :device - @current_resource.fstype "ext3" - - @provider.current_resource = @current_resource - end - - describe "mount_fs" do - it "should mount the filesystem if it is not mounted" do - @provider.should_receive(:shell_out!).with("mount -t ext3 -o defaults /dev/sdz1 /tmp/foo") - @provider.mount_fs() - end - - it "should mount the filesystem with options if options were passed" do - options = "rw,noexec,noauto" - @new_resource.options(%w{rw noexec noauto}) - @provider.should_receive(:shell_out!).with("mount -t ext3 -o rw,noexec,noauto /dev/sdz1 /tmp/foo") - @provider.mount_fs() - end - - it "should mount the filesystem specified by uuid", :not_supported_on_solaris do - @new_resource.device "d21afe51-a0fe-4dc6-9152-ac733763ae0a" - @new_resource.device_type :uuid - @stdout_findfs = double("STDOUT", :first => "/dev/sdz1") - @provider.stub(:popen4).with("/sbin/findfs UUID=d21afe51-a0fe-4dc6-9152-ac733763ae0a").and_yield(@pid,@stdin,@stdout_findfs,@stderr).and_return(@status) - @stdout_mock = double('stdout mock') - @stdout_mock.stub(:each).and_yield("#{@new_resource.device} on #{@new_resource.mount_point}") - @provider.should_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() - end - - it "should not mount the filesystem if it is mounted" do - @current_resource.stub(:mounted).and_return(true) - @provider.should_not_receive(:shell_out!) - @provider.mount_fs() - end - - end - - describe "umount_fs" do - it "should umount the filesystem if it is mounted" do - @current_resource.mounted(true) - @provider.should_receive(:shell_out!).with("umount /tmp/foo") - @provider.umount_fs() - end - - it "should not umount the filesystem if it is not mounted" do - @current_resource.mounted(false) - @provider.should_not_receive(:shell_out!) - @provider.umount_fs() - end - end - - describe "remount_fs" do - it "should use mount -o remount if remount is supported" do - @new_resource.supports({:remount => true}) - @current_resource.mounted(true) - @provider.should_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}) - options = "rw,noexec,noauto" - @new_resource.options(%w{rw noexec noauto}) - @current_resource.mounted(true) - @provider.should_receive(:shell_out!).with("mount -o remount,rw,noexec,noauto #{@new_resource.mount_point}") - @provider.remount_fs - end - - it "should umount and mount if remount is not supported" do - @new_resource.supports({:remount => false}) - @current_resource.mounted(true) - @provider.should_receive(:umount_fs) - @provider.should_receive(:sleep).with(1) - @provider.should_receive(:mount_fs) - @provider.remount_fs() - end - - it "should not try to remount at all if mounted is false" do - @current_resource.mounted(false) - @provider.should_not_receive(:shell_out!) - @provider.should_not_receive(:umount_fs) - @provider.should_not_receive(:mount_fs) - @provider.remount_fs() - end - end - - describe "when enabling the fs" do - it "should enable if enabled isn't true" do - @current_resource.enabled(false) - - @fstab = StringIO.new - ::File.stub(:open).with("/etc/fstab", "a").and_yield(@fstab) - @provider.enable_fs - @fstab.string.should match(%r{^/dev/sdz1\s+/tmp/foo\s+ext3\s+defaults\s+0\s+2\s*$}) - end - - it "should not enable if enabled is true and resources match" do - @current_resource.enabled(true) - @current_resource.fstype("ext3") - @current_resource.options(["defaults"]) - @current_resource.dump(0) - @current_resource.pass(2) - ::File.should_not_receive(:open).with("/etc/fstab", "a") - - @provider.enable_fs - end - - it "should enable if enabled is true and resources do not match" do - @current_resource.enabled(true) - @current_resource.fstype("auto") - @current_resource.options(["defaults"]) - @current_resource.dump(0) - @current_resource.pass(2) - @fstab = StringIO.new - ::File.stub(:readlines).and_return([]) - ::File.should_receive(:open).once.with("/etc/fstab", "w").and_yield(@fstab) - ::File.should_receive(:open).once.with("/etc/fstab", "a").and_yield(@fstab) - - @provider.enable_fs - end - end - - describe "when disabling the fs" do - it "should disable if enabled is true" do - @current_resource.enabled(true) - - other_mount = "/dev/sdy1 /tmp/foo ext3 defaults 1 2\n" - this_mount = "/dev/sdz1 /tmp/foo ext3 defaults 1 2\n" - - @fstab_read = [this_mount, other_mount] - ::File.stub(:readlines).with("/etc/fstab").and_return(@fstab_read) - @fstab_write = StringIO.new - ::File.stub(:open).with("/etc/fstab", "w").and_yield(@fstab_write) - - @provider.disable_fs - @fstab_write.string.should match(Regexp.escape(other_mount)) - @fstab_write.string.should_not match(Regexp.escape(this_mount)) - end - - it "should disable if enabled is true and ignore commented lines" do - @current_resource.enabled(true) - - fstab_read = [%q{/dev/sdy1 /tmp/foo ext3 defaults 1 2}, - %q{/dev/sdz1 /tmp/foo ext3 defaults 1 2}, - %q{#/dev/sdz1 /tmp/foo ext3 defaults 1 2}] - fstab_write = StringIO.new - - ::File.stub(:readlines).with("/etc/fstab").and_return(fstab_read) - ::File.stub(:open).with("/etc/fstab", "w").and_yield(fstab_write) - - @provider.disable_fs - fstab_write.string.should match(%r{^/dev/sdy1 /tmp/foo ext3 defaults 1 2$}) - fstab_write.string.should match(%r{^#/dev/sdz1 /tmp/foo ext3 defaults 1 2$}) - fstab_write.string.should_not match(%r{^/dev/sdz1 /tmp/foo ext3 defaults 1 2$}) - end - - it "should disable only the last entry if enabled is true" do - @current_resource.stub(:enabled).and_return(true) - fstab_read = ["/dev/sdz1 /tmp/foo ext3 defaults 1 2\n", - "/dev/sdy1 /tmp/foo ext3 defaults 1 2\n", - "/dev/sdz1 /tmp/foo ext3 defaults 1 2\n", - "/dev/sdz1 /tmp/foobar ext3 defaults 1 2\n"] - - fstab_write = StringIO.new - ::File.stub(:readlines).with("/etc/fstab").and_return(fstab_read) - ::File.stub(:open).with("/etc/fstab", "w").and_yield(fstab_write) - - @provider.disable_fs - fstab_write.string.should == "/dev/sdz1 /tmp/foo ext3 defaults 1 2\n" + - "/dev/sdy1 /tmp/foo ext3 defaults 1 2\n" + - "/dev/sdz1 /tmp/foobar ext3 defaults 1 2\n" - end - - it "should not disable if enabled is false" do - @current_resource.stub(:enabled).and_return(false) - - ::File.stub(:readlines).with("/etc/fstab").and_return([]) - ::File.should_not_receive(:open).and_yield(@fstab) - - @provider.disable_fs - end - end - end -end diff --git a/spec/unit/provider/mount/solaris_spec.rb b/spec/unit/provider/mount/solaris_spec.rb deleted file mode 100644 index 50ddfaa28d..0000000000 --- a/spec/unit/provider/mount/solaris_spec.rb +++ /dev/null @@ -1,822 +0,0 @@ -# -# Author:: Lamont Granquist (<lamont@getchef.com>) -# Copyright:: Copyright (c) 2008-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 'ostruct' - -# Do not run these tests on windows because some path handling -# code is not implemented to handle windows paths. - -describe Chef::Provider::Mount::Solaris, :unix_only do - let(:node) { Chef::Node.new } - - let(:events) { Chef::EventDispatch::Dispatcher.new } - - let(:run_context) { Chef::RunContext.new(node, {}, events) } - - let(:device_type) { :device } - - let(:fstype) { "ufs" } - - let(:device) { "/dev/dsk/c0t2d0s7" } - - let(:fsck_device) { "/dev/rdsk/c0t2d0s7" } - - let(:mountpoint) { "/mnt/foo" } - - let(:options) { nil } - - let(:new_resource) { - new_resource = Chef::Resource::Mount.new(mountpoint) - new_resource.device device - new_resource.device_type device_type - new_resource.fsck_device fsck_device - new_resource.fstype fstype - new_resource.options options - new_resource.supports :remount => false - new_resource - } - - let(:provider) { - Chef::Provider::Mount::Solaris.new(new_resource, run_context) - } - - let(:vfstab_file_contents) { - <<-EOF.gsub /^\s*/, '' - #device device mount FS fsck mount mount - #to mount to fsck point type pass at boot options - # - fd - /dev/fd fd - no - - /proc - /proc proc - no - - # swap - /dev/dsk/c0t0d0s1 - - swap - no - - # root - /dev/dsk/c0t0d0s0 /dev/rdsk/c0t0d0s0 / ufs 1 no - - # tmpfs - swap - /tmp tmpfs - yes - - # nfs - cartman:/share2 - /cartman nfs - yes rw,soft - # ufs - /dev/dsk/c0t2d0s7 /dev/rdsk/c0t2d0s7 /mnt/foo ufs 2 yes - - EOF - } - - let(:vfstab_file) { - t = Tempfile.new("rspec-vfstab") - t.write(vfstab_file_contents) - t.close - t - } - - let(:mount_output) { - <<-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 - } - - before do - stub_const("Chef::Provider::Mount::Solaris::VFSTAB", vfstab_file.path ) - provider.stub(:shell_out!).with("mount -v").and_return(OpenStruct.new(:stdout => mount_output)) - File.stub(:symlink?).with(device).and_return(false) - File.stub(:exist?).and_call_original # Tempfile.open on ruby 1.8.7 calls File.exist? - File.stub(:exist?).with(device).and_return(true) - File.stub(:exist?).with(mountpoint).and_return(true) - expect(File).to_not receive(:exists?) - end - - 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| provider.stub(m) } - end - - it "run_action(:mount) should raise an error if the device does not exist" do - File.stub(:exist?).with(device).and_return(false) - expect { provider.run_action(:mount) }.to raise_error(Chef::Exceptions::Mount) - end - - it "run_action(:remount) should raise an error if the device does not exist" do - File.stub(:exist?).with(device).and_return(false) - expect { provider.run_action(:remount) }.to raise_error(Chef::Exceptions::Mount) - end - - it "run_action(:mount) should raise an error if the mountpoint does not exist" do - File.stub(:exist?).with(mountpoint).and_return false - expect { provider.run_action(:mount) }.to raise_error(Chef::Exceptions::Mount) - end - - it "run_action(:remount) should raise an error if the mountpoint does not exist" do - File.stub(:exist?).with(mountpoint).and_return false - expect { provider.run_action(:remount) }.to raise_error(Chef::Exceptions::Mount) - end - - %w{tmpfs nfs ctfs proc mntfs objfs sharefs fd smbfs vxfs}.each do |ft| - context "when the device has a fstype of #{ft}" do - let(:fstype) { ft } - let(:fsck_device) { "-" } - let(:device) { "something_that_is_not_a_file" } - - before do - expect(File).to_not receive(:exist?).with(device) - end - - it "run_action(:mount) should not raise an error" do - expect { provider.run_action(:mount) }.to_not raise_error - end - - it "run_action(:remount) should not raise an error" do - expect { provider.run_action(:remount) }.to_not raise_error - end - end - end - - end - - describe "#load_current_resource" do - context "when loading a normal UFS filesystem with mount at boot" do - - before do - provider.load_current_resource - end - - it "should create a current_resource of type Chef::Resource::Mount" do - expect(provider.current_resource).to be_a(Chef::Resource::Mount) - end - - it "should set the name on the current_resource" do - provider.current_resource.name.should == mountpoint - end - - it "should set the mount_point on the current_resource" do - provider.current_resource.mount_point.should == mountpoint - end - - it "should set the device on the current_resource" do - provider.current_resource.device.should == device - end - - it "should set the fsck_device on the current_resource" do - provider.current_resource.fsck_device.should == fsck_device - end - - it "should set the device_type on the current_resource" do - provider.current_resource.device_type.should == device_type - end - - it "should set the mounted status on the current_resource" do - expect(provider.current_resource.mounted).to be_true - end - - it "should set the enabled status on the current_resource" do - expect(provider.current_resource.enabled).to be_true - end - - it "should set the fstype field on the current_resource" do - expect(provider.current_resource.fstype).to eql("ufs") - end - - it "should set the options field on the current_resource" do - expect(provider.current_resource.options).to eql(["-"]) - end - - it "should set the pass field on the current_resource" do - expect(provider.current_resource.pass).to eql(2) - end - - it "should not throw an exception when the device does not exist - CHEF-1565" do - File.stub(:exist?).with(device).and_return(false) - expect { provider.load_current_resource }.to_not raise_error - end - - it "should not throw an exception when the mount point does not exist" do - File.stub(:exist?).with(mountpoint).and_return false - expect { provider.load_current_resource }.to_not raise_error - end - end - end - - describe "#load_current_resource" do - context "when loading a normal UFS filesystem with noauto, don't mount at boot" do - - let(:vfstab_file_contents) { - <<-EOF.gsub /^\s*/, '' - #device device mount FS fsck mount mount - #to mount to fsck point type pass at boot options - # - fd - /dev/fd fd - no - - /proc - /proc proc - no - - # swap - /dev/dsk/c0t0d0s1 - - swap - no - - # root - /dev/dsk/c0t0d0s0 /dev/rdsk/c0t0d0s0 / ufs 1 no - - # tmpfs - swap - /tmp tmpfs - yes - - # nfs - cartman:/share2 - /cartman nfs - yes rw,soft - # ufs - /dev/dsk/c0t2d0s7 /dev/rdsk/c0t2d0s7 /mnt/foo ufs 2 no - - EOF - } - - before do - provider.load_current_resource - end - - it "should set the options field on the current_resource" do - expect(provider.current_resource.options).to eql(["-", "noauto"]) - end - end - - context "when the device is an smbfs mount" do - let(:mount_output) { - <<-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*/, '' - //WORKGROUP;username:password@host/share - /mountpoint smbfs - no fileperms=0777,dirperms=0777 - EOF - } - - let(:fsck_device) { "-" } - - it "should work at some point in the future" do - pending "SMBFS mounts on solaris look like they will need some future code work and more investigation" - end - end - - context "when the device is an NFS mount" do - let(:mount_output) { - <<-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*/, '' - cartman:/share2 - /cartman nfs - yes rw,soft - EOF - } - - let(:fsck_device) { "-" } - - let(:fstype) { "nfs" } - - let(:device) { "cartman:/share2" } - - let(:mountpoint) { "/cartman" } - - before do - provider.load_current_resource - end - - it "should set the name on the current_resource" do - provider.current_resource.name.should == mountpoint - end - - it "should set the mount_point on the current_resource" do - provider.current_resource.mount_point.should == mountpoint - end - - it "should set the device on the current_resource" do - provider.current_resource.device.should == device - end - - it "should set the device_type on the current_resource" do - provider.current_resource.device_type.should == device_type - end - - it "should set the mounted status on the current_resource" do - expect(provider.current_resource.mounted).to be_true - end - - it "should set the enabled status on the current_resource" do - expect(provider.current_resource.enabled).to be_true - end - - it "should set the fstype field on the current_resource" do - expect(provider.current_resource.fstype).to eql("nfs") - end - - it "should set the options field on the current_resource" do - expect(provider.current_resource.options).to eql(["rw", "soft"]) - end - - it "should set the pass field on the current_resource" do - # is this correct or should it be nil? - # - # vfstab man page says. - # "A - is used to indicate no entry in a field." - # 0 and - could mean different things for some file systems - expect(provider.current_resource.pass).to eql(0) - end - - end - - context "when the device is symlink" do - - let(:target) { "/dev/mapper/target" } - - let(:mount_output) { - <<-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*/, '' - #{target} /dev/rdsk/c0t2d0s7 /mnt/foo ufs 2 yes - - EOF - } - - before do - File.should_receive(:symlink?).with(device).at_least(:once).and_return(true) - File.should_receive(:readlink).with(device).at_least(:once).and_return(target) - - provider.load_current_resource() - end - - it "should set mounted true if the symlink target of the device is found in the mounts list" do - expect(provider.current_resource.mounted).to be_true - end - - it "should set enabled true if the symlink target of the device is found in the vfstab" do - expect(provider.current_resource.enabled).to be_true - end - - it "should have the correct mount options" do - expect(provider.current_resource.options).to eql(["-"]) - end - end - - context "when the device is a relative symlink" do - let(:target) { "foo" } - - let(:absolute_target) { File.expand_path(target, File.dirname(device)) } - - let(:mount_output) { - <<-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*/, '' - #{absolute_target} /dev/rdsk/c0t2d0s7 /mnt/foo ufs 2 yes - - EOF - } - - before do - File.should_receive(:symlink?).with(device).at_least(:once).and_return(true) - File.should_receive(:readlink).with(device).at_least(:once).and_return(target) - - provider.load_current_resource() - end - - it "should set mounted true if the symlink target of the device is found in the mounts list" do - expect(provider.current_resource.mounted).to be_true - end - - it "should set enabled true if the symlink target of the device is found in the vfstab" do - expect(provider.current_resource.enabled).to be_true - end - - it "should have the correct mount options" do - expect(provider.current_resource.options).to eql(["-"]) - end - end - - context "when the matching mount point is last in the mounts list" do - let(:mount_output) { - <<-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 - } - it "should set mounted true" do - provider.load_current_resource() - provider.current_resource.mounted.should be_true - end - end - - context "when the matching mount point is not last in the mounts list" do - let(:mount_output) { - <<-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 - } - it "should set mounted false" do - provider.load_current_resource() - provider.current_resource.mounted.should be_false - end - end - - context "when the matching mount point is not in the mounts list (mountpoint wrong)" do - let(:mount_output) { - <<-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 - } - it "should set mounted false" do - provider.load_current_resource() - provider.current_resource.mounted.should be_false - end - end - - context "when the matching mount point is not in the mounts list (raw device wrong)" do - let(:mount_output) { - <<-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 - } - it "should set mounted false" do - provider.load_current_resource() - provider.current_resource.mounted.should be_false - end - end - - context "when the mount point is last in fstab" do - let(:vfstab_file_contents) { - <<-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 - } - - it "should set enabled to true" do - provider.load_current_resource - provider.current_resource.enabled.should be_true - end - end - - 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*/, '' - /dev/dsk/c0t2d0s7 /dev/rdsk/c0t2d0s7 /mnt/foo ufs 2 yes - - /dev/dsk/c0t2d0s72 /dev/rdsk/c0t2d0s7 /mnt/foo/bar ufs 2 yes - - EOF - } - - it "should set enabled to true" do - provider.load_current_resource - provider.current_resource.enabled.should be_true - end - end - - context "when the mount point is not last in fstab" do - let(:vfstab_file_contents) { - <<-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 - } - - it "should set enabled to false" do - provider.load_current_resource - provider.current_resource.enabled.should be_false - end - end - - 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*/, '' - /dev/dsk/c0t2d0s7 /dev/rdsk/c0t2d0s7 /mnt/foob ufs 2 yes - - EOF - } - - it "should set enabled to false" do - provider.load_current_resource - provider.current_resource.enabled.should be_false - end - end - - 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*/, '' - /dev/dsk/c0t2d0s72 /dev/rdsk/c0t2d0s7 /mnt/foo ufs 2 yes - - EOF - } - - it "should set enabled to false" do - provider.load_current_resource - provider.current_resource.enabled.should be_false - end - end - - context "when the mountpoint line is commented out" do - let(:vfstab_file_contents) { - <<-EOF.gsub /^\s*/, '' - #/dev/dsk/c0t2d0s7 /dev/rdsk/c0t2d0s7 /mnt/foo ufs 2 yes - - EOF - } - - it "should set enabled to false" do - provider.load_current_resource - provider.current_resource.enabled.should be_false - end - end - end - - context "after the mount's state has been discovered" do - describe "mount_fs" do - it "should mount the filesystem" do - provider.should_receive(:shell_out!).with("mount -F #{fstype} -o defaults #{device} #{mountpoint}") - provider.mount_fs() - end - - it "should mount the filesystem with options if options were passed" do - options = "logging,noatime,largefiles,nosuid,rw,quota" - new_resource.options(options.split(/,/)) - provider.should_receive(:shell_out!).with("mount -F #{fstype} -o #{options} #{device} #{mountpoint}") - provider.mount_fs() - end - - it "should delete the 'noauto' magic option" do - options = "rw,noauto" - new_resource.options(%w{rw noauto}) - provider.should_receive(:shell_out!).with("mount -F #{fstype} -o rw #{device} #{mountpoint}") - provider.mount_fs() - end - end - - describe "umount_fs" do - it "should umount the filesystem if it is mounted" do - provider.should_receive(:shell_out!).with("umount #{mountpoint}") - provider.umount_fs() - end - end - - describe "remount_fs without options and do not mount at boot" do - it "should use mount -o remount" do - new_resource.options(%w{noauto}) - provider.should_receive(:shell_out!).with("mount -o remount #{new_resource.mount_point}") - provider.remount_fs - end - end - - describe "remount_fs with options and do not mount at boot" do - it "should use mount -o remount,rw" do - new_resource.options(%w{rw noauto}) - provider.should_receive(:shell_out!).with("mount -o remount,rw #{new_resource.mount_point}") - provider.remount_fs - end - end - - describe "remount_fs with options and mount at boot" do - it "should use mount -o remount,rw" do - new_resource.options(%w{rw}) - provider.should_receive(:shell_out!).with("mount -o remount,rw #{new_resource.mount_point}") - provider.remount_fs - end - end - - describe "remount_fs without options and mount at boot" do - it "should use mount -o remount" do - new_resource.options([]) - provider.should_receive(:shell_out!).with("mount -o remount #{new_resource.mount_point}") - provider.remount_fs - end - end - - describe "when enabling the fs" do - context "in the typical case" do - let(:other_mount) { "/dev/dsk/c0t2d0s0 /dev/rdsk/c0t2d0s0 / ufs 2 yes -" } - - let(:this_mount) { "/dev/dsk/c0t2d0s7\t/dev/rdsk/c0t2d0s7\t/mnt/foo\tufs\t2\tyes\tdefaults\n" } - - let(:vfstab_file_contents) { [other_mount].join("\n") } - - before do - provider.stub(:etc_tempfile).and_yield(Tempfile.open("vfstab")) - provider.load_current_resource - provider.enable_fs - end - - it "should leave the other mountpoint alone" do - IO.read(vfstab_file.path).should match(/^#{Regexp.escape(other_mount)}/) - end - - it "should enable the mountpoint we care about" do - IO.read(vfstab_file.path).should match(/^#{Regexp.escape(this_mount)}/) - end - end - - context "when the mount has options=noauto" do - let(:other_mount) { "/dev/dsk/c0t2d0s0 /dev/rdsk/c0t2d0s0 / ufs 2 yes -" } - - let(:this_mount) { "/dev/dsk/c0t2d0s7\t/dev/rdsk/c0t2d0s7\t/mnt/foo\tufs\t2\tno\t-\n" } - - let(:options) { "noauto" } - - let(:vfstab_file_contents) { [other_mount].join("\n") } - - before do - provider.stub(:etc_tempfile).and_yield(Tempfile.open("vfstab")) - provider.load_current_resource - provider.enable_fs - end - - it "should leave the other mountpoint alone" do - IO.read(vfstab_file.path).should match(/^#{Regexp.escape(other_mount)}/) - end - - it "should enable the mountpoint we care about" do - IO.read(vfstab_file.path).should match(/^#{Regexp.escape(this_mount)}/) - end - end - - context "when the new mount has options of noauto and the existing mount has mount at boot yes" do - let(:existing_mount) { "/dev/dsk/c0t2d0s7\t/dev/rdsk/c0t2d0s7\t/mnt/foo\tufs\t2\tyes\t-" } - - let(:this_mount) { "/dev/dsk/c0t2d0s7\t/dev/rdsk/c0t2d0s7\t/mnt/foo\tufs\t2\tno\t-\n" } - - let(:options) { "noauto" } - - let(:vfstab_file_contents) { [existing_mount].join("\n") } - - before do - provider.stub(:etc_tempfile).and_yield(Tempfile.open("vfstab")) - provider.load_current_resource - provider.mount_options_unchanged? - provider.send(:vfstab_entry) - end - - it "should detect a changed entry" do - provider.mount_options_unchanged?.should == false - end - - it "should change mount at boot to no" do - provider.send(:vfstab_entry).should match(/^#{Regexp.escape(this_mount)}/) - end - end - - context "when the new mount has options of - and the existing mount has mount at boot no" do - let(:existing_mount) { "/dev/dsk/c0t2d0s7\t/dev/rdsk/c0t2d0s7\t/mnt/foo\tufs\t2\tno\t-" } - - let(:this_mount) { "/dev/dsk/c0t2d0s7\t/dev/rdsk/c0t2d0s7\t/mnt/foo\tufs\t2\tyes\t-\n" } - - let(:options) { "-" } - - let(:vfstab_file_contents) { [existing_mount].join("\n") } - - before do - provider.stub(:etc_tempfile).and_yield(Tempfile.open("vfstab")) - provider.load_current_resource - provider.mount_options_unchanged? - provider.send(:vfstab_entry) - end - - it "should detect a changed entry" do - provider.mount_options_unchanged?.should == false - end - - it "should change mount at boot to yes" do - provider.send(:vfstab_entry).should match(/^#{Regexp.escape(this_mount)}/) - end - end - - context "when the new mount has options of noauto and the existing mount has mount at boot no" do - let(:existing_mount) { "/dev/dsk/c0t2d0s7\t/dev/rdsk/c0t2d0s7\t/mnt/foo\tufs\t2\tno\t-" } - - let(:this_mount) { "/dev/dsk/c0t2d0s7\t/dev/rdsk/c0t2d0s7\t/mnt/foo\tufs\t2\tno\t-\n" } - - let(:options) { "-,noauto" } - - let(:vfstab_file_contents) { [existing_mount].join("\n") } - - before do - provider.stub(:etc_tempfile).and_yield(Tempfile.open("vfstab")) - provider.load_current_resource - provider.mount_options_unchanged? - provider.send(:vfstab_entry) - end - - it "should detect an unchanged entry" do - provider.mount_options_unchanged?.should == true - end - - it "should not change mount at boot" do - provider.send(:vfstab_entry).should match(/^#{Regexp.escape(this_mount)}/) - end - end - - context "when the new mount has options of - and the existing mount has mount at boot yes" do - let(:existing_mount) { "/dev/dsk/c0t2d0s7\t/dev/rdsk/c0t2d0s7\t/mnt/foo\tufs\t2\tyes\t-" } - - let(:this_mount) { "/dev/dsk/c0t2d0s7\t/dev/rdsk/c0t2d0s7\t/mnt/foo\tufs\t2\tyes\t-\n" } - - let(:options) { "-" } - - let(:vfstab_file_contents) { [existing_mount].join("\n") } - - before do - provider.stub(:etc_tempfile).and_yield(Tempfile.open("vfstab")) - provider.load_current_resource - provider.mount_options_unchanged? - provider.send(:vfstab_entry) - end - - it "should detect an unchanged entry" do - provider.mount_options_unchanged?.should == true - end - - it "should not change mount at boot" do - provider.send(:vfstab_entry).should match(/^#{Regexp.escape(this_mount)}/) - end - end - end - - describe "when disabling the fs" do - context "in the typical case" do - let(:other_mount) { "/dev/dsk/c0t2d0s0 /dev/rdsk/c0t2d0s0 / ufs 2 yes -" } - - let(:this_mount) { "/dev/dsk/c0t2d0s7 /dev/rdsk/c0t2d0s7 /mnt/foo ufs 2 yes -" } - - let(:vfstab_file_contents) { [other_mount, this_mount].join("\n") } - - before do - provider.stub(:etc_tempfile).and_yield(Tempfile.open("vfstab")) - provider.disable_fs - end - - it "should leave the other mountpoint alone" do - IO.read(vfstab_file.path).should match(/^#{Regexp.escape(other_mount)}/) - end - - it "should disable the mountpoint we care about" do - IO.read(vfstab_file.path).should_not match(/^#{Regexp.escape(this_mount)}/) - end - end - - context "when there is a commented out line" do - let(:other_mount) { "/dev/dsk/c0t2d0s0 /dev/rdsk/c0t2d0s0 / ufs 2 yes -" } - - let(:this_mount) { "/dev/dsk/c0t2d0s7 /dev/rdsk/c0t2d0s7 /mnt/foo ufs 2 yes -" } - - let(:comment) { "#/dev/dsk/c0t2d0s7 /dev/rdsk/c0t2d0s7 /mnt/foo ufs 2 yes -" } - - let(:vfstab_file_contents) { [other_mount, this_mount, comment].join("\n") } - - before do - provider.stub(:etc_tempfile).and_yield(Tempfile.open("vfstab")) - provider.disable_fs - end - - it "should leave the other mountpoint alone" do - IO.read(vfstab_file.path).should match(/^#{Regexp.escape(other_mount)}/) - end - - it "should disable the mountpoint we care about" do - IO.read(vfstab_file.path).should_not match(/^#{Regexp.escape(this_mount)}/) - end - - it "should keep the comment" do - IO.read(vfstab_file.path).should match(/^#{Regexp.escape(comment)}/) - end - end - - context "when there is a duplicated line" do - let(:other_mount) { "/dev/dsk/c0t2d0s0 /dev/rdsk/c0t2d0s0 / ufs 2 yes -" } - - let(:this_mount) { "/dev/dsk/c0t2d0s7 /dev/rdsk/c0t2d0s7 /mnt/foo ufs 2 yes -" } - - let(:vfstab_file_contents) { [this_mount, other_mount, this_mount].join("\n") } - - before do - provider.stub(:etc_tempfile).and_yield(Tempfile.open("vfstab")) - provider.disable_fs - end - - it "should leave the other mountpoint alone" do - IO.read(vfstab_file.path).should match(/^#{Regexp.escape(other_mount)}/) - end - - it "should still match the duplicated mountpoint" do - IO.read(vfstab_file.path).should match(/^#{Regexp.escape(this_mount)}/) - end - - it "should have removed the last line" do - IO.read(vfstab_file.path).should eql( "#{this_mount}\n#{other_mount}\n" ) - end - end - end - end -end diff --git a/spec/unit/provider/mount/windows_spec.rb b/spec/unit/provider/mount/windows_spec.rb deleted file mode 100644 index 80e7f1e695..0000000000 --- a/spec/unit/provider/mount/windows_spec.rb +++ /dev/null @@ -1,137 +0,0 @@ -# -# Author:: Doug MacEachern (<dougm@vmware.com>) -# Copyright:: Copyright (c) 2010 VMware, 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 Chef - class Util - class Windows - class NetUse - end - class Volume - end - end - end -end - -GUID = "\\\\?\\Volume{578e72b5-6e70-11df-b5c5-000c29d4a7d9}\\" -REMOTE = "\\\\server-name\\path" - -describe Chef::Provider::Mount::Windows do - before(:each) do - @node = Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - @new_resource = Chef::Resource::Mount.new("X:") - @new_resource.device GUID - @current_resource = Chef::Resource::Mount.new("X:") - Chef::Resource::Mount.stub(:new).and_return(@current_resource) - - @net_use = double("Chef::Util::Windows::NetUse") - Chef::Util::Windows::NetUse.stub(:new).and_return(@net_use) - @vol = double("Chef::Util::Windows::Volume") - Chef::Util::Windows::Volume.stub(:new).and_return(@vol) - - @provider = Chef::Provider::Mount::Windows.new(@new_resource, @run_context) - @provider.current_resource = @current_resource - end - - describe "when loading the current resource" do - it "should set mounted true if the mount point is found" do - @vol.stub(:device).and_return(@new_resource.device) - @current_resource.should_receive(:mounted).with(true) - @provider.load_current_resource - end - - it "should set mounted false if the mount point is not found" do - @vol.stub(:device).and_raise(ArgumentError) - @current_resource.should_receive(:mounted).with(false) - @provider.load_current_resource - end - - describe "with a local device" do - before do - @new_resource.device GUID - @vol.stub(:device).and_return(@new_resource.device) - @net_use.stub(:device).and_raise(ArgumentError) - end - - it "should determine the device is a volume GUID" do - @provider.should_receive(:is_volume).with(@new_resource.device).and_return(true) - @provider.load_current_resource - end - end - - describe "with a remote device" do - before do - @new_resource.device REMOTE - @net_use.stub(:device).and_return(@new_resource.device) - @vol.stub(:device).and_raise(ArgumentError) - end - - it "should determine the device is remote" do - @provider.should_receive(:is_volume).with(@new_resource.device).and_return(false) - @provider.load_current_resource - end - end - - describe "when mounting a file system" do - before do - @new_resource.device GUID - @vol.stub(:add) - @vol.stub(:device).and_raise(ArgumentError) - @provider.load_current_resource - end - - it "should mount the filesystem if it is not mounted" do - @vol.should_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" do - @vol.should_not_receive(:add) - @current_resource.stub(:mounted).and_return(true) - @provider.mount_fs - end - end - - describe "when unmounting a file system" do - before do - @new_resource.device GUID - @vol.stub(:delete) - @vol.stub(:device).and_raise(ArgumentError) - @provider.load_current_resource - end - - it "should umount the filesystem if it is mounted" do - @current_resource.stub(:mounted).and_return(true) - @vol.should_receive(:delete) - @provider.umount_fs - end - - it "should not umount the filesystem if it is not mounted" do - @current_resource.stub(:mounted).and_return(false) - @vol.should_not_receive(:delete) - @provider.umount_fs - end - end - end -end diff --git a/spec/unit/provider/mount_spec.rb b/spec/unit/provider/mount_spec.rb deleted file mode 100644 index e9fe3fa050..0000000000 --- a/spec/unit/provider/mount_spec.rb +++ /dev/null @@ -1,193 +0,0 @@ -# -# Author:: Joshua Timberman (<joshua@getchef.com>) -# Author:: Lamont Granquist (<lamont@getchef.com>) -# Copyright:: Copyright (c) 2008-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' - -describe Chef::Provider::Mount do - - let(:node) { Chef::Node.new } - - let(:events) { Chef::EventDispatch::Dispatcher.new } - - let(:run_context) { Chef::RunContext.new(node, {}, events) } - - let(:new_resource) do - new_resource = Chef::Resource::Mount.new('/tmp/foo') - new_resource.device "/dev/sdz1" - new_resource.name "/tmp/foo" - new_resource.mount_point "/tmp/foo" - new_resource.fstype "ext3" - new_resource - end - - let(:current_resource) do - # this abstract superclass has no load_current_resource to call - current_resource = Chef::Resource::Mount.new('/tmp/foo') - current_resource.device "/dev/sdz1" - current_resource.name "/tmp/foo" - current_resource.mount_point "/tmp/foo" - current_resource.fstype "ext3" - current_resource - end - - let(:provider) do - provider = Chef::Provider::Mount.new(new_resource, run_context) - provider.current_resource = current_resource - provider - end - - describe "when the target state is a mounted filesystem" do - - it "should mount the filesystem if it isn't mounted" do - allow(current_resource).to receive(:mounted).and_return(false) - 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" do - allow(current_resource).to receive(:mounted).and_return(true) - expect(provider).not_to receive(:mount_fs) - provider.run_action(:mount) - expect(new_resource).not_to be_updated_by_last_action - end - - end - - describe "when the target state is an unmounted filesystem" do - it "should umount the filesystem if it is mounted" do - allow(current_resource).to receive(:mounted).and_return(true) - expect(provider).to receive(:umount_fs).and_return(true) - provider.run_action(:umount) - expect(new_resource).to be_updated_by_last_action - end - - it "should not umount the filesystem if it is not mounted" do - allow(current_resource).to receive(:mounted).and_return(false) - expect(provider).not_to receive(:umount_fs) - provider.run_action(:umount) - expect(new_resource).not_to be_updated_by_last_action - end - end - - describe "when the filesystem should be remounted and the resource supports remounting" do - before do - new_resource.supports[:remount] = true - end - - it "should remount the filesystem if it is mounted" do - allow(current_resource).to receive(:mounted).and_return(true) - expect(provider).to receive(:remount_fs).and_return(true) - provider.run_action(:remount) - expect(new_resource).to be_updated_by_last_action - end - - it "should not remount the filesystem if it is not mounted" do - allow(current_resource).to receive(:mounted).and_return(false) - expect(provider).not_to receive(:remount_fs) - provider.run_action(:remount) - expect(new_resource).not_to be_updated_by_last_action - end - end - - describe "when the filesystem should be remounted and the resource does not support remounting" do - before do - new_resource.supports[:remount] = false - allow(current_resource).to receive(:mounted).and_return(true) - end - - it "should try a umount/remount of the filesystem" do - expect(provider).to receive(:umount_fs) - expect(provider).to receive(:mounted?).and_return(true, false) - expect(provider).to receive(:mount_fs) - provider.run_action(:remount) - expect(new_resource).to be_updated_by_last_action - end - - it "should fail when it runs out of remounts" 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) - end - end - - describe "when enabling the filesystem to be mounted" do - it "should enable the mount if it isn't enable" do - allow(current_resource).to receive(:enabled).and_return(false) - expect(provider).not_to receive(:mount_options_unchanged?) - expect(provider).to receive(:enable_fs).and_return(true) - provider.run_action(:enable) - expect(new_resource).to be_updated_by_last_action - end - - it "should enable the mount if it is enabled and mount options have changed" do - allow(current_resource).to receive(:enabled).and_return(true) - expect(provider).to receive(:mount_options_unchanged?).and_return(false) - expect(provider).to receive(:enable_fs).and_return(true) - provider.run_action(:enable) - expect(new_resource).to be_updated_by_last_action - end - - it "should not enable the mount if it is enabled and mount options have not changed" do - allow(current_resource).to receive(:enabled).and_return(true) - expect(provider).to receive(:mount_options_unchanged?).and_return(true) - expect(provider).not_to receive(:enable_fs) - provider.run_action(:enable) - expect(new_resource).not_to be_updated_by_last_action - end - end - - describe "when the target state is to disable the mount" do - it "should disable the mount if it is enabled" do - allow(current_resource).to receive(:enabled).and_return(true) - expect(provider).to receive(:disable_fs).and_return(true) - provider.run_action(:disable) - expect(new_resource).to be_updated_by_last_action - end - - it "should not disable the mount if it isn't enabled" do - allow(current_resource).to receive(:enabled).and_return(false) - expect(provider).not_to receive(:disable_fs) - provider.run_action(:disable) - expect(new_resource).not_to be_updated_by_last_action - end - end - - - it "should delegates the mount implementation to subclasses" do - expect { provider.mount_fs }.to raise_error(Chef::Exceptions::UnsupportedAction) - end - - it "should delegates the umount implementation to subclasses" do - expect { provider.umount_fs }.to raise_error(Chef::Exceptions::UnsupportedAction) - end - - it "should delegates the remount implementation to subclasses" do - expect { provider.remount_fs }.to raise_error(Chef::Exceptions::UnsupportedAction) - end - - it "should delegates the enable implementation to subclasses" do - expect { provider.enable_fs }.to raise_error(Chef::Exceptions::UnsupportedAction) - end - - it "should delegates the disable implementation to subclasses" do - expect { provider.disable_fs }.to raise_error(Chef::Exceptions::UnsupportedAction) - end -end diff --git a/spec/unit/provider/ohai_spec.rb b/spec/unit/provider/ohai_spec.rb deleted file mode 100644 index 29c32e2690..0000000000 --- a/spec/unit/provider/ohai_spec.rb +++ /dev/null @@ -1,84 +0,0 @@ -# -# Author:: Michael Leinartas (<mleinartas@gmail.com>) -# Copyright:: Copyright (c) 2010 Michael Leinartas -# 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/run_context' - -describe Chef::Provider::Ohai do - before(:each) do - # Copied from client_spec - @fqdn = "hostname.domainname" - @hostname = "hostname" - @platform = "example-platform" - @platform_version = "example-platform" - Chef::Config[:node_name] = @fqdn - mock_ohai = { - :fqdn => @fqdn, - :hostname => @hostname, - :platform => @platform, - :platform_version => @platform_version, - :data => { - :origdata => "somevalue" - }, - :data2 => { - :origdata => "somevalue", - :newdata => "somevalue" - } - } - mock_ohai.stub(:all_plugins).and_return(true) - mock_ohai.stub(:data).and_return(mock_ohai[:data], - mock_ohai[:data2]) - Ohai::System.stub(:new).and_return(mock_ohai) - Chef::Platform.stub(:find_platform_and_version).and_return({ "platform" => @platform, - "platform_version" => @platform_version}) - # Fake node with a dummy save - @node = Chef::Node.new - @node.name(@fqdn) - @node.stub(:save).and_return(@node) - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - @new_resource = Chef::Resource::Ohai.new("ohai_reload") - ohai = Ohai::System.new - ohai.all_plugins - @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' - end - - it "applies updated ohai data to the node" do - @node[:origdata].should == 'somevalue' - @node[:newdata].should be_nil - @provider.run_action(:reload) - @node[:origdata].should == 'somevalue' - @node[:newdata].should == '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) - @node[:origdata].should == 'somevalue' - @node[:newdata].should == 'somevalue' - end - end -end diff --git a/spec/unit/provider/package/aix_spec.rb b/spec/unit/provider/package/aix_spec.rb deleted file mode 100644 index 5d6e23302f..0000000000 --- a/spec/unit/provider/package/aix_spec.rb +++ /dev/null @@ -1,159 +0,0 @@ -# -# Author:: Deepali Jagtap (deepali.jagtap@clogeny.com) -# Author:: Prabhu Das (prabhu.das@clogeny.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::Package::Aix 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("samba.base") - @new_resource.source("/tmp/samba.base") - - @provider = Chef::Provider::Package::Aix.new(@new_resource, @run_context) - ::File.stub(:exists?).and_return(true) - end - - 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:" - - @status = double("Status", :exitstatus => 0) - end - - it "should create a current resource with the name of new_resource" do - @provider.stub(:popen4).and_return(@status) - @provider.load_current_resource - @provider.current_resource.name.should == "samba.base" - end - - it "should set the current resource bff package name to the new resource bff package name" do - @provider.stub(:popen4).and_return(@status) - @provider.load_current_resource - @provider.current_resource.package_name.should == "samba.base" - end - - it "should raise an exception if a source is supplied but not found" do - @provider.stub(:popen4).and_return(@status) - ::File.stub(:exists?).and_return(false) - @provider.define_resource_requirements - @provider.load_current_resource - lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Package) - end - - it "should get the source package version from lslpp if provided" do - @stdout = StringIO.new(@bffinfo) - @stdin, @stderr = StringIO.new, StringIO.new - @provider.should_receive(:popen4).with("installp -L -d /tmp/samba.base").and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @provider.should_receive(:popen4).with("lslpp -lcq samba.base").and_return(@status) - @provider.load_current_resource - - @provider.current_resource.package_name.should == "samba.base" - @new_resource.version.should == "3.3.12.0" - end - - it "should return the current version installed if found by lslpp" do - @stdout = StringIO.new(@bffinfo) - @stdin, @stderr = StringIO.new, StringIO.new - @provider.should_receive(:popen4).with("installp -L -d /tmp/samba.base").and_return(@status) - @provider.should_receive(:popen4).with("lslpp -lcq samba.base").and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @provider.load_current_resource - @provider.current_resource.version.should == "3.3.12.0" - end - - it "should raise an exception if the source is not set but we are installing" do - @new_resource = Chef::Resource::Package.new("samba.base") - @provider = Chef::Provider::Package::Aix.new(@new_resource, @run_context) - @provider.stub(:popen4).and_return(@status) - lambda { @provider.run_action(:install) }.should raise_error(Chef::Exceptions::Package) - end - - it "should raise an exception if installp/lslpp fails to run" do - @status = double("Status", :exitstatus => -1) - @provider.stub(:popen4).and_return(@status) - lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Package) - end - - it "should return a current resource with a nil version if the package is not found" do - @stdout = StringIO.new - @provider.should_receive(:popen4).with("installp -L -d /tmp/samba.base").and_return(@status) - @provider.should_receive(:popen4).with("lslpp -lcq samba.base").and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @provider.load_current_resource - @provider.current_resource.version.should be_nil - end - end - - describe "candidate_version" do - it "should return the candidate_version variable if already setup" do - @provider.candidate_version = "3.3.12.0" - @provider.should_not_receive(:popen4) - @provider.candidate_version - end - - it "should lookup the candidate_version if the variable is not already set" do - @status = double("Status", :exitstatus => 0) - @provider.should_receive(:popen4).and_return(@status) - @provider.candidate_version - end - - it "should throw and exception if the exitstatus is not 0" do - @status = double("Status", :exitstatus => 1) - @provider.stub(:popen4).and_return(@status) - lambda { @provider.candidate_version }.should raise_error(Chef::Exceptions::Package) - end - - end - - describe "install and upgrade" do - it "should run installp -aYF -d with the package source to install" do - @provider.should_receive(:shell_out!).with("installp -aYF -d /tmp/samba.base samba.base") - @provider.install_package("samba.base", "3.3.12.0") - end - - it "should run when the package is a path to install" do - @new_resource = Chef::Resource::Package.new("/tmp/samba.base") - @provider = Chef::Provider::Package::Aix.new(@new_resource, @run_context) - @new_resource.source.should == "/tmp/samba.base" - @provider.should_receive(:shell_out!).with("installp -aYF -d /tmp/samba.base /tmp/samba.base") - @provider.install_package("/tmp/samba.base", "3.3.12.0") - end - - it "should run installp with -eLogfile option." do - @new_resource.stub(:options).and_return("-e/tmp/installp.log") - @provider.should_receive(:shell_out!).with("installp -aYF -e/tmp/installp.log -d /tmp/samba.base samba.base") - @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 - @provider.should_receive(:shell_out!).with("installp -u samba.base") - @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 - @new_resource.stub(:options).and_return("-e/tmp/installp.log") - @provider.should_receive(:shell_out!).with("installp -u -e/tmp/installp.log samba.base") - @provider.remove_package("samba.base", "3.3.12.0") - end - - end -end diff --git a/spec/unit/provider/package/apt_spec.rb b/spec/unit/provider/package/apt_spec.rb deleted file mode 100644 index a94b248418..0000000000 --- a/spec/unit/provider/package/apt_spec.rb +++ /dev/null @@ -1,360 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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 'ostruct' - -describe Chef::Provider::Package::Apt 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("irssi", @run_context) - - @status = double("Status", :exitstatus => 0) - @provider = Chef::Provider::Package::Apt.new(@new_resource, @run_context) - @stdin = StringIO.new - @stdout =<<-PKG_STATUS -irssi: - Installed: (none) - Candidate: 0.8.14-1ubuntu4 - Version table: - 0.8.14-1ubuntu4 0 - 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) - @timeout = 900 - end - - describe "when loading current resource" do - - it "should create a current resource with the name of the new_resource" do - @provider.should_receive(:shell_out!).with( - "apt-cache policy #{@new_resource.package_name}", - :timeout => @timeout - ).and_return(@shell_out) - @provider.load_current_resource - - current_resource = @provider.current_resource - current_resource.should be_a(Chef::Resource::Package) - current_resource.name.should == "irssi" - current_resource.package_name.should == "irssi" - current_resource.version.should be_nil - end - - it "should set the installed version if package has one" do - @stdout.replace(<<-INSTALLED) -sudo: - Installed: 1.7.2p1-1ubuntu5.3 - Candidate: 1.7.2p1-1ubuntu5.3 - Version table: - *** 1.7.2p1-1ubuntu5.3 0 - 500 http://us.archive.ubuntu.com/ubuntu/ lucid-updates/main Packages - 500 http://security.ubuntu.com/ubuntu/ lucid-security/main Packages - 100 /var/lib/dpkg/status - 1.7.2p1-1ubuntu5 0 - 500 http://us.archive.ubuntu.com/ubuntu/ lucid/main Packages -INSTALLED - @provider.should_receive(:shell_out!).and_return(@shell_out) - @provider.load_current_resource - @provider.current_resource.version.should == "1.7.2p1-1ubuntu5.3" - @provider.candidate_version.should eql("1.7.2p1-1ubuntu5.3") - end - - # libmysqlclient-dev is a real package in newer versions of debian + ubuntu - # 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 -libmysqlclient15-dev: - Installed: (none) - Candidate: (none) - Version table: -VPKG_STDOUT - virtual_package = double(:stdout => virtual_package_out,:exitstatus => 0) - @provider.should_receive(:shell_out!).with( - "apt-cache policy libmysqlclient15-dev", - :timeout => @timeout - ).and_return(virtual_package) - showpkg_out =<<-SHOWPKG_STDOUT -Package: libmysqlclient15-dev -Versions: - -Reverse Depends: - libmysqlclient-dev,libmysqlclient15-dev - libmysqlclient-dev,libmysqlclient15-dev - libmysqlclient-dev,libmysqlclient15-dev - libmysqlclient-dev,libmysqlclient15-dev - libmysqlclient-dev,libmysqlclient15-dev - libmysqlclient-dev,libmysqlclient15-dev -Dependencies: -Provides: -Reverse Provides: -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) - @provider.should_receive(:shell_out!).with( - "apt-cache showpkg libmysqlclient15-dev", - :timeout => @timeout - ).and_return(showpkg) - real_package_out=<<-RPKG_STDOUT -libmysqlclient-dev: - Installed: 5.1.41-3ubuntu12.10 - Candidate: 5.1.41-3ubuntu12.10 - Version table: - *** 5.1.41-3ubuntu12.10 0 - 500 http://us.archive.ubuntu.com/ubuntu/ lucid-updates/main Packages - 100 /var/lib/dpkg/status - 5.1.41-3ubuntu12.7 0 - 500 http://security.ubuntu.com/ubuntu/ lucid-security/main Packages - 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) - @provider.should_receive(:shell_out!).with( - "apt-cache policy libmysqlclient-dev", - :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 -mp3-decoder: - Installed: (none) - Candidate: (none) - Version table: -VPKG_STDOUT - virtual_package = double(:stdout => virtual_package_out,:exitstatus => 0) - @provider.should_receive(:shell_out!).with( - "apt-cache policy mp3-decoder", - :timeout => @timeout - ).and_return(virtual_package) - showpkg_out=<<-SHOWPKG_STDOUT -Package: mp3-decoder -Versions: - -Reverse Depends: - nautilus,mp3-decoder - vux,mp3-decoder - plait,mp3-decoder - ecasound,mp3-decoder - nautilus,mp3-decoder -Dependencies: -Provides: -Reverse Provides: -vlc-nox 1.0.6-1ubuntu1.8 -vlc 1.0.6-1ubuntu1.8 -vlc-nox 1.0.6-1ubuntu1 -vlc 1.0.6-1ubuntu1 -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) - @provider.should_receive(:shell_out!).with( - "apt-cache showpkg mp3-decoder", - :timeout => @timeout - ).and_return(showpkg) - lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Package) - end - - it "should run apt-cache policy with the default_release option, if there is one and provider is explicitly defined" do - @new_resource = Chef::Resource::AptPackage.new("irssi", @run_context) - @provider = Chef::Provider::Package::Apt.new(@new_resource, @run_context) - - @new_resource.stub(:default_release).and_return("lenny-backports") - @new_resource.stub(:provider).and_return("Chef::Provider::Package::Apt") - @provider.should_receive(:shell_out!).with( - "apt-cache -o APT::Default-Release=lenny-backports policy irssi", - :timeout => @timeout - ).and_return(@shell_out) - @provider.load_current_resource - end - - it "raises an exception if a source is specified (CHEF-5113)" do - @new_resource.source "pluto" - @provider.define_resource_requirements - @provider.should_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 - - context "after loading the current resource" do - before do - @current_resource = Chef::Resource::Package.new("irssi", @run_context) - @provider.current_resource = @current_resource - end - - describe "install_package" do - it "should run apt-get install with the package name and version" do - @provider.should_receive(:shell_out!). with( - "apt-get -q -y install irssi=0.8.12-7", - :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil}, - :timeout => @timeout - ) - @provider.install_package("irssi", "0.8.12-7") - end - - it "should run apt-get install with the package name and version and options if specified" do - @provider.should_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 - ) - @new_resource.options("--force-yes") - @provider.install_package("irssi", "0.8.12-7") - end - - it "should run apt-get install with the package name and version and default_release if there is one and provider is explicitly defined" do - @new_resource = nil - @new_resource = Chef::Resource::AptPackage.new("irssi", @run_context) - @new_resource.default_release("lenny-backports") - - @provider.new_resource = @new_resource - - @provider.should_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 - ) - - @provider.install_package("irssi", "0.8.12-7") - end - end - - describe Chef::Provider::Package::Apt, "upgrade_package" do - - it "should run install_package with the name and version" do - @provider.should_receive(:install_package).with("irssi", "0.8.12-7") - @provider.upgrade_package("irssi", "0.8.12-7") - end - end - - describe Chef::Provider::Package::Apt, "remove_package" do - - it "should run apt-get remove with the package name" do - @provider.should_receive(:shell_out!).with( - "apt-get -q -y remove irssi", - :env => {"DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil}, - :timeout => @timeout - ) - @provider.remove_package("irssi", "0.8.12-7") - end - - it "should run apt-get remove with the package name and options if specified" do - @provider.should_receive(:shell_out!).with( - "apt-get -q -y --force-yes remove irssi", - :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil }, - :timeout => @timeout - ) - @new_resource.options("--force-yes") - - @provider.remove_package("irssi", "0.8.12-7") - end - end - - describe "when purging a package" do - - it "should run apt-get purge with the package name" do - @provider.should_receive(:shell_out!).with( - "apt-get -q -y purge irssi", - :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil }, - :timeout => @timeout - ) - @provider.purge_package("irssi", "0.8.12-7") - end - - it "should run apt-get purge with the package name and options if specified" do - @provider.should_receive(:shell_out!).with( - "apt-get -q -y --force-yes purge irssi", - :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil }, - :timeout => @timeout - ) - @new_resource.options("--force-yes") - - @provider.purge_package("irssi", "0.8.12-7") - end - end - - describe "when preseeding a package" do - before(:each) do - @provider.stub(:get_preseed_file).and_return("/tmp/irssi-0.8.12-7.seed") - end - - it "should get the full path to the preseed response file" do - @provider.should_receive(:get_preseed_file).with("irssi", "0.8.12-7").and_return("/tmp/irssi-0.8.12-7.seed") - file = @provider.get_preseed_file("irssi", "0.8.12-7") - - @provider.should_receive(:shell_out!).with( - "debconf-set-selections /tmp/irssi-0.8.12-7.seed", - :env => {"DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil}, - :timeout => @timeout - ) - - @provider.preseed_package(file) - end - - it "should run debconf-set-selections on the preseed file if it has changed" do - @provider.should_receive(:shell_out!).with( - "debconf-set-selections /tmp/irssi-0.8.12-7.seed", - :env => {"DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil}, - :timeout => @timeout - ) - file = @provider.get_preseed_file("irssi", "0.8.12-7") - @provider.preseed_package(file) - end - - it "should not run debconf-set-selections if the preseed file has not changed" do - @provider.stub(:check_package_state) - @current_resource.version "0.8.11" - @new_resource.response_file "/tmp/file" - @provider.stub(:get_preseed_file).and_return(false) - @provider.should_not_receive(:shell_out!) - @provider.run_action(:reconfig) - end - end - - describe "when reconfiguring a package" do - it "should run dpkg-reconfigure package" do - @provider.should_receive(:shell_out!).with( - "dpkg-reconfigure irssi", - :env => {"DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil }, - :timeout => @timeout - ) - @provider.reconfig_package("irssi", "0.8.12-7") - end - end - - describe "when installing a virtual package" do - it "should install the package without specifying a version" do - @provider.is_virtual_package = true - @provider.should_receive(:shell_out!).with( - "apt-get -q -y install libmysqlclient-dev", - :env => {"DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil }, - :timeout => @timeout - ) - @provider.install_package("libmysqlclient-dev", "not_a_real_version") - end - end - end -end diff --git a/spec/unit/provider/package/dpkg_spec.rb b/spec/unit/provider/package/dpkg_spec.rb deleted file mode 100644 index 439a42daa3..0000000000 --- a/spec/unit/provider/package/dpkg_spec.rb +++ /dev/null @@ -1,196 +0,0 @@ -# -# Author:: Bryan McLellan (btm@loftninjas.org) -# Copyright:: Copyright (c) 2009 Bryan McLellan -# 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::Dpkg 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("wget") - @new_resource.source "/tmp/wget_1.11.4-1ubuntu1_amd64.deb" - - @provider = Chef::Provider::Package::Dpkg.new(@new_resource, @run_context) - - @stdin = StringIO.new - @stdout = StringIO.new - @status = double("Status", :exitstatus => 0) - @stderr = StringIO.new - @pid = double("PID") - @provider.stub(:popen4).and_return(@status) - - ::File.stub(:exists?).and_return(true) - 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 - @provider.current_resource.package_name.should == "wget" - end - - it "should raise an exception if a source is supplied but not found" do - @provider.load_current_resource - @provider.define_resource_requirements - ::File.stub(:exists?).and_return(false) - lambda { @provider.run_action(:install) }.should raise_error(Chef::Exceptions::Package) - end - - describe 'gets the source package version from dpkg-deb' do - def check_version(version) - @stdout = StringIO.new("wget\t#{version}") - @provider.stub(:popen4).with("dpkg-deb -W #{@new_resource.source}").and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @provider.load_current_resource - @provider.current_resource.package_name.should == "wget" - @new_resource.version.should == version - end - - it 'if short version provided' do - check_version('1.11.4') - end - - 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') - end - - 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 = StringIO.new("f.o.o-pkg++2\t1.11.4-1ubuntu1") - @provider.stub(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @provider.load_current_resource - @provider.current_resource.package_name.should == "f.o.o-pkg++2" - 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.define_resource_requirements - @provider.load_current_resource - lambda { @provider.run_action(:install)}.should raise_error(Chef::Exceptions::Package) - end - - it "should return the current version installed if found by dpkg" do - @stdout = StringIO.new(<<-DPKG_S) -Package: wget -Status: install ok installed -Priority: important -Section: web -Installed-Size: 1944 -Maintainer: Ubuntu Core developers <ubuntu-devel-discuss@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 - @provider.stub(:popen4).with("dpkg -s wget").and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - - @provider.load_current_resource - @provider.current_resource.version.should == "1.11.4-1ubuntu1" - end - - it "should raise an exception if dpkg fails to run" do - @status = double("Status", :exitstatus => -1) - @provider.stub(:popen4).and_return(@status) - lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Package) - end - end - - describe Chef::Provider::Package::Dpkg, "install and upgrade" do - it "should run dpkg -i with the package source" do - @provider.should_receive(:run_noninteractive).with( - "dpkg -i /tmp/wget_1.11.4-1ubuntu1_amd64.deb" - ) - @provider.install_package("wget", "1.11.4-1ubuntu1") - 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) - @provider.should_receive(:run_noninteractive).with( - "dpkg -i /tmp/wget_1.11.4-1ubuntu1_amd64.deb" - ) - @provider.install_package("/tmp/wget_1.11.4-1ubuntu1_amd64.deb", "1.11.4-1ubuntu1") - 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) - @provider.should_receive(:run_noninteractive).with( - "dpkg -i /tmp/wget_1.11.4-1ubuntu1_amd64.deb" - ) - @provider.upgrade_package("/tmp/wget_1.11.4-1ubuntu1_amd64.deb", "1.11.4-1ubuntu1") - end - - it "should run dpkg -i with the package source and options if specified" do - @provider.should_receive(:run_noninteractive).with( - "dpkg -i --force-yes /tmp/wget_1.11.4-1ubuntu1_amd64.deb" - ) - @new_resource.stub(:options).and_return("--force-yes") - - @provider.install_package("wget", "1.11.4-1ubuntu1") - end - it "should upgrade by running install_package" do - @provider.should_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 - @provider.should_receive(:run_noninteractive).with( - "dpkg -r wget" - ) - @provider.remove_package("wget", "1.11.4-1ubuntu1") - end - - it "should run dpkg -r to remove the package with options if specified" do - @provider.should_receive(:run_noninteractive).with( - "dpkg -r --force-yes wget" - ) - @new_resource.stub(:options).and_return("--force-yes") - - @provider.remove_package("wget", "1.11.4-1ubuntu1") - end - - it "should run dpkg -P to purge the package" do - @provider.should_receive(:run_noninteractive).with( - "dpkg -P wget" - ) - @provider.purge_package("wget", "1.11.4-1ubuntu1") - end - - it "should run dpkg -P to purge the package with options if specified" do - @provider.should_receive(:run_noninteractive).with( - "dpkg -P --force-yes wget" - ) - @new_resource.stub(:options).and_return("--force-yes") - - @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 deleted file mode 100644 index 87cbabcc19..0000000000 --- a/spec/unit/provider/package/easy_install_spec.rb +++ /dev/null @@ -1,112 +0,0 @@ -# -# Author:: Joe Williams (<joe@joetify.com>) -# Copyright:: Copyright (c) 2009 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 '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') - - @provider = Chef::Provider::Package::EasyInstall.new(@new_resource, @run_context) - Chef::Resource::Package.stub(:new).and_return(@current_resource) - - @stdin = StringIO.new - @stdout = StringIO.new - @status = double("Status", :exitstatus => 0) - @stderr = StringIO.new - @pid = 2342 - @provider.stub(:popen4).and_return(@status) - end - - describe "easy_install_binary_path" do - it "should return a Chef::Provider::EasyInstall object" do - provider = Chef::Provider::Package::EasyInstall.new(@node, @new_resource) - provider.should be_a_kind_of(Chef::Provider::Package::EasyInstall) - end - - it "should set the current resources package name to the new resources package name" do - $stdout.stub(:write) - @current_resource.should_receive(:package_name).with(@new_resource.package_name) - @provider.load_current_resource - end - - it "should return a relative path to easy_install if no easy_install_binary is given" do - @provider.easy_install_binary_path.should eql("easy_install") - end - - it "should return a specific path to easy_install if a easy_install_binary is given" do - @new_resource.should_receive(:easy_install_binary).and_return("/opt/local/bin/custom/easy_install") - @provider.easy_install_binary_path.should eql("/opt/local/bin/custom/easy_install") - end - - end - - describe "actions_on_package" do - it "should run easy_install with the package name and version" do - @provider.should_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 - @provider.should_receive(:run_command).with({ - :command => "easy_install --always-unzip \"boto==1.8d\"" - }) - @new_resource.stub(:options).and_return("--always-unzip") - @provider.install_package("boto", "1.8d") - end - - it "should run easy_install with the package name and version" do - @provider.should_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 - @provider.should_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 - @provider.should_receive(:run_command).with({ - :command => "easy_install -x -m boto" - }) - @new_resource.stub(:options).and_return("-x") - @provider.remove_package("boto", "1.8d") - end - - it "should run easy_install -m with the package name and version" do - @provider.should_receive(:run_command).with({ - :command => "easy_install -m boto" - }) - @provider.purge_package("boto", "1.8d") - end - - end -end diff --git a/spec/unit/provider/package/freebsd/pkg_spec.rb b/spec/unit/provider/package/freebsd/pkg_spec.rb deleted file mode 100644 index 9b2493a4c5..0000000000 --- a/spec/unit/provider/package/freebsd/pkg_spec.rb +++ /dev/null @@ -1,274 +0,0 @@ -# -# Authors:: Bryan McLellan (btm@loftninjas.org) -# Matthew Landauer (matthew@openaustralia.org) -# Copyright:: Copyright (c) 2009 Bryan McLellan, Matthew Landauer -# 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 'ostruct' - -describe Chef::Provider::Package::Freebsd::Pkg, "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::Package.new("zsh") - @current_resource = Chef::Resource::Package.new("zsh") - - @provider = Chef::Provider::Package::Freebsd::Pkg.new(@new_resource, @run_context) - @provider.current_resource = @current_resource - ::File.stub(:exist?).with('/usr/ports/Makefile').and_return(false) - end - - describe "when determining the current package state" do - before do - @provider.stub(:ports_candidate_version).and_return("4.3.6") - end - - it "should create a current resource with the name of the new_resource" do - current_resource = Chef::Provider::Package::Freebsd::Pkg.new(@new_resource, @run_context).current_resource - current_resource.name.should == "zsh" - end - - it "should return a version if the package is installed" do - @provider.should_receive(:current_installed_version).and_return("4.3.6_7") - @provider.load_current_resource - @current_resource.version.should == "4.3.6_7" - end - - it "should return nil if the package is not installed" do - @provider.should_receive(:current_installed_version).and_return(nil) - @provider.load_current_resource - @current_resource.version.should be_nil - end - - it "should return a candidate version if it exists" do - @provider.should_receive(:current_installed_version).and_return(nil) - @provider.load_current_resource - @provider.candidate_version.should eql("4.3.6") - end - end - - describe "when querying for package state and attributes" do - before do - #@new_resource = Chef::Resource::Package.new("zsh") - - #@provider = Chef::Provider::Package::Freebsd::Pkg.new(@node, @new_resource) - - #@status = double("Status", :exitstatus => 0) - #@stdin = double("STDIN", :null_object => true) - #@stdout = double("STDOUT", :null_object => true) - #@stderr = double("STDERR", :null_object => true) - #@pid = double("PID", :null_object => true) - end - - it "should return the version number when it is installed" do - pkg_info = OpenStruct.new(:stdout => "zsh-4.3.6_7") - @provider.should_receive(:shell_out!).with('pkg_info -E "zsh*"', :env => nil, :returns => [0,1]).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) - @provider.stub(:package_name).and_return("zsh") - @provider.current_installed_version.should == "4.3.6_7" - end - - it "does not set the current version number when the package is not installed" do - pkg_info = OpenStruct.new(:stdout => "") - @provider.should_receive(:shell_out!).with('pkg_info -E "zsh*"', :env => nil, :returns => [0,1]).and_return(pkg_info) - @provider.stub(:package_name).and_return("zsh") - @provider.current_installed_version.should be_nil - end - - it "should return the port path for a valid port name" do - whereis = OpenStruct.new(:stdout => "zsh: /usr/ports/shells/zsh") - @provider.should_receive(:shell_out!).with("whereis -s zsh", :env => nil).and_return(whereis) - #@provider.should_receive(:popen4).with("whereis -s zsh").and_yield(@pid, @stdin, ["zsh: /usr/ports/shells/zsh"], @stderr).and_return(@status) - @provider.stub(:port_name).and_return("zsh") - @provider.port_path.should == "/usr/ports/shells/zsh" - end - - # Not happy with the form of these tests as they are far too closely tied to the implementation and so very fragile. - it "should return the ports candidate version when given a valid port path" do - @provider.stub(:port_path).and_return("/usr/ports/shells/zsh") - make_v = OpenStruct.new(:stdout => "4.3.6\n", :exitstatus => 0) - @provider.should_receive(:shell_out!).with("make -V PORTVERSION", {:cwd=>"/usr/ports/shells/zsh", :returns=>[0, 1], :env=>nil}).and_return(make_v) - @provider.ports_candidate_version.should == "4.3.6" - end - - it "should figure out the package name when we have ports" do - ::File.stub(:exist?).with('/usr/ports/Makefile').and_return(true) - @provider.stub(:port_path).and_return("/usr/ports/shells/zsh") - make_v = OpenStruct.new(:stdout => "zsh-4.3.6_7\n", :exitstatus => 0) - @provider.should_receive(:shell_out!).with("make -V PKGNAME", {:cwd=>"/usr/ports/shells/zsh", :env=>nil, :returns=>[0, 1]}).and_return(make_v) - #@provider.should_receive(:ports_makefile_variable_value).with("PKGNAME").and_return("zsh-4.3.6_7") - @provider.package_name.should == "zsh" - end - end - - describe Chef::Provider::Package::Freebsd::Pkg, "install_package" do - before(:each) do - @cmd_result = OpenStruct.new(:status => true) - - @provider.current_resource = @current_resource - @provider.stub(:package_name).and_return("zsh") - @provider.stub(:latest_link_name).and_return("zsh") - @provider.stub(:port_path).and_return("/usr/ports/shells/zsh") - end - - it "should run pkg_add -r with the package name" do - @provider.should_receive(:shell_out!).with("pkg_add -r zsh", :env => nil).and_return(@cmd_result) - @provider.install_package("zsh", "4.3.6_7") - end - end - - describe Chef::Provider::Package::Freebsd::Pkg, "port path" do - before do - #@node = Chef::Node.new - @new_resource = Chef::Resource::Package.new("zsh") - @new_resource.cookbook_name = "adventureclub" - @provider = Chef::Provider::Package::Freebsd::Pkg.new(@new_resource, @run_context) - end - - it "should figure out the port path from the package_name using whereis" do - whereis = OpenStruct.new(:stdout => "zsh: /usr/ports/shells/zsh") - @provider.should_receive(:shell_out!).with("whereis -s zsh", :env=>nil).and_return(whereis) - @provider.port_path.should == "/usr/ports/shells/zsh" - end - - it "should use the package_name as the port path when it starts with /" do - new_resource = Chef::Resource::Package.new("/usr/ports/www/wordpress") - provider = Chef::Provider::Package::Freebsd::Pkg.new(new_resource, @run_context) - provider.should_not_receive(:popen4) - provider.port_path.should == "/usr/ports/www/wordpress" - end - - it "should use the package_name as a relative path from /usr/ports when it contains / but doesn't start with it" do - # @new_resource = double( "Chef::Resource::Package", - # :package_name => "www/wordpress", - # :cookbook_name => "xenoparadox") - new_resource = Chef::Resource::Package.new("www/wordpress") - provider = Chef::Provider::Package::Freebsd::Pkg.new(new_resource, @run_context) - provider.should_not_receive(:popen4) - provider.port_path.should == "/usr/ports/www/wordpress" - end - end - - describe Chef::Provider::Package::Freebsd::Pkg, "ruby-iconv (package with a dash in the name)" do - before(:each) do - @new_resource = Chef::Resource::Package.new("ruby-iconv") - @current_resource = Chef::Resource::Package.new("ruby-iconv") - @provider = Chef::Provider::Package::Freebsd::Pkg.new(@new_resource, @run_context) - @provider.current_resource = @current_resource - @provider.stub(:port_path).and_return("/usr/ports/converters/ruby-iconv") - @provider.stub(:package_name).and_return("ruby18-iconv") - @provider.stub(:latest_link_name).and_return("ruby18-iconv") - - @install_result = OpenStruct.new(:status => true) - end - - it "should run pkg_add -r with the package name" do - @provider.should_receive(:shell_out!).with("pkg_add -r ruby18-iconv", :env => nil).and_return(@install_result) - @provider.install_package("ruby-iconv", "1.0") - end - end - - describe Chef::Provider::Package::Freebsd::Pkg, "remove_package" do - before(:each) do - @pkg_delete = OpenStruct.new(:status => true) - @new_resource.version "4.3.6_7" - @current_resource.version "4.3.6_7" - @provider.current_resource = @current_resource - @provider.stub(:package_name).and_return("zsh") - end - - it "should run pkg_delete with the package name and version" do - @provider.should_receive(:shell_out!).with("pkg_delete zsh-4.3.6_7", :env => nil).and_return(@pkg_delete) - @provider.remove_package("zsh", "4.3.6_7") - end - end - - # CHEF-4371 - # There are some port names that contain special characters such as +'s. This breaks the regular expression used to determine what - # version of a package is currently installed and to get the port_path. - # Example package name: bonnie++ - - describe Chef::Provider::Package::Freebsd::Pkg, "bonnie++ (package with a plus in the name :: CHEF-4371)" do - before(:each) do - @new_resource = Chef::Resource::Package.new("bonnie++") - @current_resource = Chef::Resource::Package.new("bonnie++") - @provider = Chef::Provider::Package::Freebsd::Pkg.new(@new_resource, @run_context) - @provider.current_resource = @current_resource - end - - it "should return the port path for a valid port name" do - whereis = OpenStruct.new(:stdout => "bonnie++: /usr/ports/benchmarks/bonnie++") - @provider.should_receive(:shell_out!).with("whereis -s bonnie++", :env => nil).and_return(whereis) - @provider.stub(:port_name).and_return("bonnie++") - @provider.port_path.should == "/usr/ports/benchmarks/bonnie++" - end - - it "should return the version number when it is installed" do - pkg_info = OpenStruct.new(:stdout => "bonnie++-1.96") - @provider.should_receive(:shell_out!).with('pkg_info -E "bonnie++*"', :env => nil, :returns => [0,1]).and_return(pkg_info) - @provider.stub(:package_name).and_return("bonnie++") - @provider.current_installed_version.should == "1.96" - end - end - - # A couple of examples to show up the difficulty of determining the command to install the binary package given the port: - # PORT DIRECTORY INSTALLED PACKAGE NAME COMMAND TO INSTALL PACKAGE - # /usr/ports/lang/perl5.8 perl-5.8.8_1 pkg_add -r perl - # /usr/ports/databases/mysql50-server mysql-server-5.0.45_1 pkg_add -r mysql50-server - # - # So, in one case it appears the command to install the package can be derived from the name of the port directory and in the - # other case it appears the command can be derived from the package name. Very confusing! - # Well, luckily, after much poking around, I discovered that the two can be disambiguated through the use of the LATEST_LINK - # variable which is set by the ports Makefile - # - # PORT DIRECTORY LATEST_LINK INSTALLED PACKAGE NAME COMMAND TO INSTALL PACKAGE - # /usr/ports/lang/perl5.8 perl perl-5.8.8_1 pkg_add -r perl - # /usr/ports/databases/mysql50-server mysql50-server mysql-server-5.0.45_1 pkg_add -r mysql50-server - # - # The variable LATEST_LINK is named that way because the directory that "pkg_add -r" downloads from is called "Latest" and - # contains the "latest" versions of package as symbolic links to the files in the "All" directory. - - describe Chef::Provider::Package::Freebsd::Pkg, "install_package latest link fixes" do - it "should install the perl binary package with the correct name" do - @new_resource = Chef::Resource::Package.new("perl5.8") - @current_resource = Chef::Resource::Package.new("perl5.8") - @provider = Chef::Provider::Package::Freebsd::Pkg.new(@new_resource, @run_context) - @provider.current_resource = @current_resource - @provider.stub(:package_name).and_return("perl") - @provider.stub(:latest_link_name).and_return("perl") - - cmd = OpenStruct.new(:status => true) - @provider.should_receive(:shell_out!).with("pkg_add -r perl", :env => nil).and_return(cmd) - @provider.install_package("perl5.8", "5.8.8_1") - end - - it "should install the mysql50-server binary package with the correct name" do - - @new_resource = Chef::Resource::Package.new("mysql50-server") - @current_resource = Chef::Resource::Package.new("mysql50-server") - @provider = Chef::Provider::Package::Freebsd::Pkg.new(@new_resource, @run_context) - @provider.current_resource = @current_resource - @provider.stub(:package_name).and_return("mysql-server") - @provider.stub(:latest_link_name).and_return("mysql50-server") - - cmd = OpenStruct.new(:status => true) - @provider.should_receive(:shell_out!).with("pkg_add -r mysql50-server", :env=>nil).and_return(cmd) - @provider.install_package("mysql50-server", "5.0.45_1") - end - end -end diff --git a/spec/unit/provider/package/freebsd/pkgng_spec.rb b/spec/unit/provider/package/freebsd/pkgng_spec.rb deleted file mode 100644 index c3837a251b..0000000000 --- a/spec/unit/provider/package/freebsd/pkgng_spec.rb +++ /dev/null @@ -1,155 +0,0 @@ -# -# Authors:: Richard Manyanza (liseki@nyikacraftsmen.com) -# Copyright:: Copyright (c) 2014 Richard Manyanza -# 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 'ostruct' - -describe Chef::Provider::Package::Freebsd::Port 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("zsh") - @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 - @provider.current_resource.is_a?(Chef::Resource::Package).should be_true - @provider.current_resource.name.should == 'zsh' - end - end - - - describe "loading current resource" do - before(:each) do - @provider.stub(:current_installed_version) - @provider.stub(:candidate_version) - end - - it "should set the package name" do - @provider.load_current_resource - @provider.current_resource.package_name.should == "zsh" - end - - it "should set the current version" do - @provider.should_receive(:current_installed_version).and_return("5.0.2") - @provider.load_current_resource - @provider.current_resource.version.should == "5.0.2" - end - - it "should set the candidate version" do - @provider.should_receive(:candidate_version).and_return("5.0.5") - @provider.load_current_resource - @provider.instance_variable_get(:"@candidate_version").should == "5.0.5" - end - end - - - describe "determining current installed version" do - before(:each) do - @provider.stub(:supports_pkgng?) - @pkg_info = OpenStruct.new(:stdout => "zsh-3.1.7\nVersion : 3.1.7\n") - end - - it "should query pkg database" do - @provider.should_receive(:shell_out!).with('pkg info "zsh"', :env => nil, :returns => [0,70]).and_return(@pkg_info) - @provider.current_installed_version.should == "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) - @provider.should_receive(:shell_out!).with("pkg rquery '%v' zsh", :env => nil).and_return(pkg_query) - @provider.candidate_version.should == "5.0.5" - end - - it "should query specified repository when given option" do - @provider.new_resource.options('-r LocalMirror') # This requires LocalMirror repo configuration. - pkg_query = OpenStruct.new(:stdout => "5.0.3\n", :exitstatus => 0) - @provider.should_receive(:shell_out!).with("pkg rquery -r LocalMirror '%v' zsh", :env => nil).and_return(pkg_query) - @provider.candidate_version.should == "5.0.3" - end - - it "should return candidate version from file when given a file" do - @provider.new_resource.source("/nas/pkg/repo/zsh-5.0.1.txz") - @provider.candidate_version.should == "5.0.1" - end - end - - - describe "installing a binary package" do - before(:each) do - @install_result = OpenStruct.new(:status => true) - end - - it "should handle package source from file" do - @provider.new_resource.source("/nas/pkg/repo/zsh-5.0.1.txz") - @provider.should_receive(:shell_out!). - with("pkg add /nas/pkg/repo/zsh-5.0.1.txz", :env => { 'LC_ALL' => nil }). - and_return(@install_result) - @provider.install_package("zsh", "5.0.1") - end - - it "should handle package source over ftp or http" do - @provider.new_resource.source("http://repo.example.com/zsh-5.0.1.txz") - @provider.should_receive(:shell_out!). - with("pkg add http://repo.example.com/zsh-5.0.1.txz", :env => { 'LC_ALL' => nil }). - and_return(@install_result) - @provider.install_package("zsh", "5.0.1") - end - - it "should handle a package name" do - @provider.should_receive(:shell_out!). - with("pkg install -y zsh", :env => { 'LC_ALL' => nil }).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.should_receive(:shell_out!). - with("pkg install -y -r LocalMirror zsh", :env => { 'LC_ALL' => nil }).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) - end - - it "should call pkg delete" do - @provider.should_receive(:shell_out!). - with("pkg delete -y zsh-5.0.1", :env => nil).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.should_receive(:shell_out!). - with("pkg delete -y zsh-5.0.1", :env => nil).and_return(@install_result) - @provider.remove_package("zsh", "5.0.1") - end - end -end diff --git a/spec/unit/provider/package/freebsd/port_spec.rb b/spec/unit/provider/package/freebsd/port_spec.rb deleted file mode 100644 index e946719451..0000000000 --- a/spec/unit/provider/package/freebsd/port_spec.rb +++ /dev/null @@ -1,160 +0,0 @@ -# -# Authors:: Richard Manyanza (liseki@nyikacraftsmen.com) -# Copyright:: Copyright (c) 2014 Richard Manyanza -# 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 'ostruct' - -describe Chef::Provider::Package::Freebsd::Port 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("zsh") - @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 - @provider.current_resource.is_a?(Chef::Resource::Package).should be_true - @provider.current_resource.name.should == 'zsh' - end - end - - - describe "loading current resource" do - before(:each) do - @provider.stub(:current_installed_version) - @provider.stub(:candidate_version) - end - - it "should set the package name" do - @provider.load_current_resource - @provider.current_resource.package_name.should == "zsh" - end - - it "should set the current version" do - @provider.should_receive(:current_installed_version).and_return("5.0.2") - @provider.load_current_resource - @provider.current_resource.version.should == "5.0.2" - end - - it "should set the candidate version" do - @provider.should_receive(:candidate_version).and_return("5.0.5") - @provider.load_current_resource - @provider.instance_variable_get(:"@candidate_version").should == "5.0.5" - end - end - - - describe "determining current installed version" do - before(:each) do - @provider.stub(:supports_pkgng?) - @pkg_info = OpenStruct.new(:stdout => "zsh-3.1.7\n") - end - - it "should check 'pkg_info' if system uses pkg_* tools" do - @provider.should_receive(:supports_pkgng?).and_return(false) - @provider.should_receive(:shell_out!).with('pkg_info -E "zsh*"', :env => nil, :returns => [0,1]).and_return(@pkg_info) - @provider.current_installed_version.should == "3.1.7" - end - - it "should check 'pkg info' if system uses pkgng" do - @provider.should_receive(:supports_pkgng?).and_return(true) - @provider.should_receive(:shell_out!).with('pkg info "zsh"', :env => nil, :returns => [0,70]).and_return(@pkg_info) - @provider.current_installed_version.should == "3.1.7" - end - end - - - describe "determining candidate version" do - before(:each) do - @port_version = OpenStruct.new(:stdout => "5.0.5\n", :exitstatus => 0) - end - - it "should return candidate version if port exists" do - ::File.stub(:exist?).with('/usr/ports/Makefile').and_return(true) - @provider.stub(:port_dir).and_return('/usr/ports/shells/zsh') - @provider.should_receive(:shell_out!).with("make -V PORTVERSION", :cwd => "/usr/ports/shells/zsh", :env => nil, :returns => [0,1]). - and_return(@port_version) - @provider.candidate_version.should == "5.0.5" - end - - it "should raise exception if ports tree not found" do - ::File.stub(: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 - @provider.new_resource.stub(:package_name).and_return("/var/ports/shells/zsh") - @provider.port_dir.should == "/var/ports/shells/zsh" - end - - it "should return full ports path given package name and category" do - @provider.new_resource.stub(:package_name).and_return("shells/zsh") - @provider.port_dir.should == "/usr/ports/shells/zsh" - end - - it "should query system for path given just a name" do - whereis = OpenStruct.new(:stdout => "zsh: /usr/ports/shells/zsh\n") - @provider.should_receive(:shell_out!).with("whereis -s zsh", :env => nil).and_return(whereis) - @provider.port_dir.should == "/usr/ports/shells/zsh" - end - - it "should raise exception if not found" do - whereis = OpenStruct.new(:stdout => "zsh:\n") - @provider.should_receive(:shell_out!).with("whereis -s zsh", :env => nil).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) - end - - it "should run make install in port directory" do - @provider.stub(:port_dir).and_return("/usr/ports/shells/zsh") - @provider.should_receive(:shell_out!). - with("make -DBATCH install clean", :timeout => 1800, :cwd => "/usr/ports/shells/zsh", :env => nil). - and_return(@install_result) - @provider.install_package("zsh", "5.0.5") - end - end - - - describe "removing a binary package" do - before(:each) do - @install_result = OpenStruct.new(:status => true) - end - - it "should run make deinstall in port directory" do - @provider.stub(:port_dir).and_return("/usr/ports/shells/zsh") - @provider.should_receive(:shell_out!). - with("make deinstall", :timeout => 300, :cwd => "/usr/ports/shells/zsh", :env => nil). - and_return(@install_result) - @provider.remove_package("zsh", "5.0.5") - end - end -end diff --git a/spec/unit/provider/package/homebrew_spec.rb b/spec/unit/provider/package/homebrew_spec.rb deleted file mode 100644 index d38458546d..0000000000 --- a/spec/unit/provider/package/homebrew_spec.rb +++ /dev/null @@ -1,257 +0,0 @@ -# -# Author:: Joshua Timberman (<joshua@getchef.com>) -# Copyright (c) 2014, Chef Software, Inc. <legal@getchef.com> -# -# 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::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(:provider) do - Chef::Provider::Package::Homebrew.new(new_resource, run_context) - end - - let(:homebrew_uid) { 1001 } - - let(:uninstalled_brew_info) do - { - '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' => [] - } - 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' - }, - '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' - }, - 'revision' => 0, - 'installed' => [{ 'version' => '24.3-keggy' }], - 'linked_keg' => nil, - 'keg_only' => true, - 'dependencies' => [], - 'conflicts_with' => [], - 'caveats' => '', - 'options' => [] - } - end - - before(:each) do - - end - - 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') - 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::Package) - 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') - provider.load_current_resource - 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 - provider.load_current_resource - expect(provider.current_resource.version).to be_nil - end - - it 'sets a candidate version if one exists' do - provider.load_current_resource - 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 - allow(provider).to receive(:brew_info).and_return(keg_only_brew_info) - 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 - allow(provider).to receive(:brew_info).and_return(installed_brew_info) - expect(provider.current_installed_version).to eql('24.3') - end - - 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 - end - - 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') - 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') - end - end - - context 'when testing actions' do - before(:each) do - provider.current_resource = current_resource - end - - describe 'install_package' do - before(:each) do - 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') - 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') - end - - 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') - 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') - 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') - 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') - 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') - 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') - end - - 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') - end - - 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') - 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') - 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') - end - - 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') - 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') - 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') - end - - 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') - end - end - end -end diff --git a/spec/unit/provider/package/ips_spec.rb b/spec/unit/provider/package/ips_spec.rb deleted file mode 100644 index 07bca7f6d5..0000000000 --- a/spec/unit/provider/package/ips_spec.rb +++ /dev/null @@ -1,229 +0,0 @@ -# -# Author:: Bryan McLellan <btm@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 'ostruct' - -# based on the apt specs - -describe Chef::Provider::Package::Ips 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("crypto/gnupg", @run_context) - @current_resource = Chef::Resource::Package.new("crypto/gnupg", @run_context) - Chef::Resource::Package.stub(:new).and_return(@current_resource) - @provider = Chef::Provider::Package::Ips.new(@new_resource, @run_context) - end - - def local_output - stdin = StringIO.new - 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) - end - - def remote_output - - stdout = <<-PKG_STATUS - Name: security/sudo - Summary: sudo - authority delegation tool - State: Not Installed - Publisher: omnios - Version: 1.8.4.1 (1.8.4p1) - Build Release: 5.11 - Branch: 0.151002 -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) - end - - context "when loading current resource" do - it "should create a current resource with the name of the new_resource" do - @provider.should_receive(:shell_out).with("pkg info #{@new_resource.package_name}").and_return(local_output) - @provider.should_receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}").and_return(remote_output) - Chef::Resource::Package.should_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 - @provider.should_receive(:shell_out).with("pkg info #{@new_resource.package_name}").and_return(local_output) - @provider.should_receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}").and_return(remote_output) - @provider.load_current_resource - @current_resource.package_name.should == @new_resource.package_name - end - - it "should run pkg info with the package name" do - @provider.should_receive(:shell_out).with("pkg info #{@new_resource.package_name}").and_return(local_output) - @provider.should_receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}").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 - @provider.should_receive(:shell_out).with("pkg info #{@new_resource.package_name}").and_return(local_output) - @provider.should_receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}").and_return(remote_output) - @provider.load_current_resource - @current_resource.version.should be_nil - end - - it "should set the installed version if package has one" do - local = local_output - local.stdout = <<-INSTALLED - Name: crypto/gnupg - Summary: GNU Privacy Guard - Description: A complete and free implementation of the OpenPGP Standard as - defined by RFC4880. - Category: Applications/System Utilities - State: Installed - Publisher: solaris - Version: 2.0.17 - Build Release: 5.11 - Branch: 0.175.0.0.0.2.537 -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 - @provider.should_receive(:shell_out).with("pkg info #{@new_resource.package_name}").and_return(local) - @provider.should_receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}").and_return(remote_output) - @provider.load_current_resource - @current_resource.version.should == "2.0.17" - end - - it "should return the current resource" do - @provider.should_receive(:shell_out).with("pkg info #{@new_resource.package_name}").and_return(local_output) - @provider.should_receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}").and_return(remote_output) - @provider.load_current_resource.should eql(@current_resource) - end - end - - context "when installing a package" do - it "should run pkg install with the package name and version" do - @provider.should_receive(:shell_out).with("pkg install -q crypto/gnupg@2.0.17") - @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 - @provider.should_receive(:shell_out).with("pkg --no-refresh install -q crypto/gnupg@2.0.17") - @new_resource.stub(:options).and_return("--no-refresh") - @provider.install_package("crypto/gnupg", "2.0.17") - end - - it "should not include the human-readable version in the candidate_version" do - remote = remote_output - remote.stdout = <<-PKG_STATUS - Name: security/sudo - Summary: sudo - authority delegation tool - State: Not Installed - Publisher: omnios - Version: 1.8.4.1 (1.8.4p1) - Build Release: 5.11 - Branch: 0.151002 -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 - @provider.should_receive(:shell_out).with("pkg info #{@new_resource.package_name}").and_return(local_output) - @provider.should_receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}").and_return(remote) - @provider.load_current_resource - @current_resource.version.should be_nil - @provider.candidate_version.should eql("1.8.4.1") - end - - it "should not upgrade the package if it is already installed" do - local = local_output - local.stdout = <<-INSTALLED - Name: crypto/gnupg - Summary: GNU Privacy Guard - Description: A complete and free implementation of the OpenPGP Standard as - defined by RFC4880. - Category: Applications/System Utilities - State: Installed - Publisher: solaris - Version: 2.0.17 - Build Release: 5.11 - Branch: 0.175.0.0.0.2.537 -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 - remote = remote_output - remote.stdout = <<-REMOTE - Name: crypto/gnupg - Summary: GNU Privacy Guard - Description: A complete and free implementation of the OpenPGP Standard as - defined by RFC4880. - Category: Applications/System Utilities - State: Not Installed - Publisher: solaris - Version: 2.0.18 - Build Release: 5.11 - Branch: 0.175.0.0.0.2.537 -Packaging Date: October 19, 2011 09:14:50 AM - Size: 8.07 MB - FMRI: pkg://solaris/crypto/gnupg@2.0.18,5.11-0.175.0.0.0.2.537:20111019T091450Z -REMOTE - - @provider.should_receive(:shell_out).with("pkg info #{@new_resource.package_name}").and_return(local) - @provider.should_receive(:shell_out!).with("pkg info -r #{@new_resource.package_name}").and_return(remote) - @provider.load_current_resource - @provider.should_receive(:install_package).exactly(0).times - @provider.action_install - end - - context "when accept_license is true" do - before do - @new_resource.stub(:accept_license).and_return(true) - end - - it "should run pkg install with the --accept flag" do - @provider.should_receive(:shell_out).with("pkg install -q --accept crypto/gnupg@2.0.17") - @provider.install_package("crypto/gnupg", "2.0.17") - end - end - end - - context "when upgrading a package" do - it "should run pkg install with the package name and version" do - @provider.should_receive(:shell_out).with("pkg install -q crypto/gnupg@2.0.17") - @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 - @provider.should_receive(:shell_out!).with("pkg uninstall -q crypto/gnupg@2.0.17") - @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 - @provider.should_receive(:shell_out!).with("pkg --no-refresh uninstall -q crypto/gnupg@2.0.17") - @new_resource.stub(:options).and_return("--no-refresh") - @provider.remove_package("crypto/gnupg", "2.0.17") - end - end -end diff --git a/spec/unit/provider/package/macports_spec.rb b/spec/unit/provider/package/macports_spec.rb deleted file mode 100644 index 535a5d2459..0000000000 --- a/spec/unit/provider/package/macports_spec.rb +++ /dev/null @@ -1,203 +0,0 @@ -# -# Author:: David Balatero (<dbalatero@gmail.com>) -# Copyright:: Copyright (c) 2009 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::Package::Macports 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("zsh") - @current_resource = Chef::Resource::Package.new("zsh") - - @provider = Chef::Provider::Package::Macports.new(@new_resource, @run_context) - Chef::Resource::Package.stub(:new).and_return(@current_resource) - - @status = double("Status", :exitstatus => 0) - @stdin = StringIO.new - @stdout = StringIO.new - @stderr = StringIO.new - @pid = 2342 - end - - describe "load_current_resource" do - it "should create a current resource with the name of the new_resource" do - @provider.should_receive(:current_installed_version).and_return(nil) - @provider.should_receive(:macports_candidate_version).and_return("4.2.7") - - @provider.load_current_resource - @provider.current_resource.name.should == "zsh" - end - - it "should create a current resource with the version if the package is installed" do - @provider.should_receive(:macports_candidate_version).and_return("4.2.7") - @provider.should_receive(:current_installed_version).and_return("4.2.7") - - @provider.load_current_resource - @provider.candidate_version.should == "4.2.7" - end - - it "should create a current resource with a nil version if the package is not installed" do - @provider.should_receive(:current_installed_version).and_return(nil) - @provider.should_receive(:macports_candidate_version).and_return("4.2.7") - @provider.load_current_resource - @provider.current_resource.version.should be_nil - end - - it "should set a candidate version if one exists" do - @provider.should_receive(:current_installed_version).and_return(nil) - @provider.should_receive(:macports_candidate_version).and_return("4.2.7") - @provider.load_current_resource - @provider.candidate_version.should == "4.2.7" - end - end - - describe "current_installed_version" do - it "should return the current version if the package is installed" do - @stdout.should_receive(:read).and_return(<<EOF -The following ports are currently installed: - openssl @0.9.8k_0 (active) -EOF - ) - - @provider.should_receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @provider.current_installed_version.should == "0.9.8k_0" - end - - it "should return nil if a package is not currently installed" do - @stdout.should_receive(:read).and_return(" \n") - @provider.should_receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @provider.current_installed_version.should be_nil - end - end - - describe "macports_candidate_version" do - it "should return the latest available version of a given package" do - @stdout.should_receive(:read).and_return("version: 4.2.7\n") - @provider.should_receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @provider.macports_candidate_version.should == "4.2.7" - end - - it "should return nil if there is no version for a given package" do - @stdout.should_receive(:read).and_return("Error: port fadsfadsfads not found\n") - @provider.should_receive(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @provider.macports_candidate_version.should be_nil - end - end - - describe "install_package" do - it "should run the port install command with the correct version" do - @current_resource.should_receive(:version).and_return("4.1.6") - @provider.current_resource = @current_resource - @provider.should_receive(:shell_out!).with("port install zsh @4.2.7") - - @provider.install_package("zsh", "4.2.7") - end - - it "should not do anything if a package already exists with the same version" do - @current_resource.should_receive(:version).and_return("4.2.7") - @provider.current_resource = @current_resource - @provider.should_not_receive(:shell_out!) - - @provider.install_package("zsh", "4.2.7") - end - - it "should add options to the port command when specified" do - @current_resource.should_receive(:version).and_return("4.1.6") - @provider.current_resource = @current_resource - @new_resource.stub(:options).and_return("-f") - @provider.should_receive(:shell_out!).with("port -f install zsh @4.2.7") - - @provider.install_package("zsh", "4.2.7") - end - end - - describe "purge_package" do - it "should run the port uninstall command with the correct version" do - @provider.should_receive(:shell_out!).with("port uninstall zsh @4.2.7") - @provider.purge_package("zsh", "4.2.7") - end - - it "should purge the currently active version if no explicit version is passed in" do - @provider.should_receive(:shell_out!).with("port uninstall zsh") - @provider.purge_package("zsh", nil) - end - - it "should add options to the port command when specified" do - @new_resource.stub(:options).and_return("-f") - @provider.should_receive(:shell_out!).with("port -f uninstall zsh @4.2.7") - @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 - @provider.should_receive(:shell_out!).with("port deactivate zsh @4.2.7") - @provider.remove_package("zsh", "4.2.7") - end - - it "should remove the currently active version if no explicit version is passed in" do - @provider.should_receive(:shell_out!).with("port deactivate zsh") - @provider.remove_package("zsh", nil) - end - - it "should add options to the port command when specified" do - @new_resource.stub(:options).and_return("-f") - @provider.should_receive(:shell_out!).with("port -f deactivate zsh @4.2.7") - @provider.remove_package("zsh", "4.2.7") - end - end - - describe "upgrade_package" do - it "should run the port upgrade command with the correct version" do - @current_resource.should_receive(:version).at_least(:once).and_return("4.1.6") - @provider.current_resource = @current_resource - - @provider.should_receive(:shell_out!).with("port upgrade zsh @4.2.7") - - @provider.upgrade_package("zsh", "4.2.7") - end - - it "should not run the port upgrade command if the version is already installed" do - @current_resource.should_receive(:version).at_least(:once).and_return("4.2.7") - @provider.current_resource = @current_resource - @provider.should_not_receive(:shell_out!) - - @provider.upgrade_package("zsh", "4.2.7") - end - - it "should call install_package if the package isn't currently installed" do - @current_resource.should_receive(:version).at_least(:once).and_return(nil) - @provider.current_resource = @current_resource - @provider.should_receive(:install_package).and_return(true) - - @provider.upgrade_package("zsh", "4.2.7") - end - - it "should add options to the port command when specified" do - @new_resource.stub(:options).and_return("-f") - @current_resource.should_receive(:version).at_least(:once).and_return("4.1.6") - @provider.current_resource = @current_resource - - @provider.should_receive(:shell_out!).with("port -f upgrade zsh @4.2.7") - - @provider.upgrade_package("zsh", "4.2.7") - end - end -end diff --git a/spec/unit/provider/package/pacman_spec.rb b/spec/unit/provider/package/pacman_spec.rb deleted file mode 100644 index 0c1c487980..0000000000 --- a/spec/unit/provider/package/pacman_spec.rb +++ /dev/null @@ -1,198 +0,0 @@ -# -# Author:: Jan Zimmek (<jan.zimmek@web.de>) -# Copyright:: Copyright (c) 2010 Jan Zimmek -# 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::Pacman 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("nano") - @current_resource = Chef::Resource::Package.new("nano") - - @status = double("Status", :exitstatus => 0) - @provider = Chef::Provider::Package::Pacman.new(@new_resource, @run_context) - Chef::Resource::Package.stub(:new).and_return(@current_resource) - @provider.stub(:popen4).and_return(@status) - @stdin = StringIO.new - @stdout = StringIO.new(<<-ERR) -error: package "nano" not found -ERR - @stderr = StringIO.new - @pid = 2342 - end - - describe "when determining the current package state" do - it "should create a current resource with the name of the new_resource" do - Chef::Resource::Package.should_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 - @current_resource.should_receive(:package_name).with(@new_resource.package_name) - @provider.load_current_resource - end - - it "should run pacman query with the package name" do - @provider.should_receive(:popen4).with("pacman -Qi #{@new_resource.package_name}").and_return(@status) - @provider.load_current_resource - end - - it "should read stdout on pacman" do - @provider.stub(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @stdout.should_receive(:each).and_return(true) - @provider.load_current_resource - end - - it "should set the installed version to nil on the current resource if pacman installed version not exists" do - @provider.stub(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @current_resource.should_receive(:version).with(nil).and_return(true) - @provider.load_current_resource - end - - it "should set the installed version if pacman has one" do - @stdout = StringIO.new(<<-PACMAN) -Name : nano -Version : 2.2.2-1 -URL : http://www.nano-editor.org -Licenses : GPL -Groups : base -Provides : None -Depends On : glibc ncurses -Optional Deps : None -Required By : None -Conflicts With : None -Replaces : None -Installed Size : 1496.00 K -Packager : Andreas Radke <andyrtr@archlinux.org> -Architecture : i686 -Build Date : Mon 18 Jan 2010 06:16:16 PM CET -Install Date : Mon 01 Feb 2010 10:06:30 PM CET -Install Reason : Explicitly installed -Install Script : Yes -Description : Pico editor clone with enhancements -PACMAN - @provider.stub(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @provider.load_current_resource - @current_resource.version.should == "2.2.2-1" - end - - it "should set the candidate version if pacman has one" do - @stdout.stub(:each).and_yield("core/nano 2.2.3-1 (base)"). - and_yield(" Pico editor clone with enhancements"). - and_yield("community/nanoblogger 3.4.1-1"). - and_yield(" NanoBlogger is a small weblog engine written in Bash for the command line") - @provider.stub(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @provider.load_current_resource - @provider.candidate_version.should eql("2.2.3-1") - end - - it "should use pacman.conf to determine valid repo names for package versions" do - @pacman_conf = <<-PACMAN_CONF -[options] -HoldPkg = pacman glibc -Architecture = auto - -[customrepo] -Server = https://my.custom.repo - -[core] -Include = /etc/pacman.d/mirrorlist - -[extra] -Include = /etc/pacman.d/mirrorlist - -[community] -Include = /etc/pacman.d/mirrorlist -PACMAN_CONF - - ::File.stub(:exists?).with("/etc/pacman.conf").and_return(true) - ::File.stub(:read).with("/etc/pacman.conf").and_return(@pacman_conf) - @stdout.stub(:each).and_yield("customrepo/nano 1.2.3-4"). - and_yield(" My custom package") - @provider.stub(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - - @provider.load_current_resource - @provider.candidate_version.should eql("1.2.3-4") - end - - it "should raise an exception if pacman fails" do - @status.should_receive(:exitstatus).and_return(2) - lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Package) - end - - it "should not raise an exception if pacman succeeds" do - @status.should_receive(:exitstatus).and_return(0) - lambda { @provider.load_current_resource }.should_not raise_error - end - - it "should raise an exception if pacman does not return a candidate version" do - @stdout.stub(:each).and_yield("") - @provider.stub(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - lambda { @provider.candidate_version }.should raise_error(Chef::Exceptions::Package) - end - - it "should return the current resouce" do - @provider.load_current_resource.should eql(@current_resource) - end - end - - describe Chef::Provider::Package::Pacman, "install_package" do - it "should run pacman install with the package name and version" do - @provider.should_receive(:shell_out!).with("pacman --sync --noconfirm --noprogressbar nano") - @provider.install_package("nano", "1.0") - end - - it "should run pacman install with the package name and version and options if specified" do - @provider.should_receive(:shell_out!).with("pacman --sync --noconfirm --noprogressbar --debug nano") - @new_resource.stub(:options).and_return("--debug") - - @provider.install_package("nano", "1.0") - end - end - - describe Chef::Provider::Package::Pacman, "upgrade_package" do - it "should run install_package with the name and version" do - @provider.should_receive(:install_package).with("nano", "1.0") - @provider.upgrade_package("nano", "1.0") - end - end - - describe Chef::Provider::Package::Pacman, "remove_package" do - it "should run pacman remove with the package name" do - @provider.should_receive(:shell_out!).with("pacman --remove --noconfirm --noprogressbar nano") - @provider.remove_package("nano", "1.0") - end - - it "should run pacman remove with the package name and options if specified" do - @provider.should_receive(:shell_out!).with("pacman --remove --noconfirm --noprogressbar --debug nano") - @new_resource.stub(:options).and_return("--debug") - - @provider.remove_package("nano", "1.0") - end - end - - describe Chef::Provider::Package::Pacman, "purge_package" do - it "should run remove_package with the name and version" do - @provider.should_receive(:remove_package).with("nano", "1.0") - @provider.purge_package("nano", "1.0") - end - - end -end diff --git a/spec/unit/provider/package/paludis_spec.rb b/spec/unit/provider/package/paludis_spec.rb deleted file mode 100644 index c99600e535..0000000000 --- a/spec/unit/provider/package/paludis_spec.rb +++ /dev/null @@ -1,135 +0,0 @@ -# -# Author:: Vasiliy Tolstov <v.tolstov@selfip.ru> -# Copyright:: Copyright (c) 2014 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 'ostruct' - -# based on the ips specs - -describe Chef::Provider::Package::Paludis 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("net/ntp") - @current_resource = Chef::Resource::Package.new("net/ntp") - Chef::Resource::Package.stub(:new).and_return(@current_resource) - @provider = Chef::Provider::Package::Paludis.new(@new_resource, @run_context) - - @stdin = StringIO.new - @stderr = StringIO.new - @stdout =<<-PKG_STATUS -group/ntp 0 accounts -group/ntp 0 installed-accounts -net/ntp 4.2.6_p5-r2 arbor -user/ntp 0 accounts -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) - end - - context "when loading current resource" do - it "should create a current resource with the name of the new_resource" do - @provider.should_receive(:shell_out!).and_return(@shell_out) - Chef::Resource::Package.should_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 - @provider.should_receive(:shell_out!).and_return(@shell_out) - @current_resource.should_receive(:package_name).with(@new_resource.package_name) - @provider.load_current_resource - end - - it "should run pkg info with the package name" do - @provider.should_receive(:shell_out!).with("cave -L warning print-ids -M none -m \"*/#{@new_resource.package_name.split('/').last}\" -f \"%c/%p %v %r\n\"").and_return(@shell_out) - @provider.load_current_resource - end - - it "should return new version if package is installed" do - @stdout.replace(<<-INSTALLED) -group/ntp 0 accounts -group/ntp 0 installed-accounts -net/ntp 4.2.6_p5-r2 arbor -user/ntp 0 accounts -user/ntp 0 installed-accounts -net/ntp 4.2.6_p5-r1 installed -INSTALLED - @provider.should_receive(:shell_out!).and_return(@shell_out) - @provider.load_current_resource - @current_resource.version.should == "4.2.6_p5-r1" - @provider.candidate_version.should eql("4.2.6_p5-r2") - end - - it "should return the current resource" do - @provider.should_receive(:shell_out!).and_return(@shell_out) - @provider.load_current_resource.should eql(@current_resource) - end - end - - context "when installing a package" do - it "should run pkg install with the package name and version" do - @provider.should_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 - @provider.should_receive(:shell_out!).with("cave -L warning resolve -x --preserve-world \"=net/ntp-4.2.6_p5-r2\"", {:timeout=>@new_resource.timeout}) - @new_resource.stub(:options).and_return("--preserve-world") - @provider.install_package("net/ntp", "4.2.6_p5-r2") - end - - it "should not contain invalid characters for the version string" do - @stdout.replace(<<-PKG_STATUS) -sys-process/lsof 4.87 arbor -sys-process/lsof 4.87 x86_64 -PKG_STATUS - @provider.should_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 - - it "should not include the human-readable version in the candidate_version" do - @stdout.replace(<<-PKG_STATUS) -sys-process/lsof 4.87 arbor -sys-process/lsof 4.87 x86_64 -PKG_STATUS - @provider.should_receive(:shell_out!).and_return(@shell_out) - @provider.load_current_resource - @current_resource.version.should be_nil - @provider.candidate_version.should eql("4.87") - end - end - - context "when upgrading a package" do - it "should run pkg install with the package name and version" do - @provider.should_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 - - context "when uninstalling a package" do - it "should run pkg uninstall with the package name and version" do - @provider.should_receive(:shell_out!).with("cave -L warning uninstall -x \"=net/ntp-4.2.6_p5-r2\"") - @provider.remove_package("net/ntp", "4.2.6_p5-r2") - end - - end -end diff --git a/spec/unit/provider/package/portage_spec.rb b/spec/unit/provider/package/portage_spec.rb deleted file mode 100644 index 570f123168..0000000000 --- a/spec/unit/provider/package/portage_spec.rb +++ /dev/null @@ -1,310 +0,0 @@ -# -# Author:: Caleb Tennis (<caleb.tennis@gmail.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' - -describe Chef::Provider::Package::Portage, "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::Package.new("dev-util/git") - @new_resource_without_category = Chef::Resource::Package.new("git") - @current_resource = Chef::Resource::Package.new("dev-util/git") - - @provider = Chef::Provider::Package::Portage.new(@new_resource, @run_context) - Chef::Resource::Package.stub(:new).and_return(@current_resource) - end - - describe "when determining the current state of the package" do - - it "should create a current resource with the name of new_resource" do - ::Dir.stub(:[]).with("/var/db/pkg/dev-util/git-*").and_return(["/var/db/pkg/dev-util/git-1.0.0"]) - Chef::Resource::Package.should_receive(:new).and_return(@current_resource) - @provider.load_current_resource - end - - it "should set the current resource package name to the new resource package name" do - ::Dir.stub(:[]).with("/var/db/pkg/dev-util/git-*").and_return(["/var/db/pkg/dev-util/git-1.0.0"]) - @current_resource.should_receive(:package_name).with(@new_resource.package_name) - @provider.load_current_resource - end - - it "should return a current resource with the correct version if the package is found" do - ::Dir.stub(:[]).with("/var/db/pkg/dev-util/git-*").and_return(["/var/db/pkg/dev-util/git-foobar-0.9", "/var/db/pkg/dev-util/git-1.0.0"]) - @provider.load_current_resource - @provider.current_resource.version.should == "1.0.0" - end - - it "should return a current resource with the correct version if the package is found with revision" do - ::Dir.stub(:[]).with("/var/db/pkg/dev-util/git-*").and_return(["/var/db/pkg/dev-util/git-1.0.0-r1"]) - @provider.load_current_resource - @provider.current_resource.version.should == "1.0.0-r1" - end - - it "should return a current resource with a nil version if the package is not found" do - ::Dir.stub(:[]).with("/var/db/pkg/dev-util/git-*").and_return(["/var/db/pkg/dev-util/notgit-1.0.0"]) - @provider.load_current_resource - @provider.current_resource.version.should be_nil - end - - it "should return a package name match from /var/db/pkg/* if a category isn't specified and a match is found" do - ::Dir.stub(:[]).with("/var/db/pkg/*/git-*").and_return(["/var/db/pkg/dev-util/git-foobar-0.9", "/var/db/pkg/dev-util/git-1.0.0"]) - @provider = Chef::Provider::Package::Portage.new(@new_resource_without_category, @run_context) - @provider.load_current_resource - @provider.current_resource.version.should == "1.0.0" - end - - it "should return a current resource with a nil version if a category isn't specified and a name match from /var/db/pkg/* is not found" do - ::Dir.stub(:[]).with("/var/db/pkg/*/git-*").and_return(["/var/db/pkg/dev-util/notgit-1.0.0"]) - @provider = Chef::Provider::Package::Portage.new(@new_resource_without_category, @run_context) - @provider.load_current_resource - @provider.current_resource.version.should be_nil - end - - it "should throw an exception if a category isn't specified and multiple packages are found" do - ::Dir.stub(:[]).with("/var/db/pkg/*/git-*").and_return(["/var/db/pkg/dev-util/git-1.0.0", "/var/db/pkg/funny-words/git-1.0.0"]) - @provider = Chef::Provider::Package::Portage.new(@new_resource_without_category, @run_context) - lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Package) - end - - it "should return a current resource with a nil version if a category is specified and multiple packages are found" do - ::Dir.stub(:[]).with("/var/db/pkg/dev-util/git-*").and_return(["/var/db/pkg/dev-util/git-1.0.0", "/var/db/pkg/funny-words/git-1.0.0"]) - @provider = Chef::Provider::Package::Portage.new(@new_resource, @run_context) - @provider.load_current_resource - @provider.current_resource.version.should be_nil - end - - it "should return a current resource with a nil version if a category is not specified and multiple packages from the same category are found" do - ::Dir.stub(:[]).with("/var/db/pkg/*/git-*").and_return(["/var/db/pkg/dev-util/git-1.0.0", "/var/db/pkg/dev-util/git-1.0.1"]) - @provider = Chef::Provider::Package::Portage.new(@new_resource_without_category, @run_context) - @provider.load_current_resource - @provider.current_resource.version.should be_nil - end - end - - describe "once the state of the package is known" do - - describe Chef::Provider::Package::Portage, "candidate_version" do - it "should return the candidate_version variable if already set" do - @provider.candidate_version = "1.0.0" - @provider.should_not_receive(:popen4) - @provider.candidate_version - end - - it "should throw an exception if the exitstatus is not 0" do - @status = double("Status", :exitstatus => 1) - @provider.stub(:popen4).and_return(@status) - lambda { @provider.candidate_version }.should raise_error(Chef::Exceptions::Package) - end - - it "should find the candidate_version if a category is specifed and there are no duplicates" do - output = <<EOF -Searching... -[ Results for search key : git ] -[ Applications found : 14 ] - -* app-misc/digitemp [ Masked ] - Latest version available: 3.5.0 - Latest version installed: [ Not Installed ] - Size of files: 261 kB - Homepage: http://www.digitemp.com/ http://www.ibutton.com/ - Description: Temperature logging and reporting using Dallas Semiconductor's iButtons and 1-Wire protocol - License: GPL-2 - -* dev-util/git - Latest version available: 1.6.0.6 - Latest version installed: ignore - Size of files: 2,725 kB - Homepage: http://git.or.cz/ - Description: GIT - the stupid content tracker, the revision control system heavily used by the Linux kernel team - License: GPL-2 - -* dev-util/gitosis [ Masked ] - Latest version available: 0.2_p20080825 - Latest version installed: [ Not Installed ] - Size of files: 31 kB - Homepage: http://eagain.net/gitweb/?p=gitosis.git;a=summary - Description: gitosis -- software for hosting git repositories - License: GPL-2 -EOF - - @status = double("Status", :exitstatus => 0) - @provider.should_receive(:popen4).and_yield(nil, nil, StringIO.new(output), nil).and_return(@status) - @provider.candidate_version.should == "1.6.0.6" - end - - it "should find the candidate_version if a category is not specifed and there are no duplicates" do - output = <<EOF -Searching... -[ Results for search key : git ] -[ Applications found : 14 ] - -* app-misc/digitemp [ Masked ] - Latest version available: 3.5.0 - Latest version installed: [ Not Installed ] - Size of files: 261 kB - Homepage: http://www.digitemp.com/ http://www.ibutton.com/ - Description: Temperature logging and reporting using Dallas Semiconductor's iButtons and 1-Wire protocol - License: GPL-2 - -* dev-util/git - Latest version available: 1.6.0.6 - Latest version installed: ignore - Size of files: 2,725 kB - Homepage: http://git.or.cz/ - Description: GIT - the stupid content tracker, the revision control system heavily used by the Linux kernel team - License: GPL-2 - -* dev-util/gitosis [ Masked ] - Latest version available: 0.2_p20080825 - Latest version installed: [ Not Installed ] - Size of files: 31 kB - Homepage: http://eagain.net/gitweb/?p=gitosis.git;a=summary - Description: gitosis -- software for hosting git repositories - License: GPL-2 -EOF - - @status = double("Status", :exitstatus => 0) - @provider = Chef::Provider::Package::Portage.new(@new_resource_without_category, @run_context) - @provider.should_receive(:popen4).and_yield(nil, nil, StringIO.new(output), nil).and_return(@status) - @provider.candidate_version.should == "1.6.0.6" - end - - it "should throw an exception if a category is not specified and there are duplicates" do - output = <<EOF -Searching... -[ Results for search key : git ] -[ Applications found : 14 ] - -* app-misc/digitemp [ Masked ] - Latest version available: 3.5.0 - Latest version installed: [ Not Installed ] - Size of files: 261 kB - Homepage: http://www.digitemp.com/ http://www.ibutton.com/ - Description: Temperature logging and reporting using Dallas Semiconductor's iButtons and 1-Wire protocol - License: GPL-2 - -* app-misc/git - Latest version available: 4.3.20 - Latest version installed: [ Not Installed ] - Size of files: 416 kB - Homepage: http://www.gnu.org/software/git/ - Description: GNU Interactive Tools - increase speed and efficiency of most daily task - License: GPL-2 - -* dev-util/git - Latest version available: 1.6.0.6 - Latest version installed: ignore - Size of files: 2,725 kB - Homepage: http://git.or.cz/ - Description: GIT - the stupid content tracker, the revision control system heavily used by the Linux kernel team - License: GPL-2 - -* dev-util/gitosis [ Masked ] - Latest version available: 0.2_p20080825 - Latest version installed: [ Not Installed ] - Size of files: 31 kB - Homepage: http://eagain.net/gitweb/?p=gitosis.git;a=summary - Description: gitosis -- software for hosting git repositories - License: GPL-2 -EOF - - @status = double("Status", :exitstatus => 0) - @provider = Chef::Provider::Package::Portage.new(@new_resource_without_category, @run_context) - @provider.should_receive(:popen4).and_yield(nil, nil, StringIO.new(output), nil).and_return(@status) - lambda { @provider.candidate_version }.should raise_error(Chef::Exceptions::Package) - end - - it "should find the candidate_version if a category is specifed and there are category duplicates" do - output = <<EOF -Searching... -[ Results for search key : git ] -[ Applications found : 14 ] - -* app-misc/digitemp [ Masked ] - Latest version available: 3.5.0 - Latest version installed: [ Not Installed ] - Size of files: 261 kB - Homepage: http://www.digitemp.com/ http://www.ibutton.com/ - Description: Temperature logging and reporting using Dallas Semiconductor's iButtons and 1-Wire protocol - License: GPL-2 - -* app-misc/git - Latest version available: 4.3.20 - Latest version installed: [ Not Installed ] - Size of files: 416 kB - Homepage: http://www.gnu.org/software/git/ - Description: GNU Interactive Tools - increase speed and efficiency of most daily task - License: GPL-2 - -* dev-util/git - Latest version available: 1.6.0.6 - Latest version installed: ignore - Size of files: 2,725 kB - Homepage: http://git.or.cz/ - Description: GIT - the stupid content tracker, the revision control system heavily used by the Linux kernel team - License: GPL-2 - -* dev-util/gitosis [ Masked ] - Latest version available: 0.2_p20080825 - Latest version installed: [ Not Installed ] - Size of files: 31 kB - Homepage: http://eagain.net/gitweb/?p=gitosis.git;a=summary - Description: gitosis -- software for hosting git repositories - License: GPL-2 -EOF - - @status = double("Status", :exitstatus => 0) - @provider = Chef::Provider::Package::Portage.new(@new_resource, @run_context) - @provider.should_receive(:popen4).and_yield(nil, nil, StringIO.new(output), nil).and_return(@status) - @provider.candidate_version.should == "1.6.0.6" - end - end - - describe Chef::Provider::Package::Portage, "install_package" do - it "should install a normally versioned package using portage" do - @provider.should_receive(:shell_out!).with("emerge -g --color n --nospinner --quiet =dev-util/git-1.0.0") - @provider.install_package("dev-util/git", "1.0.0") - end - - it "should install a tilde versioned package using portage" do - @provider.should_receive(:shell_out!).with("emerge -g --color n --nospinner --quiet ~dev-util/git-1.0.0") - @provider.install_package("dev-util/git", "~1.0.0") - end - - it "should add options to the emerge command when specified" do - @provider.should_receive(:shell_out!).with("emerge -g --color n --nospinner --quiet --oneshot =dev-util/git-1.0.0") - @new_resource.stub(:options).and_return("--oneshot") - - @provider.install_package("dev-util/git", "1.0.0") - end - end - - describe Chef::Provider::Package::Portage, "remove_package" do - it "should un-emerge the package with no version specified" do - @provider.should_receive(:shell_out!).with("emerge --unmerge --color n --nospinner --quiet dev-util/git") - @provider.remove_package("dev-util/git", nil) - end - - it "should un-emerge the package with a version specified" do - @provider.should_receive(:shell_out!).with("emerge --unmerge --color n --nospinner --quiet =dev-util/git-1.0.0") - @provider.remove_package("dev-util/git", "1.0.0") - end - end - end -end diff --git a/spec/unit/provider/package/rpm_spec.rb b/spec/unit/provider/package/rpm_spec.rb deleted file mode 100644 index 9a96d829b8..0000000000 --- a/spec/unit/provider/package/rpm_spec.rb +++ /dev/null @@ -1,157 +0,0 @@ -# -# Author:: Joshua Timberman (<joshua@opscode.com>) -# Author:: Daniel DeLeo (<dan@opscode.com>) -# Copyright:: Copyright (c) 2008, 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. -# -require 'spec_helper' - -describe Chef::Provider::Package::Rpm 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("ImageMagick-c++") - @new_resource.source "/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm" - - @provider = Chef::Provider::Package::Rpm.new(@new_resource, @run_context) - - @status = double("Status", :exitstatus => 0) - ::File.stub(:exists?).and_return(true) - 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.stub(:popen4).and_return(@status) - @provider.load_current_resource - @provider.current_resource.name.should == "ImageMagick-c++" - end - - it "should set the current reource package name to the new resource package name" do - @provider.stub(:popen4).and_return(@status) - @provider.load_current_resource - @provider.current_resource.package_name.should == 'ImageMagick-c++' - end - - it "should raise an exception if a source is supplied but not found" do - ::File.stub(:exists?).and_return(false) - lambda { @provider.run_action(:any) }.should raise_error(Chef::Exceptions::Package) - end - - it "should get the source package version from rpm if provided" do - @stdout = StringIO.new("ImageMagick-c++ 6.5.4.7-7.el6_5") - @provider.should_receive(:popen4).with("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm").and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @provider.should_receive(:popen4).with("rpm -q --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' ImageMagick-c++").and_return(@status) - @provider.load_current_resource - @provider.current_resource.package_name.should == "ImageMagick-c++" - @provider.new_resource.version.should == "6.5.4.7-7.el6_5" - end - - it "should return the current version installed if found by rpm" do - @stdout = StringIO.new("ImageMagick-c++ 6.5.4.7-7.el6_5") - @provider.should_receive(:popen4).with("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' /tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm").and_return(@status) - @provider.should_receive(:popen4).with("rpm -q --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' ImageMagick-c++").and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @provider.load_current_resource - @provider.current_resource.version.should == "6.5.4.7-7.el6_5" - end - - it "should raise an exception if the source is not set but we are installing" do - new_resource = Chef::Resource::Package.new("ImageMagick-c++") - provider = Chef::Provider::Package::Rpm.new(new_resource, @run_context) - lambda { provider.run_action(:any) }.should raise_error(Chef::Exceptions::Package) - end - - it "should raise an exception if rpm fails to run" do - status = double("Status", :exitstatus => -1) - @provider.stub(:popen4).and_return(status) - lambda { @provider.run_action(:any) }.should raise_error(Chef::Exceptions::Package) - end - - it "should not detect the package name as version when not installed" do - @status = double("Status", :exitstatus => -1) - @stdout = StringIO.new("package openssh-askpass is not installed") - @new_resource = Chef::Resource::Package.new("openssh-askpass") - @new_resource.source 'openssh-askpass' - @provider = Chef::Provider::Package::Rpm.new(@new_resource, @run_context) - @provider.should_receive(:popen4).with("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' openssh-askpass").and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @provider.should_receive(:popen4).with("rpm -q --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' openssh-askpass").and_return(@status) - @provider.load_current_resource - @provider.current_resource.version.should be_nil - end - end - - describe "after the current resource is loaded" do - before do - @current_resource = Chef::Resource::Package.new("ImageMagick-c++") - @provider.current_resource = @current_resource - end - - describe "when installing or upgrading" do - it "should run rpm -i with the package source to install" do - @provider.should_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 - - it "should run rpm -U with the package source to upgrade" do - @current_resource.version("21.4-19.el5") - @provider.should_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 - - it "should install package if missing and set to upgrade" do - @current_resource.version("ImageMagick-c++") - @provider.should_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 - - it "should install from a path when the package is a path and the source is nil" do - @new_resource = Chef::Resource::Package.new("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm") - @provider = Chef::Provider::Package::Rpm.new(@new_resource, @run_context) - @new_resource.source.should == "/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm" - @current_resource = Chef::Resource::Package.new("ImageMagick-c++") - @provider.current_resource = @current_resource - @provider.should_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") - end - - it "should uprgrade from a path when the package is a path and the source is nil" do - @new_resource = Chef::Resource::Package.new("/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm") - @provider = Chef::Provider::Package::Rpm.new(@new_resource, @run_context) - @new_resource.source.should == "/tmp/ImageMagick-c++-6.5.4.7-7.el6_5.x86_64.rpm" - @current_resource = Chef::Resource::Package.new("ImageMagick-c++") - @current_resource.version("21.4-19.el5") - @provider.current_resource = @current_resource - @provider.should_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") - end - - it "installs with custom options specified in the resource" do - @provider.candidate_version = '11' - @new_resource.options("--dbpath /var/lib/rpm") - @provider.should_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 - - describe "when removing the package" do - it "should run rpm -e to remove the package" do - @provider.should_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 - end - end -end diff --git a/spec/unit/provider/package/rubygems_spec.rb b/spec/unit/provider/package/rubygems_spec.rb deleted file mode 100644 index d3cb9cf7fa..0000000000 --- a/spec/unit/provider/package/rubygems_spec.rb +++ /dev/null @@ -1,639 +0,0 @@ -# -# Author:: David Balatero (dbalatero@gmail.com) -# -# Copyright:: Copyright (c) 2009 David Balatero -# 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 'pp' - -module GemspecBackcompatCreator - def gemspec(name, version) - if Gem::Specification.new.method(:initialize).arity == 0 - Gem::Specification.new { |s| s.name = name; s.version = version } - else - Gem::Specification.new(name, version) - end - end -end - -require 'spec_helper' -require 'ostruct' - -describe Chef::Provider::Package::Rubygems::CurrentGemEnvironment do - include GemspecBackcompatCreator - - before do - @gem_env = Chef::Provider::Package::Rubygems::CurrentGemEnvironment.new - end - - it "determines the gem paths from the in memory rubygems" do - @gem_env.gem_paths.should == Gem.path - 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') - Gem::Specification.should_receive(:find_all_by_name).with('rspec-core', Gem::Dependency.new('rspec-core').requirement).and_return(gems) - else - Gem.source_index.should_receive(:search).with(Gem::Dependency.new('rspec-core', nil)).and_return(gems) - end - @gem_env.installed_versions(Gem::Dependency.new('rspec-core', nil)).should == 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] } - actual.should include(expected) - end - - it "yields to a block with an alternate source list set" do - sources_in_block = nil - normal_sources = Gem.sources - begin - @gem_env.with_gem_sources("http://gems.example.org") do - sources_in_block = Gem.sources - raise RuntimeError, "sources should be reset even in case of an error" - end - rescue RuntimeError - end - sources_in_block.should == %w{http://gems.example.org} - Gem.sources.should == normal_sources - end - - it "it doesnt alter the gem sources if none are set" do - sources_in_block = nil - normal_sources = Gem.sources - begin - @gem_env.with_gem_sources(nil) do - sources_in_block = Gem.sources - raise RuntimeError, "sources should be reset even in case of an error" - end - rescue RuntimeError - end - sources_in_block.should == normal_sources - Gem.sources.should == normal_sources - end - - it "finds a matching gem candidate version" do - dep = Gem::Dependency.new('rspec', '>= 0') - dep_installer = Gem::DependencyInstaller.new - @gem_env.stub(:dependency_installer).and_return(dep_installer) - latest = [[gemspec("rspec", Gem::Version.new("1.3.0")), "http://rubygems.org/"]] - dep_installer.should_receive(:find_gems_with_sources).with(dep).and_return(latest) - @gem_env.candidate_version_from_remote(Gem::Dependency.new('rspec', '>= 0')).should == 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_installer = Gem::DependencyInstaller.new - @gem_env.stub(: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") - available_set = double("Gem::AvailableSet test double") - available_set.should_receive(:pick_best!) - available_set.should_receive(:set).and_return([best_gem]) - dep_installer.should_receive(:find_gems_with_sources).with(dep).and_return(available_set) - @gem_env.candidate_version_from_remote(Gem::Dependency.new('rspec', '>= 0')).should == 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 - Gem::Package.stub(: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") - Gem::Package.should_receive(:new).with("/path/to/package.gem").and_return(package) - @gem_env.spec_from_file("/path/to/package.gem").should == "a gemspec from package" - end - - end - - it "gives the candidate version as nil if none is found" do - dep = Gem::Dependency.new('rspec', '>= 0') - latest = [] - dep_installer = Gem::DependencyInstaller.new - @gem_env.stub(:dependency_installer).and_return(dep_installer) - dep_installer.should_receive(:find_gems_with_sources).with(dep).and_return(latest) - @gem_env.candidate_version_from_remote(Gem::Dependency.new('rspec', '>= 0')).should 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' - @gem_env.candidate_version_from_file(Gem::Dependency.new('chef-integration-test', '>= 0'), location).should == Gem::Version.new('0.1.0') - @gem_env.candidate_version_from_file(Gem::Dependency.new('chef-integration-test', '>= 0.2.0'), location).should be_nil - end - - it "finds a matching gem from a specific gemserver when explicit sources are given" do - dep = Gem::Dependency.new('rspec', '>= 0') - latest = [[gemspec("rspec", Gem::Version.new("1.3.0")), "http://rubygems.org/"]] - - @gem_env.should_receive(:with_gem_sources).with('http://gems.example.com').and_yield - dep_installer = Gem::DependencyInstaller.new - @gem_env.stub(:dependency_installer).and_return(dep_installer) - dep_installer.should_receive(:find_gems_with_sources).with(dep).and_return(latest) - @gem_env.candidate_version_from_remote(Gem::Dependency.new('rspec', '>=0'), 'http://gems.example.com').should == 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 - @gem_env.should_receive(:dependency_installer).with(:install_dir => '/foo/bar').and_return(dep_installer) - @gem_env.should_receive(:with_gem_sources).with('http://gems.example.com').and_yield - dep_installer.should_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 - Gem::Uninstaller.should_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.should_receive(:uninstall) - @gem_env.should_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.should_receive(:uninstall) - @gem_env.should_receive(:uninstaller).with('rspec', :version => '1.2.3').and_return(uninstaller) - @gem_env.uninstall('rspec', '1.2.3') - end - -end - -describe Chef::Provider::Package::Rubygems::AlternateGemEnvironment do - include GemspecBackcompatCreator - - 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') - 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) - shell_out_result = OpenStruct.new(:stdout => gem_env_output) - @gem_env.should_receive(:shell_out!).with('/usr/weird/bin/gem env gempath').and_return(shell_out_result) - @gem_env.gem_paths.should == ['/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) - shell_out_result = OpenStruct.new(:stdout => gem_env_output) - @gem_env.should_receive(:shell_out!).with('/usr/weird/bin/gem env gempath').and_return(shell_out_result) - expected = ['/path/to/gems', '/another/path/to/gems'] - @gem_env.gem_paths.should == ['/path/to/gems', '/another/path/to/gems'] - Chef::Provider::Package::Rubygems::AlternateGemEnvironment.gempath_cache['/usr/weird/bin/gem'].should == 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) - @gem_env.should_not_receive(:shell_out!) - expected = ['/path/to/gems', '/another/path/to/gems'] - Chef::Provider::Package::Rubygems::AlternateGemEnvironment.gempath_cache['/usr/weird/bin/gem']= expected - @gem_env.gem_paths.should == ['/path/to/gems', '/another/path/to/gems'] - end - - it "builds the gems source index from the gem paths" do - @gem_env.stub(: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 - Gem::Specification.dirs.should == [ '/path/to/gems/specifications', '/another/path/to/gems/specifications' ] - else - Gem::SourceIndex.should_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') - @gem_env.stub(:gem_specification).and_return(Gem::Specification) - @gem_env.gem_specification.should_receive(:find_all_by_name).with(rspec_dep.name, rspec_dep.requirement).and_return(gems) - else - @gem_env.stub(:gem_source_index).and_return(Gem.source_index) - @gem_env.gem_source_index.should_receive(:search).with(rspec_dep).and_return(gems) - end - @gem_env.installed_versions(Gem::Dependency.new('rspec', nil)).should == gems - end - - it "determines the installed versions of gems from the source index (part2: the unmockening)" do - $stdout.stub(: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? - 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] } - actual.should include(expected) - end - - it "detects when the target gem environment is the jruby platform" do - gem_env_out=<<-JRUBY_GEM_ENV -RubyGems Environment: - - RUBYGEMS VERSION: 1.3.6 - - RUBY VERSION: 1.8.7 (2010-05-12 patchlevel 249) [java] - - INSTALLATION DIRECTORY: /Users/you/.rvm/gems/jruby-1.5.0 - - RUBY EXECUTABLE: /Users/you/.rvm/rubies/jruby-1.5.0/bin/jruby - - EXECUTABLE DIRECTORY: /Users/you/.rvm/gems/jruby-1.5.0/bin - - RUBYGEMS PLATFORMS: - - ruby - - universal-java-1.6 - - GEM PATHS: - - /Users/you/.rvm/gems/jruby-1.5.0 - - /Users/you/.rvm/gems/jruby-1.5.0@global - - GEM CONFIGURATION: - - :update_sources => true - - :verbose => true - - :benchmark => false - - :backtrace => false - - :bulk_threshold => 1000 - - "install" => "--env-shebang" - - "update" => "--env-shebang" - - "gem" => "--no-rdoc --no-ri" - - :sources => ["http://rubygems.org/", "http://gems.github.com/"] - - REMOTE SOURCES: - - http://rubygems.org/ - - http://gems.github.com/ -JRUBY_GEM_ENV - @gem_env.should_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')] - @gem_env.gem_platforms.should == expected - # it should also cache the result - Chef::Provider::Package::Rubygems::AlternateGemEnvironment.platform_cache['/usr/weird/bin/gem'].should == expected - end - - it "uses the cached result for gem platforms if available" do - @gem_env.should_not_receive(:shell_out!) - expected = ['ruby', Gem::Platform.new('universal-java-1.6')] - Chef::Provider::Package::Rubygems::AlternateGemEnvironment.platform_cache['/usr/weird/bin/gem']= expected - @gem_env.gem_platforms.should == expected - end - - it "uses the current gem platforms when the target env is not jruby" do - 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] - - INSTALLATION DIRECTORY: /Users/ddeleo/.rvm/gems/rbx-1.0.0-20100514 - - RUBYGEMS PREFIX: /Users/ddeleo/.rvm/rubies/rbx-1.0.0-20100514 - - RUBY EXECUTABLE: /Users/ddeleo/.rvm/rubies/rbx-1.0.0-20100514/bin/rbx - - EXECUTABLE DIRECTORY: /Users/ddeleo/.rvm/gems/rbx-1.0.0-20100514/bin - - RUBYGEMS PLATFORMS: - - ruby - - x86_64-darwin-10 - - x86_64-rubinius-1.0 - - GEM PATHS: - - /Users/ddeleo/.rvm/gems/rbx-1.0.0-20100514 - - /Users/ddeleo/.rvm/gems/rbx-1.0.0-20100514@global - - GEM CONFIGURATION: - - :update_sources => true - - :verbose => true - - :benchmark => false - - :backtrace => false - - :bulk_threshold => 1000 - - :sources => ["http://rubygems.org/", "http://gems.github.com/"] - - "gem" => "--no-rdoc --no-ri" - - REMOTE SOURCES: - - http://rubygems.org/ - - http://gems.github.com/ -RBX_GEM_ENV - @gem_env.should_receive(:shell_out!).with('/usr/weird/bin/gem env').and_return(double('rbx_gem_env', :stdout => gem_env_out)) - @gem_env.gem_platforms.should == Gem.platforms - Chef::Provider::Package::Rubygems::AlternateGemEnvironment.platform_cache['/usr/weird/bin/gem'].should == 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 - platforms_in_block = Gem.platforms - raise "gem platforms should get set to the correct value even when an error occurs" - end - rescue RuntimeError - end - platforms_in_block.should == ['ruby', Gem::Platform.new('sparc64-java-1.7')] - Gem.platforms.should == original_platforms - end - -end - -describe Chef::Provider::Package::Rubygems do - before(:each) do - @node = Chef::Node.new - @new_resource = Chef::Resource::GemPackage.new("rspec-core") - @spec_version = @new_resource.version RSpec::Core::Version::STRING - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - - # We choose detect omnibus via RbConfig::CONFIG['bindir'] in Chef::Provider::Package::Rubygems.new - RbConfig::CONFIG.stub(:[]).with('bindir').and_return("/usr/bin/ruby") - @provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context) - end - - it "triggers a gem configuration load so a later one will not stomp its config values" do - # ugly, is there a better way? - Gem.instance_variable_get(:@configuration).should_not be_nil - end - - it "uses the CurrentGemEnvironment implementation when no gem_binary_path is provided" do - @provider.gem_env.should 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) - provider.gem_env.gem_binary_location.should == '/usr/weird/bin/gem' - end - - it "searches for a gem binary when running on Omnibus on Unix" do - platform_mock :unix do - RbConfig::CONFIG.stub(:[]).with('bindir').and_return("/opt/chef/embedded/bin") - ENV.stub(:[]).with('PATH').and_return("/usr/bin:/usr/sbin:/opt/chef/embedded/bin") - File.stub(:exists?).with('/usr/bin/gem').and_return(false) - File.stub(:exists?).with('/usr/sbin/gem').and_return(true) - File.stub(:exists?).with('/opt/chef/embedded/bin/gem').and_return(true) # should not get here - provider = Chef::Provider::Package::Rubygems.new(@new_resource, @run_context) - provider.gem_env.gem_binary_location.should == '/usr/sbin/gem' - end - end - - it "searches for a gem binary when running on Omnibus on Windows" do - platform_mock :windows do - RbConfig::CONFIG.stub(:[]).with('bindir').and_return("d:/opscode/chef/embedded/bin") - ENV.stub(:[]).with('PATH').and_return('C:\windows\system32;C:\windows;C:\Ruby186\bin;d:\opscode\chef\embedded\bin') - File.stub(:exists?).with('C:\\windows\\system32\\gem').and_return(false) - File.stub(:exists?).with('C:\\windows\\gem').and_return(false) - File.stub(:exists?).with('C:\\Ruby186\\bin\\gem').and_return(true) - File.stub(:exists?).with('d:\\opscode\\chef\\bin\\gem').and_return(false) # should not get here - File.stub(: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) - provider.gem_env.gem_binary_location.should == 'C:\Ruby186\bin\gem' - 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) - lambda {Chef::Provider::Package::Rubygems.new(@new_resource, @run_context)}.should raise_error(ArgumentError) - end - - it "converts the new resource into a gem dependency" do - @provider.gem_dependency.should == Gem::Dependency.new('rspec-core', @spec_version) - @new_resource.version('~> 1.2.0') - @provider.gem_dependency.should == Gem::Dependency.new('rspec-core', '~> 1.2.0') - end - - describe "when determining the currently installed version" do - - it "sets the current version to the version specified by the new resource if that version is installed" do - @provider.load_current_resource - @provider.current_resource.version.should == @spec_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 - @provider.current_resource.version.should == @spec_version - 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 - @provider.current_resource.version.should be_nil - end - - end - - describe "when determining the candidate version to install" do - - it "does not query for available versions when the current version is the target version" do - @provider.current_resource = @new_resource.dup - @provider.candidate_version.should be_nil - end - - it "determines the candidate version by querying the remote gem servers" do - @new_resource.source('http://mygems.example.com') - version = Gem::Version.new(@spec_version) - @provider.gem_env.should_receive(:candidate_version_from_remote). - with(Gem::Dependency.new('rspec-core', @spec_version), "http://mygems.example.com"). - and_return(version) - @provider.candidate_version.should == @spec_version - end - - it "parses the gem's specification if the requested source is a file" do - @new_resource.package_name('chef-integration-test') - @new_resource.version('>= 0') - @new_resource.source(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem') - @provider.candidate_version.should == '0.1.0' - end - - end - - describe "when installing a gem" do - before do - @current_resource = Chef::Resource::GemPackage.new('rspec-core') - @provider.current_resource = @current_resource - @gem_dep = Gem::Dependency.new('rspec-core', @spec_version) - @provider.stub(:load_current_resource) - end - - describe "in the current gem environment" do - it "installs the gem via the gems api when no explicit options are used" do - @provider.gem_env.should_receive(:install).with(@gem_dep, :sources => nil) - @provider.action_install.should be_true - 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'] - @provider.gem_env.should_receive(:install).with(@gem_dep, :sources => sources) - @provider.action_install.should be_true - 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') - @provider.gem_env.should_receive(:install).with(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem') - @provider.action_install.should be_true - 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 - @new_resource.source.should == CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem' - @provider.gem_env.should_receive(:install).with(CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem') - @provider.action_install.should be_true - 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 - ::File.stub(:exists?).and_return(true) - @new_resource.package_name('rspec-core') - @provider.gem_env.should_receive(:install).with(@gem_dep, :sources => nil) - @provider.action_install.should be_true - 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" - @provider.should_receive(:shell_out!).with(expected, :env => nil) - @provider.action_install.should be_true - 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') - @provider.gem_env.should_receive(:install).with(@gem_dep, :sources => nil, :install_dir => '/alt/install/location') - @provider.action_install.should be_true - end - - describe "at a specific version" do - before do - @gem_dep = Gem::Dependency.new('rspec-core', @spec_version) - end - - it "installs the gem via the gems api" do - @provider.gem_env.should_receive(:install).with(@gem_dep, :sources => nil) - @provider.action_install.should be_true - end - end - describe "at version specified with comparison operator" do - it "skips install if current version satisifies requested version" do - @current_resource.stub(:version).and_return("2.3.3") - @new_resource.stub(:version).and_return(">=2.3.0") - - @provider.gem_env.should_not_receive(:install) - @provider.action_install - end - - it "allows user to specify gem version with fuzzy operator" do - @current_resource.stub(:version).and_return("2.3.3") - @new_resource.stub(:version).and_return("~>2.3.0") - - @provider.gem_env.should_not_receive(:install) - @provider.action_install - end - end - end - - describe "in an alternate gem environment" do - it "installs the gem by shelling out to gem install" do - @new_resource.gem_binary('/usr/weird/bin/gem') - @provider.should_receive(:shell_out!).with("/usr/weird/bin/gem install rspec-core -q --no-rdoc --no-ri -v \"#{@spec_version}\"", :env=>nil) - @provider.action_install.should be_true - 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') - @provider.should_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.action_install.should be_true - 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') - @new_resource.source.should == CHEF_SPEC_DATA + '/gems/chef-integration-test-0.1.0.gem' - @provider.should_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.action_install.should be_true - 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 - 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: - @provider.new_resource.version.should be_nil - @provider.current_resource.version.should_not be_nil - # the behavior we're testing: - @provider.gem_env.should_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: - @provider.new_resource.version.should be_nil - @provider.current_resource.version.should_not be_nil - # the behavior we're testing: - @new_resource.options(:install_dir => '/alt/install/location') - @provider.gem_env.should_receive(:uninstall).with('rspec', nil, :install_dir => '/alt/install/location') - @provider.action_remove - end - - it "uninstalls via the gem command when options are given as a String" do - @new_resource.options('-i /alt/install/location') - @provider.should_receive(:shell_out!).with("gem uninstall rspec -q -x -I -a -i /alt/install/location", :env=>nil) - @provider.action_remove - end - - it "uninstalls a specific version of a gem when a version is provided" do - @new_resource.version('1.2.3') - @provider.gem_env.should_receive(:uninstall).with('rspec', '1.2.3') - @provider.action_remove - end - end - - describe "in an alternate gem environment" do - it "uninstalls via the gem command" do - @new_resource.gem_binary('/usr/weird/bin/gem') - @provider.should_receive(:shell_out!).with("/usr/weird/bin/gem uninstall rspec -q -x -I -a", :env=>nil) - @provider.action_remove - end - end - end -end - diff --git a/spec/unit/provider/package/smartos_spec.rb b/spec/unit/provider/package/smartos_spec.rb deleted file mode 100644 index 1c690acbf5..0000000000 --- a/spec/unit/provider/package/smartos_spec.rb +++ /dev/null @@ -1,102 +0,0 @@ -# -# Author:: Trevor O (trevoro@joyent.com) -# Author:: Yukihiko Sawanobori (sawanoboriyu@higanworks.com) -# Copyright:: Copyright (c) 2012 Opscode -# 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 File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "spec_helper")) -require 'ostruct' - -describe Chef::Provider::Package::SmartOS, "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::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) - Chef::Resource::Package.stub(: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 - - it "should create a current resource with the name of the new_resource" do - @provider.should_receive(:shell_out!).and_return(@shell_out) - Chef::Resource::Package.should_receive(:new).and_return(@current_resource) - @provider.load_current_resource - end - - it "should set the current resource package name" do - @provider.should_receive(:shell_out!).and_return(@shell_out) - @current_resource.should_receive(:package_name).with(@new_resource.package_name) - @provider.load_current_resource - end - - it "should set the installed version if it is installed" do - @provider.should_receive(:shell_out!).and_return(@shell_out) - @provider.load_current_resource - @current_resource.version.should == "2.1.5nb2" - end - - it "should set the installed version to nil if it's not installed" do - out = OpenStruct.new(:stdout => nil) - @provider.should_receive(:shell_out!).and_return(out) - @provider.load_current_resource - @current_resource.version.should == nil - end - - - end - - describe "candidate_version" do - it "should return the candidate_version variable if already setup" do - @provider.candidate_version = "2.1.1" - @provider.should_not_receive(:shell_out!) - @provider.candidate_version - end - - it "should lookup the candidate_version if the variable is not already set" do - search = double() - search.should_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) - @provider.should_receive(:shell_out!).with('/opt/local/bin/pkgin se varnish', :env => nil, :returns => [0,1]).and_return(@shell_out) - @provider.candidate_version.should == "2.3.4" - end - end - - describe "when manipulating a resource" do - - it "run pkgin and install the package" do - out = OpenStruct.new(:stdout => nil) - @provider.should_receive(:shell_out!).with("/opt/local/sbin/pkg_info -E \"varnish*\"", {:env => nil, :returns=>[0,1]}).and_return(@shell_out) - @provider.should_receive(:shell_out!).with("/opt/local/bin/pkgin -y install varnish-2.1.5nb2", {:env=>nil}).and_return(out) - @provider.load_current_resource - @provider.install_package("varnish", "2.1.5nb2") - end - - end - -end diff --git a/spec/unit/provider/package/solaris_spec.rb b/spec/unit/provider/package/solaris_spec.rb deleted file mode 100644 index d83ccbdf06..0000000000 --- a/spec/unit/provider/package/solaris_spec.rb +++ /dev/null @@ -1,170 +0,0 @@ -# -# Author:: Toomas Pelberg (<toomasp@gmx.net>) -# 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. -# -require 'spec_helper' - -describe Chef::Provider::Package::Solaris 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("SUNWbash") - @new_resource.source("/tmp/bash.pkg") - - @provider = Chef::Provider::Package::Solaris.new(@new_resource, @run_context) - ::File.stub(:exists?).and_return(true) - end - - describe "assessing the current package status" do - before do - @pkginfo =<<-PKGINFO -PKGINST: SUNWbash -NAME: GNU Bourne-Again shell (bash) -CATEGORY: system -ARCH: sparc -VERSION: 11.10.0,REV=2005.01.08.05.16 -BASEDIR: / -VENDOR: Sun Microsystems, Inc. -DESC: GNU Bourne-Again shell (bash) version 3.0 -PSTAMP: sfw10-patch20070430084444 -INSTDATE: Nov 04 2009 01:02 -HOTLINE: Please contact your local service provider -PKGINFO - - @status = double("Status", :exitstatus => 0) - end - - it "should create a current resource with the name of new_resource" do - @provider.stub(:popen4).and_return(@status) - @provider.load_current_resource - @provider.current_resource.name.should == "SUNWbash" - end - - it "should set the current reource package name to the new resource package name" do - @provider.stub(:popen4).and_return(@status) - @provider.load_current_resource - @provider.current_resource.package_name.should == "SUNWbash" - end - - it "should raise an exception if a source is supplied but not found" do - @provider.stub(:popen4).and_return(@status) - ::File.stub(:exists?).and_return(false) - @provider.define_resource_requirements - @provider.load_current_resource - lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Package) - end - - it "should get the source package version from pkginfo if provided" do - @stdout = StringIO.new(@pkginfo) - @stdin, @stderr = StringIO.new, StringIO.new - @provider.should_receive(:popen4).with("pkginfo -l -d /tmp/bash.pkg SUNWbash").and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @provider.should_receive(:popen4).with("pkginfo -l SUNWbash").and_return(@status) - @provider.load_current_resource - - @provider.current_resource.package_name.should == "SUNWbash" - @new_resource.version.should == "11.10.0,REV=2005.01.08.05.16" - end - - it "should return the current version installed if found by pkginfo" do - @stdout = StringIO.new(@pkginfo) - @stdin, @stderr = StringIO.new, StringIO.new - @provider.should_receive(:popen4).with("pkginfo -l -d /tmp/bash.pkg SUNWbash").and_return(@status) - @provider.should_receive(:popen4).with("pkginfo -l SUNWbash").and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @provider.load_current_resource - @provider.current_resource.version.should == "11.10.0,REV=2005.01.08.05.16" - end - - it "should raise an exception if the source is not set but we are installing" do - @new_resource = Chef::Resource::Package.new("SUNWbash") - @provider = Chef::Provider::Package::Solaris.new(@new_resource, @run_context) - @provider.stub(:popen4).and_return(@status) - lambda { @provider.run_action(:install) }.should raise_error(Chef::Exceptions::Package) - end - - it "should raise an exception if pkginfo fails to run" do - @status = double("Status", :exitstatus => -1) - @provider.stub(:popen4).and_return(@status) - lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Package) - end - - it "should return a current resource with a nil version if the package is not found" do - @stdout = StringIO.new - @provider.should_receive(:popen4).with("pkginfo -l -d /tmp/bash.pkg SUNWbash").and_return(@status) - @provider.should_receive(:popen4).with("pkginfo -l SUNWbash").and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @provider.load_current_resource - @provider.current_resource.version.should be_nil - end - end - - describe "candidate_version" do - it "should return the candidate_version variable if already setup" do - @provider.candidate_version = "11.10.0,REV=2005.01.08.05.16" - @provider.should_not_receive(:popen4) - @provider.candidate_version - end - - it "should lookup the candidate_version if the variable is not already set" do - @status = double("Status", :exitstatus => 0) - @provider.stub(:popen4).and_return(@status) - @provider.should_receive(:popen4) - @provider.candidate_version - end - - it "should throw and exception if the exitstatus is not 0" do - @status = double("Status", :exitstatus => 1) - @provider.stub(:popen4).and_return(@status) - lambda { @provider.candidate_version }.should raise_error(Chef::Exceptions::Package) - end - - end - - describe "install and upgrade" do - it "should run pkgadd -n -d with the package source to install" do - @provider.should_receive(:shell_out!).with("pkgadd -n -d /tmp/bash.pkg all") - @provider.install_package("SUNWbash", "11.10.0,REV=2005.01.08.05.16") - end - - it "should run pkgadd -n -d when the package is a path to install" do - @new_resource = Chef::Resource::Package.new("/tmp/bash.pkg") - @provider = Chef::Provider::Package::Solaris.new(@new_resource, @run_context) - @new_resource.source.should == "/tmp/bash.pkg" - @provider.should_receive(:shell_out!).with("pkgadd -n -d /tmp/bash.pkg all") - @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 - @new_resource.stub(:options).and_return("-a /tmp/myadmin") - @provider.should_receive(:shell_out!).with("pkgadd -n -a /tmp/myadmin -d /tmp/bash.pkg all") - @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 - @provider.should_receive(:shell_out!).with("pkgrm -n SUNWbash") - @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 - @new_resource.stub(:options).and_return("-a /tmp/myadmin") - @provider.should_receive(:shell_out!).with("pkgrm -n -a /tmp/myadmin SUNWbash") - @provider.remove_package("SUNWbash", "11.10.0,REV=2005.01.08.05.16") - end - - end -end diff --git a/spec/unit/provider/package/windows/msi_spec.rb b/spec/unit/provider/package/windows/msi_spec.rb deleted file mode 100644 index c8a63ad066..0000000000 --- a/spec/unit/provider/package/windows/msi_spec.rb +++ /dev/null @@ -1,60 +0,0 @@ -# -# Author:: Bryan McLellan <btm@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 'spec_helper' - -describe Chef::Provider::Package::Windows::MSI, :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") } - let(:provider) { Chef::Provider::Package::Windows::MSI.new(new_resource) } - - 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 - provider.stub(:get_product_property).and_return("{23170F69-40C1-2702-0920-000001000000}") - provider.stub(: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 - end - - describe "package_version" do - it "returns the version of a package" do - provider.stub(:get_product_property).with(/calculator.msi$/, "ProductVersion").and_return(42) - expect(provider.package_version).to eql(42) - end - end - - describe "install_package" do - # calls shell_out! - end - - describe "remove_package" do - # calls shell_out! - end -end diff --git a/spec/unit/provider/package/windows_spec.rb b/spec/unit/provider/package/windows_spec.rb deleted file mode 100644 index b4ababb243..0000000000 --- a/spec/unit/provider/package/windows_spec.rb +++ /dev/null @@ -1,86 +0,0 @@ -# -# Author:: Bryan McLellan <btm@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 'spec_helper' - -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") } - let(:provider) { Chef::Provider::Package::Windows.new(new_resource, run_context) } - - describe "load_current_resource" do - before(:each) do - Chef::Util::PathHelper.stub(:validate_path) - provider.stub(:package_provider).and_return(double('package_provider', - :installed_version => "1.0", :package_version => "2.0")) - 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 "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 - - it "checks that the source path is valid" do - expect(Chef::Util::PathHelper).to receive(:validate_path) - provider.load_current_resource - end - end - - describe "package_provider" do - it "sets the package provider to MSI if the the installer type is :msi" do - provider.stub(:installer_type).and_return(:msi) - expect(provider.package_provider).to be_a(Chef::Provider::Package::Windows::MSI) - end - - it "raises an error if the installer_type is unknown" do - provider.stub(:installer_type).and_return(:apt_for_windows) - expect { provider.package_provider }.to raise_error - end - end - - describe "installer_type" do - it "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) - 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) - end - end -end diff --git a/spec/unit/provider/package/yum_spec.rb b/spec/unit/provider/package/yum_spec.rb deleted file mode 100644 index 9b3b6b60e0..0000000000 --- a/spec/unit/provider/package/yum_spec.rb +++ /dev/null @@ -1,1863 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -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') - @status = double("Status", :exitstatus => 0) - @yum_cache = double( - '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_2.3", - :package_available? => true, - :version_available? => true, - :allow_multi_install => [ "kernel" ], - :package_repository => "base", - :disable_extra_repo_control => true - ) - Chef::Provider::Package::Yum::YumCache.stub(:instance).and_return(@yum_cache) - @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) - @pid = double("PID") - end - - 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 - @provider.current_resource.name.should == "cups" - end - - it "should set the current resources package name to the new resources package name" do - @provider.load_current_resource - @provider.current_resource.package_name.should == "cups" - end - - it "should set the installed version to nil on the current resource if no installed package" do - @yum_cache.stub(:installed_version).and_return(nil) - @provider.load_current_resource - @provider.current_resource.version.should be_nil - end - - it "should set the installed version if yum has one" do - @provider.load_current_resource - @provider.current_resource.version.should == "1.2.4-11.18.el5" - end - - it "should set the candidate version if yum info has one" do - @provider.load_current_resource - @provider.candidate_version.should eql("1.2.4-11.18.el5_2.3") - end - - it "should return the current resouce" do - @provider.load_current_resource.should eql(@provider.current_resource) - 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') - @yum_cache = double( - 'Chef::Provider::Yum::YumCache' - ) - @yum_cache.stub(:installed_version) do |package_name, arch| - # nothing installed for package_name/new_package_name - nil - end - @yum_cache.stub(:candidate_version) do |package_name, arch| - if package_name == "testing.noarch" || package_name == "testing.more.noarch" - nil - # candidate for new_package_name - elsif package_name == "testing" || package_name == "testing.more" - "1.1" - end - end - @yum_cache.stub(:package_available?).and_return(true) - @yum_cache.stub(:disable_extra_repo_control).and_return(true) - Chef::Provider::Package::Yum::YumCache.stub(:instance).and_return(@yum_cache) - @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) - @provider.load_current_resource - @provider.new_resource.package_name.should == "testing" - @provider.new_resource.arch.should == "noarch" - @provider.arch.should == "noarch" - - @new_resource = Chef::Resource::YumPackage.new('testing.more.noarch') - @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) - @provider.load_current_resource - @provider.new_resource.package_name.should == "testing.more" - @provider.new_resource.arch.should == "noarch" - @provider.arch.should == "noarch" - end - - it "should not set the arch when an existing package_name is found" do - @new_resource = Chef::Resource::YumPackage.new('testing.beta3') - @yum_cache = double( - 'Chef::Provider::Yum::YumCache' - ) - @yum_cache.stub(:installed_version) do |package_name, arch| - # installed for package_name - if package_name == "testing.beta3" || package_name == "testing.beta3.more" - "1.1" - elsif package_name == "testing" || package_name == "testing.beta3" - nil - end - end - @yum_cache.stub(:candidate_version) do |package_name, arch| - # no candidate for package_name/new_package_name - nil - end - @yum_cache.stub(:package_available?).and_return(true) - @yum_cache.stub(:disable_extra_repo_control).and_return(true) - Chef::Provider::Package::Yum::YumCache.stub(:instance).and_return(@yum_cache) - @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) - # annoying side effect of the fun stub'ing above - @provider.load_current_resource - @provider.new_resource.package_name.should == "testing.beta3" - @provider.new_resource.arch.should == nil - @provider.arch.should == nil - - @new_resource = Chef::Resource::YumPackage.new('testing.beta3.more') - @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) - @provider.load_current_resource - @provider.new_resource.package_name.should == "testing.beta3.more" - @provider.new_resource.arch.should == nil - @provider.arch.should == nil - 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') - @yum_cache = double( - 'Chef::Provider::Yum::YumCache' - ) - @yum_cache.stub(:installed_version) do |package_name, arch| - # nothing installed for package_name/new_package_name - nil - end - @yum_cache.stub(:candidate_version) do |package_name, arch| - # no candidate for package_name/new_package_name - nil - end - @yum_cache.stub(:package_available?).and_return(true) - @yum_cache.stub(:disable_extra_repo_control).and_return(true) - Chef::Provider::Package::Yum::YumCache.stub(:instance).and_return(@yum_cache) - @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) - @provider.load_current_resource - @provider.new_resource.package_name.should == "testing.beta3" - @provider.new_resource.arch.should == nil - @provider.arch.should == nil - - @new_resource = Chef::Resource::YumPackage.new('testing.beta3.more') - @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) - @provider.load_current_resource - @provider.new_resource.package_name.should == "testing.beta3.more" - @provider.new_resource.arch.should == nil - @provider.arch.should == nil - end - - it "should ensure it doesn't clobber an existing arch if passed" do - @new_resource = Chef::Resource::YumPackage.new('testing.i386') - @new_resource.arch("x86_64") - @yum_cache = double( - 'Chef::Provider::Yum::YumCache' - ) - @yum_cache.stub(:installed_version) do |package_name, arch| - # nothing installed for package_name/new_package_name - nil - end - @yum_cache.stub(:candidate_version) do |package_name, arch| - if package_name == "testing.noarch" - nil - # candidate for new_package_name - elsif package_name == "testing" - "1.1" - end - end.and_return("something") - @yum_cache.stub(:package_available?).and_return(true) - @yum_cache.stub(:disable_extra_repo_control).and_return(true) - Chef::Provider::Package::Yum::YumCache.stub(:instance).and_return(@yum_cache) - @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) - @provider.load_current_resource - @provider.new_resource.package_name.should == "testing.i386" - @provider.new_resource.arch.should == "x86_64" - end - end - - it "should flush the cache if :before is true" do - @new_resource.stub(:flush_cache).and_return({:after => false, :before => true}) - @yum_cache.should_receive(:reload).once - @provider.load_current_resource - end - - it "should flush the cache if :before is false" do - @new_resource.stub(:flush_cache).and_return({:after => false, :before => false}) - @yum_cache.should_not_receive(:reload) - @provider.load_current_resource - end - - it "should detect --enablerepo or --disablerepo when passed among options, collect them preserving order and notify the yum cache" do - @new_resource.stub(:options).and_return("--stuff --enablerepo=foo --otherthings --disablerepo=a,b,c --enablerepo=bar") - @yum_cache.should_receive(:enable_extra_repo_control).with("--enablerepo=foo --disablerepo=a,b,c --enablerepo=bar") - @provider.load_current_resource - end - - it "should let the yum cache know extra repos are disabled if --enablerepo or --disablerepo aren't among options" do - @new_resource.stub(:options).and_return("--stuff --otherthings") - @yum_cache.should_receive(:disable_extra_repo_control) - @provider.load_current_resource - end - - it "should let the yum cache know extra repos are disabled if options aren't set" do - @new_resource.stub(:options).and_return(nil) - @yum_cache.should_receive(:disable_extra_repo_control) - @provider.load_current_resource - end - - it "should search provides if package name can't be found then set package_name to match" do - @yum_cache = double( - '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 - ) - Chef::Provider::Package::Yum::YumCache.stub(:instance).and_return(@yum_cache) - pkg = Chef::Provider::Package::Yum::RPMPackage.new("test-package", "1.2.4-11.18.el5", "x86_64", []) - @yum_cache.should_receive(:packages_from_require).and_return([pkg]) - @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) - @provider.load_current_resource - @new_resource.package_name.should == "test-package" - end - - it "should search provides if package name can't be found, warn about multiple matches, but use the first one" do - @yum_cache = double( - '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 - ) - Chef::Provider::Package::Yum::YumCache.stub(:instance).and_return(@yum_cache) - pkg_x = Chef::Provider::Package::Yum::RPMPackage.new("test-package-x", "1.2.4-11.18.el5", "x86_64", []) - pkg_y = Chef::Provider::Package::Yum::RPMPackage.new("test-package-y", "1.2.6-11.3.el5", "i386", []) - @yum_cache.should_receive(:packages_from_require).and_return([pkg_x, pkg_y]) - Chef::Log.should_receive(:warn).exactly(1).times.with(%r{matched multiple Provides}) - @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) - @provider.load_current_resource - @new_resource.package_name.should == "test-package-x" - 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', - :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 - ) - Chef::Provider::Package::Yum::YumCache.stub(:instance).and_return(@yum_cache) - @yum_cache.should_receive(:packages_from_require).twice.and_return([]) - @yum_cache.should_receive(:reload_provides) - @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) - @provider.load_current_resource - end - - 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', - :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 - ) - Chef::Provider::Package::Yum::YumCache.stub(:instance).and_return(@yum_cache) - @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) - @yum_cache.should_receive(:packages_from_require).once.and_return([]) - @yum_cache.should_not_receive(:reload_provides) - @new_resource.action(:remove) - @provider.load_current_resource - @yum_cache.should_receive(:packages_from_require).once.and_return([]) - @yum_cache.should_not_receive(:reload_provides) - @new_resource.action(:purge) - @provider.load_current_resource - end - - 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', - :reload_provides => true, - :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 - ) - Chef::Provider::Package::Yum::YumCache.stub(:instance).and_return(@yum_cache) - @yum_cache.should_receive(:packages_from_require).twice.and_return([]) - @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) - @provider.load_current_resource - @new_resource.package_name.should == "cups" - end - end - - describe "when installing a package" do - it "should run yum install with the package name and version" do - @provider.load_current_resource - Chef::Provider::Package::Yum::RPMUtils.stub(:rpmvercmp).and_return(-1) - @provider.should_receive(:yum_command).with( - "yum -d0 -e0 -y install emacs-1.0" - ) - @provider.install_package("emacs", "1.0") - end - - it "should run yum localinstall if given a path to an rpm" do - @new_resource.stub(:source).and_return("/tmp/emacs-21.4-20.el5.i386.rpm") - @provider.should_receive(:yum_command).with( - "yum -d0 -e0 -y localinstall /tmp/emacs-21.4-20.el5.i386.rpm" - ) - @provider.install_package("emacs", "21.4-20.el5") - end - - it "should run yum localinstall if given a path to an rpm as the package" do - @new_resource = Chef::Resource::Package.new("/tmp/emacs-21.4-20.el5.i386.rpm") - ::File.stub(:exists?).and_return(true) - @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) - @new_resource.source.should == "/tmp/emacs-21.4-20.el5.i386.rpm" - @provider.should_receive(:yum_command).with( - "yum -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 - - it "should run yum install with the package name, version and arch" do - @provider.load_current_resource - @new_resource.stub(:arch).and_return("i386") - Chef::Provider::Package::Yum::RPMUtils.stub(:rpmvercmp).and_return(-1) - @provider.should_receive(:yum_command).with( - "yum -d0 -e0 -y install emacs-21.4-20.el5.i386" - ) - @provider.install_package("emacs", "21.4-20.el5") - end - - it "installs the package with the options given in the resource" do - @provider.load_current_resource - @provider.candidate_version = '11' - @new_resource.stub(:options).and_return("--disablerepo epmd") - Chef::Provider::Package::Yum::RPMUtils.stub(:rpmvercmp).and_return(-1) - @provider.should_receive(:yum_command).with( - "yum -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', - :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 - ) - Chef::Provider::Package::Yum::YumCache.stub(:instance).and_return(@yum_cache) - @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) - lambda { @provider.install_package("lolcats", "0.99") }.should raise_error(Chef::Exceptions::Package, %r{Version .* not found}) - end - - it "should raise an exception if candidate version is older than the installed version and allow_downgrade is false" do - @new_resource.stub(:allow_downgrade).and_return(false) - @yum_cache = double( - 'Chef::Provider::Yum::YumCache', - :reload_installed => true, - :reset => true, - :installed_version => "1.2.4-11.18.el5", - :candidate_version => "1.2.4-11.15.el5", - :package_available? => true, - :version_available? => true, - :allow_multi_install => [ "kernel" ], - :disable_extra_repo_control => true - ) - Chef::Provider::Package::Yum::YumCache.stub(:instance).and_return(@yum_cache) - @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) - @provider.load_current_resource - lambda { @provider.install_package("cups", "1.2.4-11.15.el5") }.should raise_error(Chef::Exceptions::Package, %r{is newer than candidate package}) - end - - 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', - :reload_installed => true, - :reset => true, - :installed_version => "1.2.4-11.18.el5", - :candidate_version => "1.2.4-11.15.el5", - :package_available? => true, - :version_available? => true, - :allow_multi_install => [ "cups" ], - :package_repository => "base", - :disable_extra_repo_control => true - ) - Chef::Provider::Package::Yum::YumCache.stub(:instance).and_return(@yum_cache) - @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) - @provider.load_current_resource - @provider.should_receive(:yum_command).with( - "yum -d0 -e0 -y install cups-1.2.4-11.15.el5" - ) - @provider.install_package("cups", "1.2.4-11.15.el5") - end - - it "should run yum downgrade if candidate version is older than the installed version and allow_downgrade is true" do - @new_resource.stub(:allow_downgrade).and_return(true) - @yum_cache = double( - 'Chef::Provider::Yum::YumCache', - :reload_installed => true, - :reset => true, - :installed_version => "1.2.4-11.18.el5", - :candidate_version => "1.2.4-11.15.el5", - :package_available? => true, - :version_available? => true, - :allow_multi_install => [], - :package_repository => "base", - :disable_extra_repo_control => true - ) - Chef::Provider::Package::Yum::YumCache.stub(:instance).and_return(@yum_cache) - @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) - @provider.load_current_resource - @provider.should_receive(:yum_command).with( - "yum -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 - @new_resource.stub(:flush_cache).and_return({:after => true, :before => false}) - @provider.load_current_resource - Chef::Provider::Package::Yum::RPMUtils.stub(:rpmvercmp).and_return(-1) - @provider.should_receive(:yum_command).with( - "yum -d0 -e0 -y install emacs-1.0" - ) - @yum_cache.should_receive(:reload).once - @provider.install_package("emacs", "1.0") - end - - it "should run yum install then not flush the cache if :after is false" do - @new_resource.stub(:flush_cache).and_return({:after => false, :before => false}) - @provider.load_current_resource - Chef::Provider::Package::Yum::RPMUtils.stub(:rpmvercmp).and_return(-1) - @provider.should_receive(:yum_command).with( - "yum -d0 -e0 -y install emacs-1.0" - ) - @yum_cache.should_not_receive(:reload) - @provider.install_package("emacs", "1.0") - end - end - - 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 - @provider.candidate_version = '11' - Chef::Provider::Package::Yum::RPMUtils.stub(:rpmvercmp).and_return(-1) - @provider.should_receive(:yum_command).with( - "yum -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') - @provider.candidate_version = '11' - Chef::Provider::Package::Yum::RPMUtils.stub(:rpmvercmp).and_return(-1) - @provider.should_receive(:yum_command).with( - "yum -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', - :reload_installed => true, - :reset => true, - :installed_version => "1.2.4-11.18.el5", - :candidate_version => "1.2.4-11.15.el5", - :package_available? => true, - :version_available? => true, - :allow_multi_install => [ "kernel" ], - :disable_extra_repo_control => true - ) - Chef::Provider::Package::Yum::YumCache.stub(:instance).and_return(@yum_cache) - @provider = Chef::Provider::Package::Yum.new(@new_resource, @run_context) - @provider.load_current_resource - lambda { @provider.upgrade_package("cups", "1.2.4-11.15.el5") }.should raise_error(Chef::Exceptions::Package, %r{is newer than candidate package}) - end - - # 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 - @yum_cache.stub(:installed_version).and_return(nil) - @provider.load_current_resource - @current_resource = Chef::Resource::Package.new('cups') - @provider.candidate_version = '11' - @provider.should_receive(:upgrade_package).with( - "cups", - "11" - ) - @provider.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') - @provider.candidate_version = nil - @provider.should_not_receive(:upgrade_package) - @provider.action_upgrade - end - - 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') - @provider.candidate_version = '11' - @provider.should_receive(:upgrade_package).with( - "cups", - "11" - ) - @provider.action_upgrade - end - - it "should not call action_upgrade in the parent if the candidate is older" do - @yum_cache.stub(:installed_version).and_return("12") - @provider.load_current_resource - @current_resource = Chef::Resource::Package.new('cups') - @provider.candidate_version = '11' - @provider.should_not_receive(:upgrade_package) - @provider.action_upgrade - end - end - - describe "when removing a package" do - it "should run yum remove with the package name" do - @provider.should_receive(:yum_command).with( - "yum -d0 -e0 -y remove emacs-1.0" - ) - @provider.remove_package("emacs", "1.0") - end - - it "should run yum remove with the package name and arch" do - @new_resource.stub(:arch).and_return("x86_64") - @provider.should_receive(:yum_command).with( - "yum -d0 -e0 -y remove emacs-1.0.x86_64" - ) - @provider.remove_package("emacs", "1.0") - end - end - - describe "when purging a package" do - it "should run yum remove with the package name" do - @provider.should_receive(:yum_command).with( - "yum -d0 -e0 -y remove emacs-1.0" - ) - @provider.purge_package("emacs", "1.0") - end - end - - describe "when running yum" do - it "should run yum once if it exits with a return code of 0" do - @status = double("Status", :exitstatus => 0) - @provider.stub(:output_of_command).and_return([@status, "", ""]) - @provider.should_receive(:output_of_command).once.with( - "yum -d0 -e0 -y install emacs-1.0", - {:timeout => Chef::Config[:yum_timeout]} - ) - @provider.yum_command("yum -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 - @status = double("Status", :exitstatus => 2) - @provider.stub(:output_of_command).and_return([@status, "failure failure", "problem problem"]) - @provider.should_receive(:output_of_command).once.with( - "yum -d0 -e0 -y install emacs-1.0", - {:timeout => Chef::Config[:yum_timeout]} - ) - lambda { @provider.yum_command("yum -d0 -e0 -y install emacs-1.0") }.should 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) - @provider.stub(:output_of_command).and_return([@status, "error: %pre(demo-1-1.el5.centos.x86_64) scriptlet failed, exit status 2", ""]) - @provider.should_receive(:output_of_command).once.with( - "yum -d0 -e0 -y install emacs-1.0", - {:timeout => Chef::Config[:yum_timeout]} - ) - # will still raise an exception, can't stub out the subsequent call - lambda { @provider.yum_command("yum -d0 -e0 -y install emacs-1.0") }.should 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) - @provider.stub(:output_of_command).and_return([@status, "error: %post(demo-1-1.el5.centos.x86_64) scriptlet failed, exit status 2", ""]) - @provider.should_receive(:output_of_command).twice.with( - "yum -d0 -e0 -y install emacs-1.0", - {:timeout => Chef::Config[:yum_timeout]} - ) - # will still raise an exception, can't stub out the subsequent call - lambda { @provider.yum_command("yum -d0 -e0 -y install emacs-1.0") }.should raise_error(Chef::Exceptions::Exec) - end - end -end - -describe Chef::Provider::Package::Yum::RPMUtils do - describe "version_parse" do - before do - @rpmutils = Chef::Provider::Package::Yum::RPMUtils - end - - it "parses known good epoch strings" do - [ - [ "0:3.3", [ 0, "3.3", nil ] ], - [ "9:1.7.3", [ 9, "1.7.3", nil ] ], - [ "15:20020927", [ 15, "20020927", nil ] ] - ].each do |x, y| - @rpmutils.version_parse(x).should == y - end - end - - it "parses strange epoch strings" do - [ - [ ":3.3", [ 0, "3.3", nil ] ], - [ "-1:1.7.3", [ nil, nil, "1:1.7.3" ] ], - [ "-:20020927", [ nil, nil, ":20020927" ] ] - ].each do |x, y| - @rpmutils.version_parse(x).should == y - end - end - - it "parses known good version strings" do - [ - [ "3.3", [ nil, "3.3", nil ] ], - [ "1.7.3", [ nil, "1.7.3", nil ] ], - [ "20020927", [ nil, "20020927", nil ] ] - ].each do |x, y| - @rpmutils.version_parse(x).should == y - end - end - - it "parses strange version strings" do - [ - [ "3..3", [ nil, "3..3", nil ] ], - [ "0001.7.3", [ nil, "0001.7.3", nil ] ], - [ "20020927,3", [ nil, "20020927,3", nil ] ] - ].each do |x, y| - @rpmutils.version_parse(x).should == y - end - end - - it "parses known good version release strings" 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" ] ] - ].each do |x, y| - @rpmutils.version_parse(x).should == y - end - end - - it "parses strange version release strings" do - [ - [ "3.3-", [ nil, "3.3", nil ] ], - [ "-1jpp.2.el5", [ nil, nil, "1jpp.2.el5" ] ], - [ "-0020020927-46.el5", [ nil, "-0020020927", "46.el5" ] ] - ].each do |x, y| - @rpmutils.version_parse(x).should == y - end - end - end - - describe "rpmvercmp" do - before do - @rpmutils = Chef::Provider::Package::Yum::RPMUtils - end - - it "should validate version compare logic for standard examples" do - [ - # numeric - [ "0.0.2", "0.0.1", 1 ], - [ "0.2.0", "0.1.0", 1 ], - [ "2.0.0", "1.0.0", 1 ], - [ "0.0.1", "0.0.1", 0 ], - [ "0.0.1", "0.0.2", -1 ], - [ "0.1.0", "0.2.0", -1 ], - [ "1.0.0", "2.0.0", -1 ], - # alpha - [ "bb", "aa", 1 ], - [ "ab", "aa", 1 ], - [ "aa", "aa", 0 ], - [ "aa", "bb", -1 ], - [ "aa", "ab", -1 ], - [ "BB", "AA", 1 ], - [ "AA", "AA", 0 ], - [ "AA", "BB", -1 ], - [ "aa", "AA", 1 ], - [ "AA", "aa", -1 ], - # alphanumeric - [ "0.0.1b", "0.0.1a", 1 ], - [ "0.1b.0", "0.1a.0", 1 ], - [ "1b.0.0", "1a.0.0", 1 ], - [ "0.0.1a", "0.0.1a", 0 ], - [ "0.0.1a", "0.0.1b", -1 ], - [ "0.1a.0", "0.1b.0", -1 ], - [ "1a.0.0", "1b.0.0", -1 ], - # alphanumeric against alphanumeric - [ "0.0.1", "0.0.a", 1 ], - [ "0.1.0", "0.a.0", 1 ], - [ "1.0.0", "a.0.0", 1 ], - [ "0.0.a", "0.0.a", 0 ], - [ "0.0.a", "0.0.1", -1 ], - [ "0.a.0", "0.1.0", -1 ], - [ "a.0.0", "1.0.0", -1 ], - # alphanumeric against numeric - [ "0.0.2", "0.0.1a", 1 ], - [ "0.0.2a", "0.0.1", 1 ], - [ "0.0.1", "0.0.2a", -1 ], - [ "0.0.1a", "0.0.2", -1 ], - # length - [ "0.0.1aa", "0.0.1a", 1 ], - [ "0.0.1aa", "0.0.1aa", 0 ], - [ "0.0.1a", "0.0.1aa", -1 ], - ].each do |x, y, result| - @rpmutils.rpmvercmp(x,y).should == result - end - end - - it "should validate version compare logic for strange examples" do - [ - [ "2,0,0", "1.0.0", 1 ], - [ "0.0.1", "0,0.1", 0 ], - [ "1.0.0", "2,0,0", -1 ], - [ "002.0.0", "001.0.0", 1 ], - [ "001..0.1", "001..0.0", 1 ], - [ "-001..1", "-001..0", 1 ], - [ "1.0.1", nil, 1 ], - [ nil, nil, 0 ], - [ nil, "1.0.1", -1 ], - [ "1.0.1", "", 1 ], - [ "", "", 0 ], - [ "", "1.0.1", -1 ] - ].each do |x, y, result| - @rpmutils.rpmvercmp(x,y).should == result - end - end - - it "tests isalnum good input" do - [ 'a', 'z', 'A', 'Z', '0', '9' ].each do |t| - @rpmutils.isalnum(t).should == true - end - end - - it "tests isalnum bad input" do - [ '-', '.', '!', '^', ':', '_' ].each do |t| - @rpmutils.isalnum(t).should == false - end - end - - it "tests isalpha good input" do - [ 'a', 'z', 'A', 'Z', ].each do |t| - @rpmutils.isalpha(t).should == true - end - end - - it "tests isalpha bad input" do - [ '0', '9', '-', '.', '!', '^', ':', '_' ].each do |t| - @rpmutils.isalpha(t).should == false - end - end - - it "tests isdigit good input" do - [ '0', '9', ].each do |t| - @rpmutils.isdigit(t).should == true - end - end - - it "tests isdigit bad input" do - [ 'A', 'z', '-', '.', '!', '^', ':', '_' ].each do |t| - @rpmutils.isdigit(t).should == false - end - end - end - -end - -describe Chef::Provider::Package::Yum::RPMVersion do - describe "new - with parsing" do - before do - @rpmv = Chef::Provider::Package::Yum::RPMVersion.new("1:1.6.5-9.36.el5") - end - - it "should expose evr (name-version-release) available" do - @rpmv.e.should == 1 - @rpmv.v.should == "1.6.5" - @rpmv.r.should == "9.36.el5" - - @rpmv.evr.should == "1:1.6.5-9.36.el5" - end - - it "should output a version-release string" do - @rpmv.to_s.should == "1.6.5-9.36.el5" - end - end - - describe "new - no parsing" do - before do - @rpmv = Chef::Provider::Package::Yum::RPMVersion.new("1", "1.6.5", "9.36.el5") - end - - it "should expose evr (name-version-release) available" do - @rpmv.e.should == 1 - @rpmv.v.should == "1.6.5" - @rpmv.r.should == "9.36.el5" - - @rpmv.evr.should == "1:1.6.5-9.36.el5" - end - - it "should output a version-release string" do - @rpmv.to_s.should == "1.6.5-9.36.el5" - end - end - - it "should raise an error unless passed 1 or 3 args" do - lambda { - Chef::Provider::Package::Yum::RPMVersion.new() - }.should raise_error(ArgumentError) - lambda { - Chef::Provider::Package::Yum::RPMVersion.new("1:1.6.5-9.36.el5") - }.should_not raise_error - lambda { - Chef::Provider::Package::Yum::RPMVersion.new("1:1.6.5-9.36.el5", "extra") - }.should raise_error(ArgumentError) - lambda { - Chef::Provider::Package::Yum::RPMVersion.new("1", "1.6.5", "9.36.el5") - }.should_not raise_error - lambda { - Chef::Provider::Package::Yum::RPMVersion.new("1", "1.6.5", "9.36.el5", "extra") - }.should raise_error(ArgumentError) - end - - # thanks version_class_spec.rb! - describe "compare" do - it "should sort based on complete epoch-version-release data" do - [ - # smaller, larger - [ "0:1.6.5-9.36.el5", - "1:1.6.5-9.36.el5" ], - [ "0:2.3-15.el5", - "0:3.3-15.el5" ], - [ "0:alpha9.8-27.2", - "0:beta9.8-27.2" ], - [ "0:0.09-14jpp.3", - "0:0.09-15jpp.3" ], - [ "0:0.9.0-0.6.20110211.el5", - "0:0.9.0-0.6.20120211.el5" ], - [ "0:1.9.1-4.el5", - "0:1.9.1-5.el5" ], - [ "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" ] - ].each do |smaller, larger| - sm = Chef::Provider::Package::Yum::RPMVersion.new(smaller) - lg = Chef::Provider::Package::Yum::RPMVersion.new(larger) - sm.should be < lg - lg.should be > sm - sm.should_not == lg - end - end - - it "should sort based on partial epoch-version-release data" do - [ - # smaller, larger - [ ":1.6.5-9.36.el5", - "1:1.6.5-9.36.el5" ], - [ "2.3-15.el5", - "3.3-15.el5" ], - [ "alpha9.8", - "beta9.8" ], - [ "14jpp", - "15jpp" ], - [ "0.9.0-0.6", - "0.9.0-0.7" ], - [ "0:1.9", - "3:1.9" ], - [ "2.3-2.el5", - "2.3-2.el6" ] - ].each do |smaller, larger| - sm = Chef::Provider::Package::Yum::RPMVersion.new(smaller) - lg = Chef::Provider::Package::Yum::RPMVersion.new(larger) - sm.should be < lg - lg.should be > sm - sm.should_not == lg - end - end - - it "should verify equality of complete epoch-version-release data" do - [ - [ "0:1.6.5-9.36.el5", - "0:1.6.5-9.36.el5" ], - [ "0:2.3-15.el5", - "0:2.3-15.el5" ], - [ "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) - sm.should be == lg - end - end - - it "should verify equality of partial epoch-version-release data" do - [ - [ ":1.6.5-9.36.el5", - "0:1.6.5-9.36.el5" ], - [ "2.3-15.el5", - "2.3-15.el5" ], - [ "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) - sm.should be == lg - end - end - end - - describe "partial compare" do - it "should compare based on partial epoch-version-release data" do - [ - # smaller, larger - [ "0:1.1.1-1", - "1:" ], - [ "0:1.1.1-1", - "0:1.1.2" ], - [ "0:1.1.1-1", - "0:1.1.2-1" ], - [ "0:", - "1:1.1.1-1" ], - [ "0:1.1.1", - "0:1.1.2-1" ], - [ "0:1.1.1-1", - "0:1.1.2-1" ], - ].each do |smaller, larger| - sm = Chef::Provider::Package::Yum::RPMVersion.new(smaller) - lg = Chef::Provider::Package::Yum::RPMVersion.new(larger) - sm.partial_compare(lg).should be == -1 - lg.partial_compare(sm).should be == 1 - sm.partial_compare(lg).should_not be == 0 - end - end - - it "should verify equality based on partial epoch-version-release data" do - [ - [ "0:", - "0:1.1.1-1" ], - [ "0:1.1.1", - "0:1.1.1-1" ], - [ "0:1.1.1-1", - "0:1.1.1-1" ], - ].each do |smaller, larger| - sm = Chef::Provider::Package::Yum::RPMVersion.new(smaller) - lg = Chef::Provider::Package::Yum::RPMVersion.new(larger) - sm.partial_compare(lg).should be == 0 - end - end - end - -end - -describe Chef::Provider::Package::Yum::RPMPackage do - describe "new - with parsing" do - before do - @rpm = Chef::Provider::Package::Yum::RPMPackage.new("testing", "1:1.6.5-9.36.el5", "x86_64", []) - end - - it "should expose nevra (name-epoch-version-release-arch) available" do - @rpm.name.should == "testing" - @rpm.version.e.should == 1 - @rpm.version.v.should == "1.6.5" - @rpm.version.r.should == "9.36.el5" - @rpm.arch.should == "x86_64" - - @rpm.nevra.should == "testing-1:1.6.5-9.36.el5.x86_64" - @rpm.to_s.should == @rpm.nevra - end - - it "should always have at least one provide, itself" do - @rpm.provides.size.should == 1 - @rpm.provides[0].name == "testing" - @rpm.provides[0].version.evr == "1:1.6.5-9.36.el5" - @rpm.provides[0].flag == :== - end - end - - describe "new - no parsing" do - before do - @rpm = Chef::Provider::Package::Yum::RPMPackage.new("testing", "1", "1.6.5", "9.36.el5", "x86_64", []) - end - - it "should expose nevra (name-epoch-version-release-arch) available" do - @rpm.name.should == "testing" - @rpm.version.e.should == 1 - @rpm.version.v.should == "1.6.5" - @rpm.version.r.should == "9.36.el5" - @rpm.arch.should == "x86_64" - - @rpm.nevra.should == "testing-1:1.6.5-9.36.el5.x86_64" - @rpm.to_s.should == @rpm.nevra - end - - it "should always have at least one provide, itself" do - @rpm.provides.size.should == 1 - @rpm.provides[0].name == "testing" - @rpm.provides[0].version.evr == "1:1.6.5-9.36.el5" - @rpm.provides[0].flag == :== - end - end - - it "should raise an error unless passed 4 or 6 args" do - lambda { - Chef::Provider::Package::Yum::RPMPackage.new() - }.should raise_error(ArgumentError) - lambda { - Chef::Provider::Package::Yum::RPMPackage.new("testing") - }.should raise_error(ArgumentError) - lambda { - Chef::Provider::Package::Yum::RPMPackage.new("testing", "1:1.6.5-9.36.el5") - }.should raise_error(ArgumentError) - lambda { - Chef::Provider::Package::Yum::RPMPackage.new("testing", "1:1.6.5-9.36.el5", "x86_64") - }.should raise_error(ArgumentError) - lambda { - Chef::Provider::Package::Yum::RPMPackage.new("testing", "1:1.6.5-9.36.el5", "x86_64", []) - }.should_not raise_error - lambda { - Chef::Provider::Package::Yum::RPMPackage.new("testing", "1", "1.6.5", "9.36.el5", "x86_64") - }.should raise_error(ArgumentError) - lambda { - Chef::Provider::Package::Yum::RPMPackage.new("testing", "1", "1.6.5", "9.36.el5", "x86_64", []) - }.should_not raise_error - lambda { - Chef::Provider::Package::Yum::RPMPackage.new("testing", "1", "1.6.5", "9.36.el5", "x86_64", [], "extra") - }.should raise_error(ArgumentError) - end - - describe "<=>" do - it "should sort alphabetically based on package name" do - [ - [ "a-test", - "b-test" ], - [ "B-test", - "a-test" ], - [ "A-test", - "B-test" ], - [ "Aa-test", - "aA-test" ], - [ "1test", - "2test" ], - ].each do |smaller, larger| - sm = Chef::Provider::Package::Yum::RPMPackage.new(smaller, "0:0.0.1-1", "x86_64", []) - lg = Chef::Provider::Package::Yum::RPMPackage.new(larger, "0:0.0.1-1", "x86_64", []) - sm.should be < lg - lg.should be > sm - sm.should_not == lg - end - end - - it "should sort alphabetically based on package arch" do - [ - [ "i386", - "x86_64" ], - [ "i386", - "noarch" ], - [ "noarch", - "x86_64" ], - ].each do |smaller, larger| - sm = Chef::Provider::Package::Yum::RPMPackage.new("test-package", "0:0.0.1-1", smaller, []) - lg = Chef::Provider::Package::Yum::RPMPackage.new("test-package", "0:0.0.1-1", larger, []) - sm.should be < lg - lg.should be > sm - sm.should_not == lg - end - end - end - -end - -describe Chef::Provider::Package::Yum::RPMDbPackage do - before(:each) do - # name, version, arch, installed, available, repoid - @rpm_x = Chef::Provider::Package::Yum::RPMDbPackage.new("test-package-b", "0:1.6.5-9.36.el5", "noarch", [], false, true, "base") - @rpm_y = Chef::Provider::Package::Yum::RPMDbPackage.new("test-package-b", "0:1.6.5-9.36.el5", "noarch", [], true, true, "extras") - @rpm_z = Chef::Provider::Package::Yum::RPMDbPackage.new("test-package-b", "0:1.6.5-9.36.el5", "noarch", [], true, false, "other") - end - - describe "initialize" do - it "should return a Chef::Provider::Package::Yum::RPMDbPackage object" do - @rpm_x.should be_kind_of(Chef::Provider::Package::Yum::RPMDbPackage) - end - end - - describe "available" do - it "should return true" do - @rpm_x.available.should be == true - @rpm_y.available.should be == true - @rpm_z.available.should be == false - end - end - - describe "installed" do - it "should return true" do - @rpm_x.installed.should be == false - @rpm_y.installed.should be == true - @rpm_z.installed.should be == true - end - end - - describe "repoid" do - it "should return the source repository repoid" do - @rpm_x.repoid.should be == "base" - @rpm_y.repoid.should be == "extras" - @rpm_z.repoid.should be == "other" - end - end -end - -describe Chef::Provider::Package::Yum::RPMDependency do - describe "new - with parsing" do - before do - @rpmdep = Chef::Provider::Package::Yum::RPMDependency.new("testing", "1:1.6.5-9.36.el5", :==) - end - - it "should expose name, version, flag available" do - @rpmdep.name.should == "testing" - @rpmdep.version.e.should == 1 - @rpmdep.version.v.should == "1.6.5" - @rpmdep.version.r.should == "9.36.el5" - @rpmdep.flag.should == :== - end - end - - describe "new - no parsing" do - before do - @rpmdep = Chef::Provider::Package::Yum::RPMDependency.new("testing", "1", "1.6.5", "9.36.el5", :==) - end - - it "should expose name, version, flag available" do - @rpmdep.name.should == "testing" - @rpmdep.version.e.should == 1 - @rpmdep.version.v.should == "1.6.5" - @rpmdep.version.r.should == "9.36.el5" - @rpmdep.flag.should == :== - end - end - - it "should raise an error unless passed 3 or 5 args" do - lambda { - Chef::Provider::Package::Yum::RPMDependency.new() - }.should raise_error(ArgumentError) - lambda { - Chef::Provider::Package::Yum::RPMDependency.new("testing") - }.should raise_error(ArgumentError) - lambda { - Chef::Provider::Package::Yum::RPMDependency.new("testing", "1:1.6.5-9.36.el5") - }.should raise_error(ArgumentError) - lambda { - Chef::Provider::Package::Yum::RPMDependency.new("testing", "1:1.6.5-9.36.el5", :==) - }.should_not raise_error - lambda { - Chef::Provider::Package::Yum::RPMDependency.new("testing", "1:1.6.5-9.36.el5", :==, "extra") - }.should raise_error(ArgumentError) - lambda { - Chef::Provider::Package::Yum::RPMDependency.new("testing", "1", "1.6.5", "9.36.el5", :==) - }.should_not raise_error - lambda { - Chef::Provider::Package::Yum::RPMDependency.new("testing", "1", "1.6.5", "9.36.el5", :==, "extra") - }.should raise_error(ArgumentError) - end - - describe "parse" do - it "should parse a name, flag, version string into a valid RPMDependency object" do - @rpmdep = Chef::Provider::Package::Yum::RPMDependency.parse("testing >= 1:1.6.5-9.36.el5") - - @rpmdep.name.should == "testing" - @rpmdep.version.e.should == 1 - @rpmdep.version.v.should == "1.6.5" - @rpmdep.version.r.should == "9.36.el5" - @rpmdep.flag.should == :>= - end - - it "should parse a name into a valid RPMDependency object" do - @rpmdep = Chef::Provider::Package::Yum::RPMDependency.parse("testing") - - @rpmdep.name.should == "testing" - @rpmdep.version.e.should == nil - @rpmdep.version.v.should == nil - @rpmdep.version.r.should == nil - @rpmdep.flag.should == :== - end - - it "should parse an invalid string into the name of a RPMDependency object" do - @rpmdep = Chef::Provider::Package::Yum::RPMDependency.parse("testing blah >") - - @rpmdep.name.should == "testing blah >" - @rpmdep.version.e.should == nil - @rpmdep.version.v.should == nil - @rpmdep.version.r.should == nil - @rpmdep.flag.should == :== - end - - it "should parse various valid flags" do - [ - [ ">", :> ], - [ ">=", :>= ], - [ "=", :== ], - [ "==", :== ], - [ "<=", :<= ], - [ "<", :< ] - ].each do |before, after| - @rpmdep = Chef::Provider::Package::Yum::RPMDependency.parse("testing #{before} 1:1.1-1") - @rpmdep.flag.should == after - end - end - - it "should parse various invalid flags and treat them as names" do - [ - [ "<>", :== ], - [ "!=", :== ], - [ ">>", :== ], - [ "<<", :== ], - [ "!", :== ], - [ "~", :== ] - ].each do |before, after| - @rpmdep = Chef::Provider::Package::Yum::RPMDependency.parse("testing #{before} 1:1.1-1") - @rpmdep.name.should == "testing #{before} 1:1.1-1" - @rpmdep.flag.should == after - end - end - end - - describe "satisfy?" do - it "should raise an error unless a RPMDependency is passed" do - @rpmprovide = Chef::Provider::Package::Yum::RPMDependency.new("testing", "1:1.6.5-9.36.el5", :==) - @rpmrequire = Chef::Provider::Package::Yum::RPMDependency.new("testing", "1:1.6.5-9.36.el5", :>=) - lambda { - @rpmprovide.satisfy?("hi") - }.should raise_error(ArgumentError) - lambda { - @rpmprovide.satisfy?(@rpmrequire) - }.should_not raise_error - end - - it "should validate dependency satisfaction logic for standard examples" do - [ - # names - [ "test", "test", true ], - [ "test", "foo", false ], - # full: epoch:version-relese - [ "testing = 1:1.1-1", "testing > 1:1.1-0", true ], - [ "testing = 1:1.1-1", "testing >= 1:1.1-0", true ], - [ "testing = 1:1.1-1", "testing >= 1:1.1-1", true ], - [ "testing = 1:1.1-1", "testing = 1:1.1-1", true ], - [ "testing = 1:1.1-1", "testing == 1:1.1-1", true ], - [ "testing = 1:1.1-1", "testing <= 1:1.1-1", true ], - [ "testing = 1:1.1-1", "testing <= 1:1.1-0", false ], - [ "testing = 1:1.1-1", "testing < 1:1.1-0", false ], - # partial: epoch:version - [ "testing = 1:1.1", "testing > 1:1.0", true ], - [ "testing = 1:1.1", "testing >= 1:1.0", true ], - [ "testing = 1:1.1", "testing >= 1:1.1", true ], - [ "testing = 1:1.1", "testing = 1:1.1", true ], - [ "testing = 1:1.1", "testing == 1:1.1", true ], - [ "testing = 1:1.1", "testing <= 1:1.1", true ], - [ "testing = 1:1.1", "testing <= 1:1.0", false ], - [ "testing = 1:1.1", "testing < 1:1.0", false ], - # partial: epoch - [ "testing = 1:", "testing > 0:", true ], - [ "testing = 1:", "testing >= 0:", true ], - [ "testing = 1:", "testing >= 1:", true ], - [ "testing = 1:", "testing = 1:", true ], - [ "testing = 1:", "testing == 1:", true ], - [ "testing = 1:", "testing <= 1:", true ], - [ "testing = 1:", "testing <= 0:", false ], - [ "testing = 1:", "testing < 0:", false ], - # mix and match! - [ "testing = 1:1.1-1", "testing == 1:1.1", true ], - [ "testing = 1:1.1-1", "testing == 1:", true ], - ].each do |prov, req, result| - @rpmprovide = Chef::Provider::Package::Yum::RPMDependency.parse(prov) - @rpmrequire = Chef::Provider::Package::Yum::RPMDependency.parse(req) - - @rpmprovide.satisfy?(@rpmrequire).should == result - @rpmrequire.satisfy?(@rpmprovide).should == result - end - end - end - -end - -# thanks resource_collection_spec.rb! -describe Chef::Provider::Package::Yum::RPMDb do - before(:each) do - @rpmdb = Chef::Provider::Package::Yum::RPMDb.new - # 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") - ] - 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") - ] - @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") - @rpm_x = Chef::Provider::Package::Yum::RPMDbPackage.new("test-package-b", "0:1.6.5-9.36.el5", "x86_64", [], false, true, "extras") - @rpm_y = Chef::Provider::Package::Yum::RPMDbPackage.new("test-package-b", "1:1.6.5-9.36.el5", "x86_64", [], true, true, "extras") - @rpm_z = Chef::Provider::Package::Yum::RPMDbPackage.new("test-package-c", "0:1.6.5-9.36.el5", "noarch", deps_z, true, true, "base") - @rpm_z_mirror = Chef::Provider::Package::Yum::RPMDbPackage.new("test-package-c", "0:1.6.5-9.36.el5", "noarch", deps_z, true, true, "base") - end - - describe "initialize" do - it "should return a Chef::Provider::Package::Yum::RPMDb object" do - @rpmdb.should be_kind_of(Chef::Provider::Package::Yum::RPMDb) - end - end - - describe "push" do - it "should accept an RPMDbPackage object through pushing" do - lambda { @rpmdb.push(@rpm_w) }.should_not raise_error - end - - it "should accept multiple RPMDbPackage object through pushing" do - lambda { @rpmdb.push(@rpm_w, @rpm_x, @rpm_y, @rpm_z) }.should_not raise_error - end - - it "should only accept an RPMDbPackage object" do - lambda { @rpmdb.push("string") }.should raise_error - end - - it "should add the package to the package db" do - @rpmdb.push(@rpm_w) - @rpmdb["test-package-b"].should_not be == nil - end - - it "should add conditionally add the package to the available list" do - @rpmdb.available_size.should be == 0 - @rpmdb.push(@rpm_v, @rpm_w) - @rpmdb.available_size.should be == 1 - end - - it "should add conditionally add the package to the installed list" do - @rpmdb.installed_size.should be == 0 - @rpmdb.push(@rpm_w, @rpm_x) - @rpmdb.installed_size.should be == 1 - end - - it "should have a total of 2 packages in the RPMDb" do - @rpmdb.size.should be == 0 - @rpmdb.push(@rpm_w, @rpm_x, @rpm_y, @rpm_z) - @rpmdb.size.should be == 2 - end - - it "should keep the Array unique when a duplicate is pushed" do - @rpmdb.push(@rpm_z, @rpm_z_mirror) - @rpmdb["test-package-c"].size.should be == 1 - end - - it "should register the package provides in the provides index" do - @rpmdb.push(@rpm_v, @rpm_w, @rpm_z) - @rpmdb.lookup_provides("test-package-a")[0].should be == @rpm_v - @rpmdb.lookup_provides("config(test)")[0].should be == @rpm_z - @rpmdb.lookup_provides("libz.so.1()(64bit)")[0].should be == @rpm_v - @rpmdb.lookup_provides("libz.so.1()(64bit)")[1].should be == @rpm_z - end - end - - describe "<<" do - it "should accept an RPMPackage object through the << operator" do - lambda { @rpmdb << @rpm_w }.should_not raise_error - end - end - - describe "lookup" do - it "should return an Array of RPMPackage objects by index" do - @rpmdb << @rpm_w - @rpmdb.lookup("test-package-b").should be_kind_of(Array) - end - end - - describe "[]" do - it "should return an Array of RPMPackage objects though the [index] operator" do - @rpmdb << @rpm_w - @rpmdb["test-package-b"].should be_kind_of(Array) - end - - it "should return an Array of 3 RPMPackage objects" do - @rpmdb.push(@rpm_w, @rpm_x, @rpm_y, @rpm_z) - @rpmdb["test-package-b"].size.should be == 3 - end - - it "should return an Array of RPMPackage objects sorted from newest to oldest" do - @rpmdb.push(@rpm_w, @rpm_x, @rpm_y, @rpm_z) - @rpmdb["test-package-b"][0].should be == @rpm_y - @rpmdb["test-package-b"][1].should be == @rpm_x - @rpmdb["test-package-b"][2].should be == @rpm_w - end - end - - describe "lookup_provides" do - it "should return an Array of RPMPackage objects by index" do - @rpmdb << @rpm_z - x = @rpmdb.lookup_provides("config(test)") - x.should be_kind_of(Array) - x[0].should be == @rpm_z - end - end - - describe "clear" do - it "should clear the RPMDb" do - @rpmdb.should_receive(:clear_available).once - @rpmdb.should_receive(:clear_installed).once - @rpmdb.push(@rpm_w, @rpm_x, @rpm_y, @rpm_z) - @rpmdb.size.should_not be == 0 - @rpmdb.lookup_provides("config(test)").should be_kind_of(Array) - @rpmdb.clear - @rpmdb.lookup_provides("config(test)").should be == nil - @rpmdb.size.should be == 0 - end - end - - describe "clear_available" do - it "should clear the available list" do - @rpmdb.push(@rpm_w, @rpm_x, @rpm_y, @rpm_z) - @rpmdb.available_size.should_not be == 0 - @rpmdb.clear_available - @rpmdb.available_size.should be == 0 - end - end - - describe "available?" do - it "should return true if a package is available" do - @rpmdb.available?(@rpm_w).should be == false - @rpmdb.push(@rpm_v, @rpm_w) - @rpmdb.available?(@rpm_v).should be == false - @rpmdb.available?(@rpm_w).should be == true - end - end - - describe "clear_installed" do - it "should clear the installed list" do - @rpmdb.push(@rpm_w, @rpm_x, @rpm_y, @rpm_z) - @rpmdb.installed_size.should_not be == 0 - @rpmdb.clear_installed - @rpmdb.installed_size.should be == 0 - end - end - - describe "installed?" do - it "should return true if a package is installed" do - @rpmdb.installed?(@rpm_w).should be == false - @rpmdb.push(@rpm_w, @rpm_x) - @rpmdb.installed?(@rpm_w).should be == true - @rpmdb.installed?(@rpm_x).should be == false - end - end - - describe "whatprovides" do - it "should raise an error unless a RPMDependency is passed" do - @rpmprovide = Chef::Provider::Package::Yum::RPMDependency.new("testing", "1:1.6.5-9.36.el5", :==) - @rpmrequire = Chef::Provider::Package::Yum::RPMDependency.new("testing", "1:1.6.5-9.36.el5", :>=) - lambda { - @rpmdb.whatprovides("hi") - }.should raise_error(ArgumentError) - lambda { - @rpmdb.whatprovides(@rpmrequire) - }.should_not raise_error - end - - it "should return an Array of packages statisfying a RPMDependency" do - @rpmdb.push(@rpm_v, @rpm_w, @rpm_z) - - @rpmrequire = Chef::Provider::Package::Yum::RPMDependency.parse("test-package-a >= 1.6.5") - x = @rpmdb.whatprovides(@rpmrequire) - x.should be_kind_of(Array) - x[0].should be == @rpm_v - - @rpmrequire = Chef::Provider::Package::Yum::RPMDependency.parse("libz.so.1()(64bit)") - x = @rpmdb.whatprovides(@rpmrequire) - x.should be_kind_of(Array) - x[0].should be == @rpm_v - x[1].should be == @rpm_z - end - end - -end - -describe Chef::Provider::Package::Yum::YumCache do - # allow for the reset of a Singleton - # thanks to Ian White (http://blog.ardes.com/2006/12/11/testing-singletons-with-ruby) - class << Chef::Provider::Package::Yum::YumCache - def reset_instance - Singleton.send :__init__, self - self - end - end - - before(:each) do - @stdin = double("STDIN", :nil_object => true) - @stdout = double("STDOUT", :nil_object => true) - - @stdout_good = <<EOF -[option installonlypkgs] kernel kernel-bigmem kernel-enterprise -erlang-mochiweb 0 1.4.1 5.el5 x86_64 ['erlang-mochiweb = 1.4.1-5.el5', 'mochiweb = 1.4.1-5.el5'] i installed -zip 0 2.31 2.el5 x86_64 ['zip = 2.31-2.el5'] r base -zisofs-tools 0 1.0.6 3.2.2 x86_64 [] a extras -zlib 0 1.2.3 3 x86_64 ['zlib = 1.2.3-3', 'libz.so.1()(64bit)'] r base -zlib 0 1.2.3 3 i386 ['zlib = 1.2.3-3', 'libz.so.1'] r base -zlib-devel 0 1.2.3 3 i386 [] a extras -zlib-devel 0 1.2.3 3 x86_64 ['zlib-devel = 1.2.3-3'] r base -znc 0 0.098 1.el5 x86_64 [] a base -znc-devel 0 0.098 1.el5 i386 [] a extras -znc-devel 0 0.098 1.el5 x86_64 [] a base -znc-extra 0 0.098 1.el5 x86_64 [] a base -znc-modtcl 0 0.098 1.el5 x86_64 [] a base -znc-test.beta1 0 0.098 1.el5 x86_64 [] a extras -znc-test.test.beta1 0 0.098 1.el5 x86_64 [] a base -EOF - @stdout_bad_type = <<EOF -zip 0 2.31 2.el5 x86_64 ['zip = 2.31-2.el5'] r base -zlib 0 1.2.3 3 x86_64 ['zlib = 1.2.3-3', 'libz.so.1()(64bit)'] c base -zlib-devel 0 1.2.3 3 i386 [] a extras -zlib-devel 0 1.2.3 3 x86_64 ['zlib-devel = 1.2.3-3'] bad installed -znc-modtcl 0 0.098 1.el5 x86_64 [] a base -EOF - - @stdout_bad_separators = <<EOF -zip 0 2.31 2.el5 x86_64 ['zip = 2.31-2.el5'] r base -zlib 0 1.2.3 3 x86_64 ['zlib = 1.2.3-3', 'libz.so.1()(64bit)'] i base bad -zlib-devel 0 1.2.3 3 i386 [] a extras -bad zlib-devel 0 1.2.3 3 x86_64 ['zlib-devel = 1.2.3-3'] i installed -znc-modtcl 0 0.098 1.el5 x86_64 [] a base bad -EOF - - @stdout_no_output = "" - - @stderr = <<EOF -yum-dump Config Error: File contains no section headers. -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.stub(:shell_out!).and_return(@status) - end - - describe "initialize" do - it "should return a Chef::Provider::Package::Yum::YumCache object" do - @yc.should be_kind_of(Chef::Provider::Package::Yum::YumCache) - end - - it "should register reload for start of Chef::Client runs" do - Chef::Provider::Package::Yum::YumCache.reset_instance - Chef::Client.should_receive(:when_run_starts) do |&b| - b.should_not be_nil - end - @yc = Chef::Provider::Package::Yum::YumCache.instance - end - end - - describe "refresh" do - it "should implicitly call yum-dump.py only once by default after being instantiated" do - @yc.should_receive(:shell_out!).once - @yc.installed_version("zlib") - @yc.reset - @yc.installed_version("zlib") - end - - it "should run yum-dump.py using the system python when next_refresh is for :all" do - @yc.reload - @yc.should_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 - @yc.should_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 - @yc.should_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") - @yc.should_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") - @yc.should_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 - - it "should warn about invalid data with too many separators" do - @status = double("Status", :exitstatus => 0, :stdin => @stdin, :stdout => @stdout_bad_separators, :stderr => @stderr) - @yc.stub(:shell_out!).and_return(@status) - Chef::Log.should_receive(:warn).exactly(3).times.with(%r{Problem parsing}) - @yc.refresh - end - - it "should warn about invalid data with an incorrect type" do - @status = double("Status", :exitstatus => 0, :stdin => @stdin, :stdout => @stdout_bad_type, :stderr => @stderr) - @yc.stub(:shell_out!).and_return(@status) - Chef::Log.should_receive(:warn).exactly(2).times.with(%r{Problem parsing}) - @yc.refresh - end - - it "should warn about no output from yum-dump.py" do - @status = double("Status", :exitstatus => 0, :stdin => @stdin, :stdout => @stdout_no_output, :stderr => @stderr) - @yc.stub(:shell_out!).and_return(@status) - Chef::Log.should_receive(:warn).exactly(1).times.with(%r{no output from yum-dump.py}) - @yc.refresh - end - - 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) - @yc.stub(:shell_out!).and_return(@status) - lambda { @yc.refresh}.should 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 - @yc.available_version("erlang-mochiweb").should be == nil - @yc.installed_version("erlang-mochiweb").should_not be == nil - end - - it "should parse type 'a' into an available state for a package" do - @yc.available_version("znc").should_not be == nil - @yc.installed_version("znc").should be == nil - end - - it "should parse type 'r' into an installed and available states for a package" do - @yc.available_version("zip").should_not be == nil - @yc.installed_version("zip").should_not be == nil - end - - it "should parse installonlypkgs from yum-dump.py options output" do - @yc.allow_multi_install.should be == %w{kernel kernel-bigmem kernel-enterprise} - end - end - - describe "installed_version" do - it "should take one or two arguments" do - lambda { @yc.installed_version("zip") }.should_not raise_error - lambda { @yc.installed_version("zip", "i386") }.should_not raise_error - lambda { @yc.installed_version("zip", "i386", "extra") }.should raise_error(ArgumentError) - end - - it "should return version-release for matching package regardless of arch" do - @yc.installed_version("zip", "x86_64").should be == "2.31-2.el5" - @yc.installed_version("zip", nil).should be == "2.31-2.el5" - end - - it "should return version-release for matching package and arch" do - @yc.installed_version("zip", "x86_64").should be == "2.31-2.el5" - @yc.installed_version("zisofs-tools", "i386").should be == nil - end - - it "should return nil for an unmatched package" do - @yc.installed_version(nil, nil).should be == nil - @yc.installed_version("test1", nil).should be == nil - @yc.installed_version("test2", "x86_64").should be == nil - end - end - - describe "available_version" do - it "should take one or two arguments" do - lambda { @yc.available_version("zisofs-tools") }.should_not raise_error - lambda { @yc.available_version("zisofs-tools", "i386") }.should_not raise_error - lambda { @yc.available_version("zisofs-tools", "i386", "extra") }.should raise_error(ArgumentError) - end - - it "should return version-release for matching package regardless of arch" do - @yc.available_version("zip", "x86_64").should be == "2.31-2.el5" - @yc.available_version("zip", nil).should be == "2.31-2.el5" - end - - it "should return version-release for matching package and arch" do - @yc.available_version("zip", "x86_64").should be == "2.31-2.el5" - @yc.available_version("zisofs-tools", "i386").should be == nil - end - - it "should return nil for an unmatched package" do - @yc.available_version(nil, nil).should be == nil - @yc.available_version("test1", nil).should be == nil - @yc.available_version("test2", "x86_64").should be == nil - end - end - - describe "version_available?" do - it "should take two or three arguments" do - lambda { @yc.version_available?("zisofs-tools") }.should raise_error(ArgumentError) - lambda { @yc.version_available?("zisofs-tools", "1.0.6-3.2.2") }.should_not raise_error - lambda { @yc.version_available?("zisofs-tools", "1.0.6-3.2.2", "x86_64") }.should_not raise_error - end - - it "should return true if our package-version-arch is available" do - @yc.version_available?("zisofs-tools", "1.0.6-3.2.2", "x86_64").should be == true - end - - it "should return true if our package-version, no arch, is available" do - @yc.version_available?("zisofs-tools", "1.0.6-3.2.2", nil).should be == true - @yc.version_available?("zisofs-tools", "1.0.6-3.2.2").should be == true - end - - it "should return false if our package-version-arch isn't available" do - @yc.version_available?("zisofs-tools", "1.0.6-3.2.2", "pretend").should be == false - @yc.version_available?("zisofs-tools", "pretend", "x86_64").should be == false - @yc.version_available?("pretend", "1.0.6-3.2.2", "x86_64").should be == false - end - - it "should return false if our package-version, no arch, isn't available" do - @yc.version_available?("zisofs-tools", "pretend", nil).should be == false - @yc.version_available?("zisofs-tools", "pretend").should be == false - @yc.version_available?("pretend", "1.0.6-3.2.2").should be == false - end - end - - describe "package_repository" do - it "should take two or three arguments" do - lambda { @yc.package_repository("zisofs-tools") }.should raise_error(ArgumentError) - lambda { @yc.package_repository("zisofs-tools", "1.0.6-3.2.2") }.should_not raise_error - lambda { @yc.package_repository("zisofs-tools", "1.0.6-3.2.2", "x86_64") }.should_not raise_error - end - - it "should return repoid for package-version-arch" do - @yc.package_repository("zlib-devel", "1.2.3-3", "i386").should be == "extras" - @yc.package_repository("zlib-devel", "1.2.3-3", "x86_64").should be == "base" - end - - it "should return repoid for package-version, no arch" do - @yc.package_repository("zisofs-tools", "1.0.6-3.2.2", nil).should be == "extras" - @yc.package_repository("zisofs-tools", "1.0.6-3.2.2").should be == "extras" - end - - it "should return nil when no match for package-version-arch" do - @yc.package_repository("zisofs-tools", "1.0.6-3.2.2", "pretend").should be == nil - @yc.package_repository("zisofs-tools", "pretend", "x86_64").should be == nil - @yc.package_repository("pretend", "1.0.6-3.2.2", "x86_64").should be == nil - end - - it "should return nil when no match for package-version, no arch" do - @yc.package_repository("zisofs-tools", "pretend", nil).should be == nil - @yc.package_repository("zisofs-tools", "pretend").should be == nil - @yc.package_repository("pretend", "1.0.6-3.2.2").should be == nil - end - end - - describe "reset" do - it "should empty the installed and available packages RPMDb" do - @yc.available_version("zip", "x86_64").should be == "2.31-2.el5" - @yc.installed_version("zip", "x86_64").should be == "2.31-2.el5" - @yc.reset - @yc.available_version("zip", "x86_64").should be == nil - @yc.installed_version("zip", "x86_64").should be == nil - end - end - - describe "package_available?" do - it "should return true a package name is available" do - @yc.package_available?("zisofs-tools").should be == true - @yc.package_available?("moo").should be == false - @yc.package_available?(nil).should be == false - end - - it "should return true a package name + arch is available" do - @yc.package_available?("zlib-devel.i386").should be == true - @yc.package_available?("zisofs-tools.x86_64").should be == true - @yc.package_available?("znc-test.beta1.x86_64").should be == true - @yc.package_available?("znc-test.beta1").should be == true - @yc.package_available?("znc-test.test.beta1").should be == true - @yc.package_available?("moo.i386").should be == false - @yc.package_available?("zisofs-tools.beta").should be == false - @yc.package_available?("znc-test.test").should be == false - end - end - - describe "enable_extra_repo_control" do - it "should set @extra_repo_control to arg" do - @yc.enable_extra_repo_control("--enablerepo=test") - @yc.extra_repo_control.should be == "--enablerepo=test" - end - - it "should call reload once when set to flag cache for update" do - @yc.should_receive(:reload).once - @yc.enable_extra_repo_control("--enablerepo=test") - @yc.enable_extra_repo_control("--enablerepo=test") - end - end - - describe "disable_extra_repo_control" do - it "should set @extra_repo_control to nil" do - @yc.enable_extra_repo_control("--enablerepo=test") - @yc.disable_extra_repo_control - @yc.extra_repo_control.should be == nil - end - - it "should call reload once when cleared to flag cache for update" do - @yc.should_receive(:reload).once - @yc.enable_extra_repo_control("--enablerepo=test") - @yc.should_receive(:reload).once - @yc.disable_extra_repo_control - @yc.disable_extra_repo_control - end - end - -end diff --git a/spec/unit/provider/package/zypper_spec.rb b/spec/unit/provider/package/zypper_spec.rb deleted file mode 100644 index 87f02d7794..0000000000 --- a/spec/unit/provider/package/zypper_spec.rb +++ /dev/null @@ -1,233 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef::Provider::Package::Zypper 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") - - @current_resource = Chef::Resource::Package.new("cups") - - @status = double("Status", :exitstatus => 0) - - @provider = Chef::Provider::Package::Zypper.new(@new_resource, @run_context) - Chef::Resource::Package.stub(:new).and_return(@current_resource) - @provider.stub(:popen4).and_return(@status) - @stderr = StringIO.new - @stdout = StringIO.new - @pid = double("PID") - @provider.stub(:`).and_return("2.0") - end - - describe "when loading the current package state" do - it "should create a current resource with the name of the new_resource" do - Chef::Resource::Package.should_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 - @current_resource.should_receive(:package_name).with(@new_resource.package_name) - @provider.load_current_resource - end - - it "should run zypper info with the package name" do - @provider.should_receive(:popen4).with("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 - @provider.stub(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @current_resource.should_receive(:version).with(nil).and_return(true) - @provider.load_current_resource - end - - it "should set the installed version if zypper info has one" do - @stdout = StringIO.new("Version: 1.0\nInstalled: Yes\n") - @provider.stub(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @current_resource.should_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 - @stdout = StringIO.new("Version: 1.0\nInstalled: No\nStatus: out-of-date (version 0.9 installed)") - - @provider.stub(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @provider.load_current_resource - @provider.candidate_version.should eql("1.0") - end - - it "should raise an exception if zypper info fails" do - @status.should_receive(:exitstatus).and_return(1) - lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Package) - end - - it "should not raise an exception if zypper info succeeds" do - @status.should_receive(:exitstatus).and_return(0) - lambda { @provider.load_current_resource }.should_not raise_error - end - - it "should return the current resouce" do - @provider.load_current_resource.should eql(@current_resource) - end - end - - describe "install_package" do - it "should run zypper install with the package name and version" do - Chef::Config.stub(:[]).with(:zypper_check_gpg).and_return(true) - @provider.should_receive(:shell_out!).with( - "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 - Chef::Config.stub(:[]).with(:zypper_check_gpg).and_return(false) - @provider.should_receive(:shell_out!).with( - "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 - Chef::Log.should_receive(:warn).with( - /All packages will be installed without gpg signature checks/) - @provider.should_receive(:shell_out!).with( - "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 - Chef::Config.stub(:[]).with(:zypper_check_gpg).and_return(true) - @provider.should_receive(:shell_out!).with( - "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 - Chef::Config.stub(:[]).with(:zypper_check_gpg).and_return(false) - @provider.should_receive(:shell_out!).with( - "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 - Chef::Log.should_receive(:warn).with( - /All packages will be installed without gpg signature checks/) - @provider.should_receive(:shell_out!).with( - "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 - @provider.should_receive(:shell_out!).with( - "zypper --non-interactive --no-gpg-checks install "+ - "--auto-agree-with-licenses emacs=1.0") - - @provider.upgrade_package("emacs", "1.0") - end - end - - describe "remove_package" do - - context "when package version is not explicitly specified" do - it "should run zypper remove with the package name" do - Chef::Config.stub(:[]).with(:zypper_check_gpg).and_return(true) - @provider.should_receive(:shell_out!).with( - "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 - Chef::Config.stub(:[]).with(:zypper_check_gpg).and_return(true) - @provider.should_receive(:shell_out!).with( - "zypper --non-interactive remove emacs=1.0") - @provider.remove_package("emacs", "1.0") - end - it "should run zypper remove without gpg checks" do - Chef::Config.stub(:[]).with(:zypper_check_gpg).and_return(false) - @provider.should_receive(:shell_out!).with( - "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 - Chef::Log.should_receive(:warn).with( - /All packages will be installed without gpg signature checks/) - @provider.should_receive(:shell_out!).with( - "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 - @provider.should_receive(:shell_out!).with( - "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 - Chef::Config.stub(:[]).with(:zypper_check_gpg).and_return(false) - @provider.should_receive(:shell_out!).with( - "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 - Chef::Log.should_receive(:warn).with( - /All packages will be installed without gpg signature checks/) - @provider.should_receive(:shell_out!).with( - "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 - @provider.stub(:`).and_return("0.11.6") - end - - describe "install_package" do - it "should run zypper install with the package name and version" do - @provider.should_receive(:shell_out!).with( - "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 - @provider.should_receive(:shell_out!).with( - "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 - @provider.should_receive(:shell_out!).with( - "zypper --no-gpg-checks remove -y emacs") - @provider.remove_package("emacs", "1.0") - end - end - end -end diff --git a/spec/unit/provider/package_spec.rb b/spec/unit/provider/package_spec.rb deleted file mode 100644 index 375a0d0646..0000000000 --- a/spec/unit/provider/package_spec.rb +++ /dev/null @@ -1,427 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -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" - end - - describe "when installing a package" do - before(:each) do - @provider.current_resource = @current_resource - @provider.stub(:install_package).and_return(true) - end - - it "should raise a Chef::Exceptions::Package if no version is specified, and no candidate is available" do - @provider.candidate_version = nil - lambda { @provider.run_action(:install) }.should raise_error(Chef::Exceptions::Package) - end - - it "should call preseed_package if a response_file is given" do - @new_resource.response_file("foo") - @provider.should_receive(:get_preseed_file).with( - @new_resource.name, - @provider.candidate_version - ).and_return("/var/cache/preseed-test") - - @provider.should_receive(:preseed_package).with( - "/var/cache/preseed-test" - ).and_return(true) - @provider.run_action(:install) - end - - it "should not call preseed_package if a response_file is not given" do - @provider.should_not_receive(:preseed_package) - @provider.run_action(:install) - end - - it "should install the package at the candidate_version if it is not already installed" do - @provider.should_receive(:install_package).with( - @new_resource.name, - @provider.candidate_version - ).and_return(true) - @provider.run_action(:install) - @new_resource.should 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") - @provider.should_receive(:install_package).with( - @new_resource.name, - @new_resource.version - ).and_return(true) - @provider.run_action(:install) - @new_resource.should 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") - @current_resource.stub(:version).and_return("0.99") - @provider.should_receive(:install_package).with( - @new_resource.name, - @new_resource.version - ).and_return(true) - @provider.run_action(:install) - @new_resource.should 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") - @provider.should_not_receive(:install_package) - @provider.run_action(:install) - @new_resource.should_not 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") - @provider.should_not_receive(:install_package) - @provider.run_action(:install) - @new_resource.should_not 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") - @provider.stub(: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) - end - - it "should set the resource to updated if it installs the package" do - @provider.run_action(:install) - @new_resource.should be_updated - end - - end - - describe "when upgrading the package" do - before(:each) do - @provider.stub(:upgrade_package).and_return(true) - end - - it "should upgrade the package if the current version is not the candidate version" do - @provider.should_receive(:upgrade_package).with( - @new_resource.name, - @provider.candidate_version - ).and_return(true) - @provider.run_action(:upgrade) - @new_resource.should be_updated_by_last_action - end - - it "should set the resource to updated if it installs the package" do - @provider.run_action(:upgrade) - @new_resource.should be_updated - end - - it "should not install the package if the current version is the candidate version" do - @current_resource.version "1.0" - @provider.should_not_receive(:upgrade_package) - @provider.run_action(:upgrade) - @new_resource.should_not be_updated_by_last_action - end - - it "should print the word 'uninstalled' if there was no original version" do - @current_resource.stub(:version).and_return(nil) - Chef::Log.should_receive(:info).with("package[emacs] upgraded from uninstalled to 1.0") - @provider.run_action(:upgrade) - @new_resource.should be_updated_by_last_action - end - - it "should raise a Chef::Exceptions::Package if current version and candidate are nil" do - @current_resource.stub(:version).and_return(nil) - @provider.candidate_version = nil - lambda { @provider.run_action(:upgrade) }.should 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 - @provider.should_not_receive(:upgrade_package) - @provider.run_action(:upgrade) - @new_resource.should_not be_updated_by_last_action - end - end - - describe "When removing the package" do - before(:each) do - @provider.stub(:remove_package).and_return(true) - @current_resource.version '1.4.2' - end - - it "should remove the package if it is installed" do - @provider.should be_removing_package - @provider.should_receive(:remove_package).with('emacs', nil) - @provider.run_action(:remove) - @new_resource.should be_updated - @new_resource.should 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" - @provider.should be_removing_package - @provider.should_receive(:remove_package).with('emacs', '1.4.2') - @provider.run_action(:remove) - @new_resource.should 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" - @provider.should_not be_removing_package - @provider.should_not_receive(:remove_package) - @provider.run_action(:remove) - @new_resource.should_not be_updated_by_last_action - end - - it "should not remove the package if it is not installed" do - @provider.should_not_receive(:remove_package) - @current_resource.stub(:version).and_return(nil) - @provider.run_action(:remove) - @new_resource.should_not be_updated_by_last_action - end - - it "should set the resource to updated if it removes the package" do - @provider.run_action(:remove) - @new_resource.should be_updated - end - - end - - describe "When purging the package" do - before(:each) do - @provider.stub(:purge_package).and_return(true) - @current_resource.version '1.4.2' - end - - it "should purge the package if it is installed" do - @provider.should be_removing_package - @provider.should_receive(:purge_package).with('emacs', nil) - @provider.run_action(:purge) - @new_resource.should be_updated - @new_resource.should 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" - @provider.should be_removing_package - @provider.should_receive(:purge_package).with('emacs', '1.4.2') - @provider.run_action(:purge) - @new_resource.should 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" - @provider.should_not be_removing_package - @provider.should_not_receive(:purge_package) - @provider.run_action(:purge) - @new_resource.should_not 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) - @provider.should_not be_removing_package - - @provider.should_not_receive(:purge_package) - @provider.run_action(:purge) - @new_resource.should_not be_updated_by_last_action - end - - it "should set the resource to updated if it purges the package" do - @provider.run_action(:purge) - @new_resource.should be_updated - end - - end - - describe "when reconfiguring the package" do - before(:each) do - @provider.stub(:reconfig_package).and_return(true) - end - - it "should info log, reconfigure the package and update the resource" do - @current_resource.stub(:version).and_return('1.0') - @new_resource.stub(:response_file).and_return(true) - @provider.should_receive(:get_preseed_file).and_return('/var/cache/preseed-test') - @provider.stub(:preseed_package).and_return(true) - @provider.stub(:reconfig_package).and_return(true) - Chef::Log.should_receive(:info).with("package[emacs] reconfigured") - @provider.should_receive(:reconfig_package) - @provider.run_action(:reconfig) - @new_resource.should be_updated - @new_resource.should be_updated_by_last_action - end - - it "should debug log and not reconfigure the package if the package is not installed" do - @current_resource.stub(:version).and_return(nil) - Chef::Log.should_receive(:debug).with("package[emacs] is NOT installed - nothing to do") - @provider.should_not_receive(:reconfig_package) - @provider.run_action(:reconfig) - @new_resource.should_not be_updated_by_last_action - end - - it "should debug log and not reconfigure the package if no response_file is given" do - @current_resource.stub(:version).and_return('1.0') - @new_resource.stub(:response_file).and_return(nil) - Chef::Log.should_receive(:debug).with("package[emacs] no response_file provided - nothing to do") - @provider.should_not_receive(:reconfig_package) - @provider.run_action(:reconfig) - @new_resource.should_not be_updated_by_last_action - end - - it "should debug log and not reconfigure the package if the response_file has not changed" do - @current_resource.stub(:version).and_return('1.0') - @new_resource.stub(:response_file).and_return(true) - @provider.should_receive(:get_preseed_file).and_return(false) - @provider.stub(:preseed_package).and_return(false) - Chef::Log.should_receive(:debug).with("package[emacs] preseeding has not changed - nothing to do") - @provider.should_not_receive(:reconfig_package) - @provider.run_action(:reconfig) - @new_resource.should_not be_updated_by_last_action - end - end - - describe "when running commands to be implemented by subclasses" do - it "should raises UnsupportedAction for install" do - lambda { @provider.install_package('emacs', '1.4.2') }.should raise_error(Chef::Exceptions::UnsupportedAction) - end - - it "should raises UnsupportedAction for upgrade" do - lambda { @provider.upgrade_package('emacs', '1.4.2') }.should raise_error(Chef::Exceptions::UnsupportedAction) - end - - it "should raises UnsupportedAction for remove" do - lambda { @provider.remove_package('emacs', '1.4.2') }.should raise_error(Chef::Exceptions::UnsupportedAction) - end - - it "should raises UnsupportedAction for purge" do - lambda { @provider.purge_package('emacs', '1.4.2') }.should raise_error(Chef::Exceptions::UnsupportedAction) - end - - it "should raise UnsupportedAction for preseed_package" do - preseed_file = "/tmp/sun-jdk-package-preseed-file.seed" - lambda { @provider.preseed_package(preseed_file) }.should raise_error(Chef::Exceptions::UnsupportedAction) - end - - it "should raise UnsupportedAction for reconfig" do - lambda { @provider.reconfig_package('emacs', '1.4.2') }.should 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' - end - - describe "creating the cookbook file resource to fetch the response file" do - before do - Chef::FileCache.should_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 - Chef::FileCache.stub(:create_cache_path).and_return("/tmp/preseed/java") - @provider.preseed_resource('java', '6').run_context.should_not be_nil - @provider.preseed_resource('java', '6').run_context.should equal(@provider.run_context) - end - - it "should set the cookbook name of the remote file to the new resources cookbook name" do - @provider.preseed_resource('java', '6').cookbook_name.should == 'java' - end - - it "should set remote files source to the new resources response file" do - @provider.preseed_resource('java', '6').source.should == 'java.response' - end - - it "should never back up the cached response file" do - @provider.preseed_resource('java', '6').backup.should be_false - end - - it "sets the install path of the resource to $file_cache/$cookbook/$pkg_name-$pkg_version.seed" do - @provider.preseed_resource('java', '6').path.should == '/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 - - @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') - - - @provider.should_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) - end - - it "creates the preseed file in the cache" do - @response_file_resource.should_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 - @provider.get_preseed_file("java", "6").should == @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) - @response_file_resource.should_not be_updated_by_last_action - # don't let the response_file_resource set updated to true - @response_file_resource.should_receive(:run_action).with(:create) - @provider.get_preseed_file("java", "6").should be(false) - 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 33c402836b..0000000000 --- a/spec/unit/provider/powershell_spec.rb +++ /dev/null @@ -1,38 +0,0 @@ -# -# Author:: Adam Edwards (<adamed@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 - @provider.flags.split(' ').pop.should == "-File" - end - -end diff --git a/spec/unit/provider/registry_key_spec.rb b/spec/unit/provider/registry_key_spec.rb deleted file mode 100644 index 2cfbcf98f1..0000000000 --- a/spec/unit/provider/registry_key_spec.rb +++ /dev/null @@ -1,283 +0,0 @@ -# -# Author:: Lamont Granquist (lamont@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' - -shared_examples_for "a registry key" do - before(:each) do - @node = Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - - @new_resource = Chef::Resource::RegistryKey.new("windows is fun", @run_context) - @new_resource.key keyname - @new_resource.values( testval1 ) - @new_resource.recursive false - - @provider = Chef::Provider::RegistryKey.new(@new_resource, @run_context) - - @provider.stub(:running_on_windows!).and_return(true) - @double_registry = double(Chef::Win32::Registry) - @provider.stub(:registry).and_return(@double_registry) - end - - describe "when first created" do - end - - describe "executing load_current_resource" do - describe "when the key exists" do - before(:each) do - @double_registry.should_receive(:key_exists?).with(keyname).and_return(true) - @double_registry.should_receive(:get_values).with(keyname).and_return( testval2 ) - @provider.load_current_resource - end - - it "should set the key of the current resource to the key of the new resource" do - @provider.current_resource.key.should == @new_resource.key - end - - it "should set the architecture of the current resource to the architecture of the new resource" do - @provider.current_resource.architecture.should == @new_resource.architecture - end - - it "should set the recursive flag of the current resource to the recursive flag of the new resource" do - @provider.current_resource.recursive.should == @new_resource.recursive - end - - it "should set the unscrubbed values of the current resource to the values it got from the registry" do - @provider.current_resource.unscrubbed_values.should == [ testval2 ] - end - end - - describe "when the key does not exist" do - before(:each) do - @double_registry.should_receive(:key_exists?).with(keyname).and_return(false) - @provider.load_current_resource - end - - it "should set the values in the current resource to empty array" do - @provider.current_resource.values.should == [] - end - end - end - - describe "action_create" do - context "when the key exists" do - before(:each) do - @double_registry.should_receive(:key_exists?).twice.with(keyname).and_return(true) - end - it "should do nothing if the key and the value both exist" do - @double_registry.should_receive(:get_values).with(keyname).and_return( testval1 ) - @double_registry.should_not_receive(:set_value) - @provider.load_current_resource - @provider.action_create - end - it "should create the value if the key exists but the value does not" do - @double_registry.should_receive(:get_values).with(keyname).and_return( testval2 ) - @double_registry.should_receive(:set_value).with(keyname, testval1) - @provider.load_current_resource - @provider.action_create - end - it "should set the value if the key exists but the data does not match" do - @double_registry.should_receive(:get_values).with(keyname).and_return( testval1_wrong_data ) - @double_registry.should_receive(:set_value).with(keyname, testval1) - @provider.load_current_resource - @provider.action_create - end - it "should set the value if the key exists but the type does not match" do - @double_registry.should_receive(:get_values).with(keyname).and_return( testval1_wrong_type ) - @double_registry.should_receive(:set_value).with(keyname, testval1) - @provider.load_current_resource - @provider.action_create - end - end - context "when the key exists and the values in the new resource are empty" do - it "when a value is in the key, it should do nothing" do - @provider.new_resource.values([]) - @double_registry.should_receive(:key_exists?).twice.with(keyname).and_return(true) - @double_registry.should_receive(:get_values).with(keyname).and_return( testval1 ) - @double_registry.should_not_receive(:create_key) - @double_registry.should_not_receive(:set_value) - @provider.load_current_resource - @provider.action_create - end - it "when no value is in the key, it should do nothing" do - @provider.new_resource.values([]) - @double_registry.should_receive(:key_exists?).twice.with(keyname).and_return(true) - @double_registry.should_receive(:get_values).with(keyname).and_return( nil ) - @double_registry.should_not_receive(:create_key) - @double_registry.should_not_receive(:set_value) - @provider.load_current_resource - @provider.action_create - end - end - context "when the key does not exist" do - before(:each) do - @double_registry.should_receive(:key_exists?).twice.with(keyname).and_return(false) - end - it "should create the key and the value" do - @double_registry.should_receive(:create_key).with(keyname, false) - @double_registry.should_receive(:set_value).with(keyname, testval1) - @provider.load_current_resource - @provider.action_create - end - end - context "when the key does not exist and the values in the new resource are empty" do - it "should create the key" do - @new_resource.values([]) - @double_registry.should_receive(:key_exists?).twice.with(keyname).and_return(false) - @double_registry.should_receive(:create_key).with(keyname, false) - @double_registry.should_not_receive(:set_value) - @provider.load_current_resource - @provider.action_create - end - end - end - - describe "action_create_if_missing" do - context "when the key exists" do - before(:each) do - @double_registry.should_receive(:key_exists?).twice.with(keyname).and_return(true) - end - it "should do nothing if the key and the value both exist" do - @double_registry.should_receive(:get_values).with(keyname).and_return( testval1 ) - @double_registry.should_not_receive(:set_value) - @provider.load_current_resource - @provider.action_create_if_missing - end - it "should create the value if the key exists but the value does not" do - @double_registry.should_receive(:get_values).with(keyname).and_return( testval2 ) - @double_registry.should_receive(:set_value).with(keyname, testval1) - @provider.load_current_resource - @provider.action_create_if_missing - end - it "should not set the value if the key exists but the data does not match" do - @double_registry.should_receive(:get_values).with(keyname).and_return( testval1_wrong_data ) - @double_registry.should_not_receive(:set_value) - @provider.load_current_resource - @provider.action_create_if_missing - end - it "should not set the value if the key exists but the type does not match" do - @double_registry.should_receive(:get_values).with(keyname).and_return( testval1_wrong_type ) - @double_registry.should_not_receive(:set_value) - @provider.load_current_resource - @provider.action_create_if_missing - end - end - context "when the key does not exist" do - before(:each) do - @double_registry.should_receive(:key_exists?).twice.with(keyname).and_return(false) - end - it "should create the key and the value" do - @double_registry.should_receive(:create_key).with(keyname, false) - @double_registry.should_receive(:set_value).with(keyname, testval1) - @provider.load_current_resource - @provider.action_create_if_missing - end - end - end - - describe "action_delete" do - context "when the key exists" do - before(:each) do - @double_registry.should_receive(:key_exists?).twice.with(keyname).and_return(true) - end - it "deletes the value when the value exists" do - @double_registry.should_receive(:get_values).with(keyname).and_return( testval1 ) - @double_registry.should_receive(:delete_value).with(keyname, testval1) - @provider.load_current_resource - @provider.action_delete - end - it "deletes the value when the value exists, but the type is wrong" do - @double_registry.should_receive(:get_values).with(keyname).and_return( testval1_wrong_type ) - @double_registry.should_receive(:delete_value).with(keyname, testval1) - @provider.load_current_resource - @provider.action_delete - end - it "deletes the value when the value exists, but the data is wrong" do - @double_registry.should_receive(:get_values).with(keyname).and_return( testval1_wrong_data ) - @double_registry.should_receive(:delete_value).with(keyname, testval1) - @provider.load_current_resource - @provider.action_delete - end - it "does not delete the value when the value does not exist" do - @double_registry.should_receive(:get_values).with(keyname).and_return( testval2 ) - @double_registry.should_not_receive(:delete_value) - @provider.load_current_resource - @provider.action_delete - end - end - context "when the key does not exist" do - before(:each) do - @double_registry.should_receive(:key_exists?).twice.with(keyname).and_return(false) - end - it "does nothing" do - @double_registry.should_not_receive(:delete_value) - @provider.load_current_resource - @provider.action_delete - end - end - end - - describe "action_delete_key" do - context "when the key exists" do - before(:each) do - @double_registry.should_receive(:key_exists?).twice.with(keyname).and_return(true) - end - it "deletes the key" do - @double_registry.should_receive(:get_values).with(keyname).and_return( testval1 ) - @double_registry.should_receive(:delete_key).with(keyname, false) - @provider.load_current_resource - @provider.action_delete_key - end - end - context "when the key does not exist" do - before(:each) do - @double_registry.should_receive(:key_exists?).twice.with(keyname).and_return(false) - end - it "does nothing" do - @double_registry.should_not_receive(:delete_key) - @provider.load_current_resource - @provider.action_delete_key - end - end - end - -end - -describe Chef::Provider::RegistryKey do - context "when the key data is safe" do - let(:keyname) { 'HKLM\Software\Opscode\Testing\Safe' } - let(:testval1) { { :name => "one", :type => :string, :data => "1" } } - let(:testval1_wrong_type) { { :name => "one", :type => :multi_string, :data => "1" } } - let(:testval1_wrong_data) { { :name => "one", :type => :string, :data => "2" } } - let(:testval2) { { :name => "two", :type => :string, :data => "2" } } - - it_should_behave_like "a registry key" - end - - context "when the key data is unsafe" do - let(:keyname) { 'HKLM\Software\Opscode\Testing\Unsafe' } - let(:testval1) { { :name => "one", :type => :binary, :data => 255.chr * 1 } } - let(:testval1_wrong_type) { { :name => "one", :type => :string, :data => 255.chr * 1 } } - let(:testval1_wrong_data) { { :name => "one", :type => :binary, :data => 254.chr * 1 } } - let(:testval2) { { :name => "two", :type => :binary, :data => 0.chr * 1 } } - - it_should_behave_like "a registry key" - end -end diff --git a/spec/unit/provider/remote_directory_spec.rb b/spec/unit/provider/remote_directory_spec.rb deleted file mode 100644 index b986e2c8ad..0000000000 --- a/spec/unit/provider/remote_directory_spec.rb +++ /dev/null @@ -1,222 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@kallistec.com>) -# Copyright:: Copyright (c) 2010 Daniel DeLeo -# 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 'digest/md5' -require 'tmpdir' -require 'chef/mixin/file_class' - -class Chef::CFCCheck - include Chef::Mixin::FileClass -end - -describe Chef::Provider::RemoteDirectory do - before do - Chef::FileAccessControl.any_instance.stub(:set_all) - - @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') - - @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) - - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events) - - @provider = Chef::Provider::RemoteDirectory.new(@resource, @run_context) - @provider.current_resource = @resource.clone - end - - describe "when the contents of the directory changed on the first run and not on the second run" do - before do - @resource_second_run = @resource.clone - @provider_second_run = Chef::Provider::RemoteDirectory.new(@resource_second_run, @run_context) - @provider.run_action(:create) - @provider_second_run.run_action(:create) - end - it "identifies that the state has changed the after first run" do - @provider_second_run.new_resource.updated_by_last_action? == true - end - it "identifies that the state has not changed after the second run" do - @provider_second_run.new_resource.updated_by_last_action? == false - end - end - - describe "when access control is configured on the resource" do - before do - @resource.mode "0750" - @resource.group "wheel" - @resource.owner "root" - - @resource.files_mode "0640" - @resource.files_group "staff" - @resource.files_owner "toor" - @resource.files_backup 23 - - @resource.source "remotedir_root" - end - - it "configures access control on intermediate directorys" do - directory_resource = @provider.send(:resource_for_directory, File.join(Dir.tmpdir, "intermediate_dir")) - directory_resource.path.should == File.join(Dir.tmpdir, "intermediate_dir") - directory_resource.mode.should == "0750" - directory_resource.group.should == "wheel" - directory_resource.owner.should == "root" - directory_resource.recursive.should be_true - end - - it "configures access control on files in the directory" do - @resource.cookbook "berlin_style_tasty_cupcakes" - cookbook_file = @provider.send(:cookbook_file_resource, - "/target/destination/path.txt", - "relative/source/path.txt") - cookbook_file.cookbook_name.should == "berlin_style_tasty_cupcakes" - cookbook_file.source.should == "remotedir_root/relative/source/path.txt" - cookbook_file.mode.should == "0640" - cookbook_file.group.should == "staff" - cookbook_file.owner.should == "toor" - cookbook_file.backup.should == 23 - end - end - - describe "when creating the remote directory" do - before do - @node.automatic_attrs[:platform] = :just_testing - @node.automatic_attrs[:platform_version] = :just_testing - - @destination_dir = Dir.mktmpdir << "/remote_directory_test" - @resource.path(@destination_dir) - end - - after {FileUtils.rm_rf(@destination_dir)} - - # CHEF-3552 - it "creates the toplevel directory without error " do - @resource.recursive(false) - @provider.run_action(:create) - ::File.exist?(@destination_dir).should be_true - end - - it "transfers the directory with all contents" do - @provider.run_action(:create) - ::File.exist?(@destination_dir + '/remote_dir_file1.txt').should be_true - ::File.exist?(@destination_dir + '/remote_dir_file2.txt').should be_true - ::File.exist?(@destination_dir + '/remotesubdir/remote_subdir_file1.txt').should be_true - ::File.exist?(@destination_dir + '/remotesubdir/remote_subdir_file2.txt').should be_true - ::File.exist?(@destination_dir + '/remotesubdir/.a_dotfile').should be_true - ::File.exist?(@destination_dir + '/.a_dotdir/.a_dotfile_in_a_dotdir').should be_true - end - - describe "only if it is missing" do - it "should not overwrite existing files" 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')) - - @provider.run_action(:create_if_missing) - - file1md5.eql?(Digest::MD5.hexdigest(File.read(@destination_dir + '/remote_dir_file1.txt'))).should be_true - subdirfile1md5.eql?(Digest::MD5.hexdigest(File.read(@destination_dir + '/remotesubdir/remote_subdir_file1.txt'))).should be_true - end - end - - describe "with purging enabled" do - 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') - @provider.run_action(:create) - - ::File.exist?(@destination_dir + '/remote_dir_file1.txt').should be_true - ::File.exist?(@destination_dir + '/remote_dir_file2.txt').should be_true - ::File.exist?(@destination_dir + '/remotesubdir/remote_subdir_file1.txt').should be_true - ::File.exist?(@destination_dir + '/remotesubdir/remote_subdir_file2.txt').should be_true - - ::File.exist?(@destination_dir + '/marked_for_death.txt').should be_false - ::File.exist?(@destination_dir + '/remotesubdir/marked_for_death_again.txt').should be_false - 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') - @provider.run_action(:create) - ::File.exist?(@destination_dir + '/a/foo.txt').should be_false - ::File.exist?(@destination_dir + '/a/multiply/bar.txt').should be_false - ::File.exist?(@destination_dir + '/a/multiply/nested/baz.txt').should be_false - ::File.exist?(@destination_dir + '/a/multiply/nested/directory/qux.txt').should be_false - end - - it "removes directory symlinks properly", :not_supported_on_win2k3 do - symlinked_dir_path = @destination_dir + '/symlinked_dir' - @provider.action = :create - @provider.run_action - - @fclass = Chef::CFCCheck.new - - Dir.mktmpdir do |tmp_dir| - begin - @fclass.file_class.symlink(tmp_dir.dup, symlinked_dir_path) - ::File.exist?(symlinked_dir_path).should be_true - - @provider.run_action - - ::File.exist?(symlinked_dir_path).should be_false - ::File.exist?(tmp_dir).should be_true - rescue Chef::Exceptions::Win32APIError => e - pending "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)} - - 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')) - @provider.run_action(:create) - file1md5.eql?(Digest::MD5.hexdigest(::File.read(@destination_dir + '/remote_dir_file1.txt'))).should be_true - subdirfile1md5.eql?(Digest::MD5.hexdigest(::File.read(@destination_dir + '/remotesubdir/remote_subdir_file1.txt'))).should be_true - 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 deleted file mode 100644 index 8e396b1b40..0000000000 --- a/spec/unit/provider/remote_file/cache_control_data_spec.rb +++ /dev/null @@ -1,220 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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' -require 'uri' - -CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH = 64 -CACHE_FILE_MD5_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_JSON_FILE_EXTENSION_LENGTH # {friendly}-{md5hex}.json == 102 - -describe Chef::Provider::RemoteFile::CacheControlData do - - let(:uri) { URI.parse("http://www.google.com/robots.txt") } - - subject(:cache_control_data) 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" } - - # the checksum of the file we have on disk already - let(:current_file_checksum) { "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" } - - context "when loading data for an unknown URI" do - - before do - Chef::FileCache.should_receive(:load).with(cache_path).and_raise(Chef::Exceptions::FileNotFound, "nope") - end - - context "and there is no current copy of the file" do - let(:current_file_checksum) { nil } - - it "returns empty cache control data" do - cache_control_data.etag.should be_nil - cache_control_data.mtime.should be_nil - end - end - - it "returns empty cache control data" do - cache_control_data.etag.should be_nil - cache_control_data.mtime.should be_nil - end - - 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" } - - 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) - end - end - end - - describe "when loading data for a known URI" do - - # the checksum of the file last we fetched it. - let(:last_fetched_checksum) { "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" } - - let(:etag) { "\"a-strong-identifier\"" } - let(:mtime) { "Tue, 21 May 2013 19:19:23 GMT" } - - let(:cache_json_data) do - cache = {} - cache["etag"] = etag - cache["mtime"] = mtime - cache["checksum"] = last_fetched_checksum - cache.to_json - end - - before do - Chef::FileCache.should_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 - cache_control_data.etag.should be_nil - cache_control_data.mtime.should be_nil - end - end - - context "and the cached checksum does not match the on-disk copy" do - let(:current_file_checksum) { "e2a8938cc31754f6c067b35aab1d0d4864272e9bf8504536ef3e79ebf8432305" } - - it "returns empty cache control data" do - cache_control_data.etag.should be_nil - cache_control_data.mtime.should be_nil - end - end - - context "and the cached checksum matches the on-disk copy" do - - it "populates the cache control data" do - cache_control_data.etag.should == etag - cache_control_data.mtime.should == mtime - end - end - - context "and the cached checksum data is corrupted" do - let(:cache_json_data) { '{"foo",,"bar" []}' } - - it "returns empty cache control data" do - cache_control_data.etag.should be_nil - cache_control_data.mtime.should be_nil - end - - context "and it still is valid JSON" do - let(:cache_json_data) { '' } - - it "returns empty cache control data" do - cache_control_data.etag.should be_nil - cache_control_data.mtime.should be_nil - end - end - end - end - - describe "when saving to disk" do - - let(:etag) { "\"a-strong-identifier\"" } - let(:mtime) { "Tue, 21 May 2013 19:19:23 GMT" } - let(:fetched_file_checksum) { "e2a8938cc31754f6c067b35aab1d0d4864272e9bf8504536ef3e79ebf8432305" } - - let(:expected_serialization_data) do - data = {} - data["etag"] = etag - data["mtime"] = mtime - data["checksum"] = fetched_file_checksum - data - end - - before do - cache_control_data.etag = etag - cache_control_data.mtime = mtime - cache_control_data.checksum = fetched_file_checksum - end - - it "serializes its attributes to JSON" do - # we have to test this separately because ruby 1.8 hash order is unstable - # so we can't count on the order of the keys in the json format. - - json_data = cache_control_data.json_data - Chef::JSONCompat.from_json(json_data).should == expected_serialization_data - end - - it "writes data to the cache" do - json_data = cache_control_data.json_data - Chef::FileCache.should_receive(:store).with(cache_path, json_data) - cache_control_data.save - end - - 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" } - - it "writes the data to the cache with a sanitized path name" do - json_data = cache_control_data.json_data - Chef::FileCache.should_receive(:store).with(cache_path, json_data) - cache_control_data.save - end - end - - # Cover the very long remote file path case -- see CHEF-4422 where - # local cache file names generated from the long uri exceeded - # 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(: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] - end - - it "truncates the file cache path to 102 characters" do - normalized_cache_path = cache_control_data.send('sanitized_cache_file_basename') - - Chef::FileCache.should_receive(:store).with("remote_file/" + normalized_cache_path, cache_control_data.json_data) - - cache_control_data.save - - normalized_cache_path.length.should == CACHE_FILE_PATH_LIMIT - 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') - - truncated_file_cache_path.length.should == CACHE_FILE_TRUNCATED_FRIENDLY_FILE_NAME_LENGTH - normalized_cache_path.start_with?(truncated_file_cache_path).should == true - end - end - - end - -end - diff --git a/spec/unit/provider/remote_file/content_spec.rb b/spec/unit/provider/remote_file/content_spec.rb deleted file mode 100644 index 4ee33aeefb..0000000000 --- a/spec/unit/provider/remote_file/content_spec.rb +++ /dev/null @@ -1,253 +0,0 @@ -# -# Author:: Lamont Granquist (<lamont@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::RemoteFile::Content do - - # - # mock setup - # - - let(:current_resource) do - Chef::Resource::RemoteFile.new("remote-file-content-spec (current resource)") - end - - let(:source) { [ "http://opscode.com/seattle.txt" ] } - - let(:new_resource) do - r = Chef::Resource::RemoteFile.new("remote-file-content-spec (current resource)") - r.source(source) - r - end - - let(:run_context) { double("Chef::RunContext") } - - # - # subject - # - let(:content) do - Chef::Provider::RemoteFile::Content.new(new_resource, current_resource, run_context) - end - - describe "when the checksum of the current_resource matches the checksum set on the resource" do - before do - new_resource.stub(:checksum).and_return("0fd012fdc96e96f8f7cf2046522a54aed0ce470224513e45da6bc1a17a4924aa") - current_resource.stub(:checksum).and_return("0fd012fdc96e96f8f7cf2046522a54aed0ce470224513e45da6bc1a17a4924aa") - end - - it "should return nil for the tempfile" do - content.tempfile.should be_nil - end - - it "should not call any fetcher" do - Chef::Provider::RemoteFile::Fetcher.should_not_receive(:for_resource) - end - end - - describe "when the checksum of the current_resource is a partial match for the checksum set on the resource" do - before do - new_resource.stub(:checksum).and_return("0fd012fd") - current_resource.stub(:checksum).and_return("0fd012fdc96e96f8f7cf2046522a54aed0ce470224513e45da6bc1a17a4924aa") - end - - it "should return nil for the tempfile" do - content.tempfile.should be_nil - end - - it "should not call any fetcher" do - Chef::Provider::RemoteFile::Fetcher.should_not_receive(:for_resource) - end - end - - shared_examples_for "the resource needs fetching" do - before do - # FIXME: test one or the other nil, test both not nil and not equal, abuse the regexp a little - @uri = double("URI") - URI.should_receive(:parse).with(new_resource.source[0]).and_return(@uri) - end - - describe "when the fetcher returns nil for the tempfile" do - before do - http_fetcher = double("Chef::Provider::RemoteFile::HTTP", :fetch => nil) - Chef::Provider::RemoteFile::Fetcher.should_receive(:for_resource).with(@uri, new_resource, current_resource).and_return(http_fetcher) - end - - it "should return nil for the tempfile" do - content.tempfile.should be_nil - end - end - - describe "when the fetcher returns a valid tempfile" do - - let(:mtime) { Time.now } - let(:tempfile) { double("Tempfile") } - let(:http_fetcher) { double("Chef::Provider::RemoteFile::HTTP", :fetch => tempfile) } - - before do - Chef::Provider::RemoteFile::Fetcher.should_receive(:for_resource).with(@uri, new_resource, current_resource).and_return(http_fetcher) - end - - it "should return the tempfile object to the caller" do - content.tempfile.should == tempfile - end - - end - end - describe "when the checksum are both nil" do - before do - new_resource.checksum.should be_nil - current_resource.checksum.should be_nil - end - it_behaves_like "the resource needs fetching" - end - - describe "when the current_resource checksum is nil" do - before do - new_resource.stub(:checksum).and_return("fd012fd") - current_resource.stub(:checksum).and_return(nil) - end - it_behaves_like "the resource needs fetching" - end - - describe "when the new_resource checksum is nil" do - before do - new_resource.stub(:checksum).and_return(nil) - current_resource.stub(:checksum).and_return("0fd012fdc96e96f8f7cf2046522a54aed0ce470224513e45da6bc1a17a4924aa") - end - it_behaves_like "the resource needs fetching" - end - - describe "when the checksums are a partial match, but not to the leading portion" do - before do - new_resource.stub(:checksum).and_return("fd012fd") - current_resource.stub(:checksum).and_return("0fd012fdc96e96f8f7cf2046522a54aed0ce470224513e45da6bc1a17a4924aa") - end - it_behaves_like "the resource needs fetching" - end - - - describe "when the fetcher throws an exception" do - before do - new_resource.stub(:checksum).and_return(nil) - current_resource.stub(:checksum).and_return(nil) - @uri = double("URI") - URI.should_receive(:parse).with(new_resource.source[0]).and_return(@uri) - http_fetcher = double("Chef::Provider::RemoteFile::HTTP") - http_fetcher.should_receive(:fetch).and_raise(Errno::ECONNREFUSED) - Chef::Provider::RemoteFile::Fetcher.should_receive(:for_resource).with(@uri, new_resource, current_resource).and_return(http_fetcher) - end - - it "should propagate the error back to the caller" do - lambda { content.tempfile }.should raise_error(Errno::ECONNREFUSED) - end - end - - describe "when there is an array of sources and the first fails" 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}) - else - exception_class.new - end - end - - let(:source) { [ "http://opscode.com/seattle.txt", "http://opscode.com/nyc.txt" ] } - - ### Test each exception we care about and make sure they all behave properly - [ - SocketError, - Errno::ECONNREFUSED, - Errno::ENOENT, - Errno::EACCES, - Timeout::Error, - Net::HTTPServerException, - Net::HTTPFatalError, - Net::FTPError - ].each do |exception| - describe "with an exception of #{exception}" do - before do - new_resource.stub(:checksum).and_return(nil) - current_resource.stub(:checksum).and_return(nil) - @uri0 = double("URI0") - @uri1 = double("URI1") - URI.should_receive(:parse).with(new_resource.source[0]).and_return(@uri0) - URI.should_receive(:parse).with(new_resource.source[1]).and_return(@uri1) - @http_fetcher_throws_exception = double("Chef::Provider::RemoteFile::HTTP") - @http_fetcher_throws_exception.should_receive(:fetch).at_least(:once).and_raise(create_exception(exception)) - Chef::Provider::RemoteFile::Fetcher.should_receive(:for_resource).with(@uri0, new_resource, current_resource).and_return(@http_fetcher_throws_exception) - end - - describe "the second url should succeed" do - before do - @tempfile = double("Tempfile") - mtime = Time.now - http_fetcher_works = double("Chef::Provider::RemoteFile::HTTP", :fetch => @tempfile) - Chef::Provider::RemoteFile::Fetcher.should_receive(:for_resource).with(@uri1, new_resource, current_resource).and_return(http_fetcher_works) - end - - it "should return a valid tempfile" do - content.tempfile.should == @tempfile - end - - it "should not mutate the new_resource" do - content.tempfile - new_resource.source.length.should == 2 - end - end - - describe "when both urls fail" do - before do - Chef::Provider::RemoteFile::Fetcher.should_receive(:for_resource).with(@uri1, new_resource, current_resource).and_return(@http_fetcher_throws_exception) - end - - it "should propagate the error back to the caller" do - lambda { content.tempfile }.should raise_error(exception) - end - end - end - end - end - - describe "when there is an array of sources and the first succeeds" do - let(:source) { [ "http://opscode.com/seattle.txt", "http://opscode.com/nyc.txt" ] } - before do - new_resource.stub(:checksum).and_return(nil) - current_resource.stub(:checksum).and_return(nil) - @uri0 = double("URI0") - URI.should_receive(:parse).with(new_resource.source[0]).and_return(@uri0) - URI.should_not_receive(:parse).with(new_resource.source[1]) - @tempfile = double("Tempfile") - mtime = Time.now - http_fetcher_works = double("Chef::Provider::RemoteFile::HTTP", :fetch => @tempfile) - Chef::Provider::RemoteFile::Fetcher.should_receive(:for_resource).with(@uri0, new_resource, current_resource).and_return(http_fetcher_works) - end - - it "should return a valid tempfile" do - content.tempfile.should == @tempfile - end - - it "should not mutate the new_resource" do - content.tempfile - new_resource.source.length.should == 2 - end - end - -end diff --git a/spec/unit/provider/remote_file/fetcher_spec.rb b/spec/unit/provider/remote_file/fetcher_spec.rb deleted file mode 100644 index b5594b50e6..0000000000 --- a/spec/unit/provider/remote_file/fetcher_spec.rb +++ /dev/null @@ -1,75 +0,0 @@ -# -# Author:: Lamont Granquist (<lamont@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::RemoteFile::Fetcher do - - let(:current_resource) { double("current resource") } - let(:new_resource) { double("new resource") } - let(:fetcher_instance) { double("fetcher") } - - describe "when passed an http url" do - let(:uri) { double("uri", :scheme => "http" ) } - before do - Chef::Provider::RemoteFile::HTTP.should_receive(:new).and_return(fetcher_instance) - end - it "returns an http fetcher" do - described_class.for_resource(uri, new_resource, current_resource).should == fetcher_instance - end - end - - describe "when passed an https url" do - let(:uri) { double("uri", :scheme => "https" ) } - before do - Chef::Provider::RemoteFile::HTTP.should_receive(:new).and_return(fetcher_instance) - end - it "returns an http fetcher" do - described_class.for_resource(uri, new_resource, current_resource).should == fetcher_instance - end - end - - describe "when passed an ftp url" do - let(:uri) { double("uri", :scheme => "ftp" ) } - before do - Chef::Provider::RemoteFile::FTP.should_receive(:new).and_return(fetcher_instance) - end - it "returns an ftp fetcher" do - described_class.for_resource(uri, new_resource, current_resource).should == fetcher_instance - end - end - - describe "when passed a file url" do - let(:uri) { double("uri", :scheme => "file" ) } - before do - Chef::Provider::RemoteFile::LocalFile.should_receive(:new).and_return(fetcher_instance) - end - it "returns a localfile fetcher" do - described_class.for_resource(uri, new_resource, current_resource).should == fetcher_instance - end - end - - describe "when passed a url we do not recognize" do - let(:uri) { double("uri", :scheme => "xyzzy" ) } - it "throws an ArgumentError exception" do - lambda { described_class.for_resource(uri, new_resource, current_resource) }.should raise_error(ArgumentError) - end - end - -end - diff --git a/spec/unit/provider/remote_file/ftp_spec.rb b/spec/unit/provider/remote_file/ftp_spec.rb deleted file mode 100644 index b393912ef9..0000000000 --- a/spec/unit/provider/remote_file/ftp_spec.rb +++ /dev/null @@ -1,219 +0,0 @@ -# -# Author:: Jesse Campbell (<hikeit@gmail.com>) -# Copyright:: Copyright (c) 2013 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 'spec_helper' - -describe Chef::Provider::RemoteFile::FTP do - let(:enclosing_directory) { - canonicalize_path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates"))) - } - let(:resource_path) { - canonicalize_path(File.expand_path(File.join(enclosing_directory, "seattle.txt"))) - } - - let(:new_resource) do - r = Chef::Resource::RemoteFile.new("remote file ftp backend test (new resource)") - r.ftp_active_mode(false) - r.path(resource_path) - r - end - - let(:current_resource) do - Chef::Resource::RemoteFile.new("remote file ftp backend test (current resource)'") - end - - let(:ftp) do - ftp = double(Net::FTP, { }) - ftp.stub(:connect) - ftp.stub(:login) - ftp.stub(:voidcmd) - ftp.stub(:mtime).and_return(Time.now) - ftp.stub(:getbinaryfile) - ftp.stub(:close) - ftp.stub(:passive=) - ftp - end - - let(:tempfile_path) { "/tmp/somedir/remote-file-ftp-backend-spec-test" } - - let(:tempfile) do - t = StringIO.new - t.stub(:path).and_return(tempfile_path) - t - end - - let(:uri) { URI.parse("ftp://opscode.com/seattle.txt") } - - before(:each) do - Net::FTP.stub(:new).with().and_return(ftp) - Tempfile.stub(:new).and_return(tempfile) - end - - describe "when first created" do - - it "throws an argument exception when no path is given" do - uri.path = "" - lambda { Chef::Provider::RemoteFile::FTP.new(uri, new_resource, current_resource) }.should raise_error(ArgumentError) - end - - it "throws an argument exception when only a / is given" do - uri.path = "/" - lambda { Chef::Provider::RemoteFile::FTP.new(uri, new_resource, current_resource) }.should raise_error(ArgumentError) - end - - it "throws an argument exception when no filename is given" do - uri.path = "/the/whole/path/" - lambda { Chef::Provider::RemoteFile::FTP.new(uri, new_resource, current_resource) }.should raise_error(ArgumentError) - end - - it "throws an argument exception when the typecode is invalid" do - uri.typecode = "d" - lambda { Chef::Provider::RemoteFile::FTP.new(uri, new_resource, current_resource) }.should raise_error(ArgumentError) - end - - it "does not use passive mode when new_resource sets ftp_active_mode to true" do - new_resource.ftp_active_mode(true) - fetcher = Chef::Provider::RemoteFile::FTP.new(uri, new_resource, current_resource) - fetcher.use_passive_mode?.should be_false - end - - it "uses passive mode when new_resource sets ftp_active_mode to false" do - new_resource.ftp_active_mode(false) - fetcher = Chef::Provider::RemoteFile::FTP.new(uri, new_resource, current_resource) - fetcher.use_passive_mode?.should be_true - end - end - - describe "when fetching the object" do - - let(:cache_control_data) { Chef::Provider::RemoteFile::CacheControlData.new(uri) } - let(:current_resource_checksum) { "e2a8938cc31754f6c067b35aab1d0d4864272e9bf8504536ef3e79ebf8432305" } - - subject(:fetcher) { Chef::Provider::RemoteFile::FTP.new(uri, new_resource, current_resource) } - - before do - current_resource.checksum(current_resource_checksum) - #Chef::Provider::RemoteFile::CacheControlData.should_receive(:load_and_validate).with(uri, current_resource_checksum).and_return(cache_control_data) - end - - it "should connect to the host from the uri on the default port 21" do - ftp.should_receive(:connect).with("opscode.com", 21) - fetcher.fetch - end - - it "should set passive true when ftp_active_mode is false" do - new_resource.ftp_active_mode(false) - ftp.should_receive(:passive=).with(true) - fetcher.fetch - end - - it "should set passive false when ftp_active_mode is false" do - new_resource.ftp_active_mode(true) - ftp.should_receive(:passive=).with(false) - fetcher.fetch - end - - it "should use anonymous ftp when no userinfo is provided" do - ftp.should_receive(:login).with("anonymous", nil) - fetcher.fetch - end - - context "and the URI specifies an alternate port" do - let(:uri) { URI.parse("ftp://opscode.com:8021/seattle.txt") } - - it "should connect on an alternate port when one is provided" do - uri = URI.parse("ftp://opscode.com:8021/seattle.txt") - ftp.should_receive(:connect).with("opscode.com", 8021) - fetcher.fetch - end - - end - - context "and the URI contains a username and password" do - let(:uri) { URI.parse("ftp://the_user:the_password@opscode.com/seattle.txt") } - - it "should use authenticated ftp when userinfo is provided" do - ftp.should_receive(:login).with("the_user", "the_password") - fetcher.fetch - end - end - - context "and the uri sets the typecode to ascii" do - let(:uri) { URI.parse("ftp://the_user:the_password@opscode.com/seattle.txt;type=a") } - - it "fetches the file with ascii typecode set" do - ftp.should_receive(:voidcmd).with("TYPE A").once - fetcher.fetch - end - - end - - context "and the uri sets the typecode to image" do - let(:uri) { URI.parse("ftp://the_user:the_password@opscode.com/seattle.txt;type=i") } - - it "should accept image for the typecode" do - ftp.should_receive(:voidcmd).with("TYPE I").once - fetcher.fetch - end - - end - - context "and the uri specifies a nested path" do - let(:uri) { URI.parse("ftp://opscode.com/the/whole/path/seattle.txt") } - - it "should fetch the file from the correct path" do - ftp.should_receive(:voidcmd).with("CWD the").once - ftp.should_receive(:voidcmd).with("CWD whole").once - ftp.should_receive(:voidcmd).with("CWD path").once - ftp.should_receive(:getbinaryfile).with("seattle.txt", tempfile.path) - fetcher.fetch - end - - end - - context "when not using last modified based conditional fetching" do - before do - new_resource.use_last_modified(false) - end - - it "should return a tempfile in the result" do - result = fetcher.fetch - result.should equal(tempfile) - end - - end - - context "and proxying is enabled" do - before do - Chef::Config[:ftp_proxy] = "socks5://socks.example.com:5000" - Chef::Config[:ftp_proxy_user] = "bill" - Chef::Config[:ftp_proxy_pass] = "ted" - end - - it "fetches the file via the proxy" do - current_socks_server = ENV["SOCKS_SERVER"] - ENV.should_receive(:[]=).with("SOCKS_SERVER", "socks5://bill:ted@socks.example.com:5000").ordered - ENV.should_receive(:[]=).with("SOCKS_SERVER", current_socks_server).ordered - result = fetcher.fetch - result.should equal(tempfile) - end - - end - - end -end diff --git a/spec/unit/provider/remote_file/http_spec.rb b/spec/unit/provider/remote_file/http_spec.rb deleted file mode 100644 index 951d9f0a05..0000000000 --- a/spec/unit/provider/remote_file/http_spec.rb +++ /dev/null @@ -1,303 +0,0 @@ -# -# Author:: Lamont Granquist (<lamont@opscode.com>) -# Copyright:: Copyright (c) 2013 Lamont Granquist -# 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::HTTP do - - let(:uri) { URI.parse("http://opscode.com/seattle.txt") } - - let(:existing_file_source) { nil } - - let(:current_resource_checksum) { "41e78735319af11327e9d2ca8535ea1c191e5ac1f76bb08d88fe6c3f93a8c8e5" } - - let(:current_resource) do - current_resource = Chef::Resource::RemoteFile.new("/tmp/foo.txt") - current_resource.source(existing_file_source) if existing_file_source - current_resource.checksum(current_resource_checksum) - current_resource - end - - let(:new_resource) do - Chef::Resource::RemoteFile.new("/tmp/foo.txt") - end - - subject(:fetcher) do - Chef::Provider::RemoteFile::HTTP.new(uri, new_resource, current_resource) - end - - let(:cache_control_data) { Chef::Provider::RemoteFile::CacheControlData.new(uri) } - - describe "generating cache control headers" do - - context "and there is no valid cache control data for this URI on disk" do - - before do - Chef::Provider::RemoteFile::CacheControlData.should_receive(:load_and_validate).with(uri, current_resource_checksum).and_return(cache_control_data) - end - - it "does not add conditional GET headers" do - fetcher.conditional_get_headers.should == {} - end - - context "and the resource specifies custom headers" do - before do - new_resource.headers("x-myapp-header" => "custom-header-value") - end - - it "has the user-specified custom headers" do - fetcher.headers.should == {"x-myapp-header" => "custom-header-value"} - end - end - - end - - context "and the cache control data matches the existing file" do - - # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26 - let(:etag) { "\"a-strong-unique-identifier\"" } - - # http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3 - let(:mtime) { "Tue, 21 May 2013 19:19:23 GMT" } - - before do - cache_control_data.etag = etag - cache_control_data.mtime = mtime - - Chef::Provider::RemoteFile::CacheControlData.should_receive(:load_and_validate).with(uri, current_resource_checksum).and_return(cache_control_data) - end - - context "and no conditional get features are enabled" do - before do - new_resource.use_conditional_get(false) - end - - it "does not add headers to the request" do - fetcher.headers.should == {} - end - end - - context "and conditional get is enabled" do - before do - new_resource.use_conditional_get(true) - end - - it "adds If-None-Match and If-Modified-Since headers to the request" do - headers = fetcher.headers - headers["if-none-match"].should == etag - headers["if-modified-since"].should == mtime - end - - context "and custom headers are provided" do - before do - new_resource.headers("x-myapp-header" => "app-specific-header", - "if-none-match" => "custom-etag", - "if-modified-since" => "custom-last-modified") - end - - it "preserves non-conflicting headers" do - fetcher.headers["x-myapp-header"].should == "app-specific-header" - end - - it "prefers user-supplied cache control headers" do - headers = fetcher.headers - headers["if-none-match"].should == "custom-etag" - headers["if-modified-since"].should == "custom-last-modified" - end - end - - end - - context "and etag support is enabled" do - before do - new_resource.use_conditional_get(false) - new_resource.use_etags(true) - end - - it "only adds If-None-Match headers to the request" do - headers = fetcher.headers - headers["if-none-match"].should == etag - headers.should_not have_key("if-modified-since") - end - end - - context "and mtime support is enabled" do - before do - new_resource.use_conditional_get(false) - new_resource.use_last_modified(true) - end - - it "only adds If-Modified-Since headers to the request" do - headers = fetcher.headers - headers["if-modified-since"].should == mtime - headers.should_not have_key("if-none-match") - end - end - end - - end - - describe "when fetching the uri" do - - let(:expected_http_opts) { {} } - let(:expected_http_args) { [uri, expected_http_opts] } - - let(:tempfile_path) { "/tmp/chef-mock-tempfile-abc123" } - - let(:tempfile) { double(Tempfile, :path => tempfile_path, :close => nil) } - - let(:last_response) { {} } - - let(:rest) do - rest = double(Chef::HTTP::Simple) - rest.stub(:streaming_request).and_return(tempfile) - rest.stub(:last_response).and_return(last_response) - rest - end - - before do - new_resource.headers({}) - new_resource.use_last_modified(false) - Chef::Provider::RemoteFile::CacheControlData.should_receive(:load_and_validate).with(uri, current_resource_checksum).and_return(cache_control_data) - - Chef::HTTP::Simple.should_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 - # Streaming request returns nil for 304 errors - rest.stub(:streaming_request).and_return(nil) - fetcher.fetch.should be_nil - end - - end - - describe "and the request returns new content" do - - let(:fetched_content_checksum) { "e2a8938cc31754f6c067b35aab1d0d4864272e9bf8504536ef3e79ebf8432305" } - - before do - cache_control_data.should_receive(:save) - Chef::Digester.should_receive(:checksum_for_file).with(tempfile_path).and_return(fetched_content_checksum) - end - - it "should return a tempfile" do - result = fetcher.fetch - result.should == tempfile - cache_control_data.etag.should be_nil - cache_control_data.mtime.should be_nil - cache_control_data.checksum.should == fetched_content_checksum - end - - context "and the response does not contain an etag" do - let(:last_response) { {"etag" => nil} } - it "does not include an etag in the result" do - fetcher.fetch - cache_control_data.etag.should be_nil - cache_control_data.mtime.should be_nil - cache_control_data.checksum.should == fetched_content_checksum - end - end - - context "and the response has an etag header" do - let(:last_response) { {"etag" => "abc123"} } - - it "includes the etag value in the response" do - fetcher.fetch - cache_control_data.etag.should == "abc123" - cache_control_data.mtime.should be_nil - cache_control_data.checksum.should == fetched_content_checksum - end - - end - - context "and the response has no Date or Last-Modified header" do - 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. - fetcher.fetch - cache_control_data.etag.should be_nil - cache_control_data.mtime.should be_nil - cache_control_data.checksum.should == fetched_content_checksum - end - end - - 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"} - end - - it "sets the mtime to the Last-Modified time in the response" do - fetcher.fetch - cache_control_data.etag.should be_nil - cache_control_data.mtime.should == last_response["last_modified"] - end - end - - 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} - end - - it "sets the mtime to the Date in the response" do - fetcher.fetch - cache_control_data.etag.should be_nil - cache_control_data.mtime.should == last_response["date"] - cache_control_data.checksum.should == fetched_content_checksum - end - - end - - 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} } - - # CHEF-3140 - # Some servers return tarballs as content type tar and encoding gzip, which - # is totally wrong. When this happens and gzip isn't disabled, Chef::HTTP::Simple - # will decompress the file for you, which is not at all what you expected - # to happen (you end up with an uncomressed tar archive instead of the - # gzipped tar archive you expected). To work around this behavior, we - # detect when users are fetching gzipped files and turn off gzip in - # Chef::HTTP::Simple. - - it "should disable gzip compression in the client" do - # Before block in the parent context has set an expectation on - # Chef::HTTP::Simple.new() being called with expected arguments. Here we fufil - # that expectation, so that we can explicitly set it for this test. - # This is intended to provide insurance that refactoring of the parent - # context does not negate the value of this particular example. - Chef::HTTP::Simple.new(*expected_http_args) - Chef::HTTP::Simple.should_receive(:new).once.with(*expected_http_args).and_return(rest) - fetcher.fetch - cache_control_data.etag.should be_nil - cache_control_data.mtime.should be_nil - cache_control_data.checksum.should == fetched_content_checksum - end - end - end - - end - -end - diff --git a/spec/unit/provider/remote_file/local_file_spec.rb b/spec/unit/provider/remote_file/local_file_spec.rb deleted file mode 100644 index b65c917c44..0000000000 --- a/spec/unit/provider/remote_file/local_file_spec.rb +++ /dev/null @@ -1,84 +0,0 @@ -# -# Author:: Jesse Campbell (<hikeit@gmail.com>) -# Copyright:: Copyright (c) 2013 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 'spec_helper' - -describe Chef::Provider::RemoteFile::LocalFile do - - let(:uri) { URI.parse("file:///nyan_cat.png") } - - 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 - describe "when given local unix path" do - let(:uri) { URI.parse("file:///nyan_cat.png") } - it "returns a correct unix path" do - fetcher.fix_windows_path(uri.path).should == "/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 - fetcher.fix_windows_path(uri.path).should == "z:/windows/path/file.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 - fetcher.fix_windows_path(uri.path).should == "//server/share/windows/path/file.txt" - end - end - end - - context "when first created" do - - it "stores the uri it is passed" do - fetcher.uri.should == uri - end - - it "stores the new_resource" do - fetcher.new_resource.should == new_resource - end - - end - - describe "when fetching the object" do - - let(:tempfile) { double("Tempfile", :path => "/tmp/foo/bar/nyan.png", :close => nil) } - let(:chef_tempfile) { double("Chef::FileContentManagement::Tempfile", :tempfile => tempfile) } - - before do - current_resource.source("file:///nyan_cat.png") - end - - it "stages the local file to a temporary file" do - Chef::FileContentManagement::Tempfile.should_receive(:new).with(new_resource).and_return(chef_tempfile) - ::FileUtils.should_receive(:cp).with(uri.path, tempfile.path) - tempfile.should_receive(:close) - - result = fetcher.fetch - result.should == tempfile - end - - end - -end diff --git a/spec/unit/provider/remote_file_spec.rb b/spec/unit/provider/remote_file_spec.rb deleted file mode 100644 index 3fa3866743..0000000000 --- a/spec/unit/provider/remote_file_spec.rb +++ /dev/null @@ -1,63 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: Lamont Granquist (<lamont@opscode.com>) -# Copyright:: Copyright (c) 2008-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' - -require 'support/shared/unit/provider/file' - - -describe Chef::Provider::RemoteFile do - let(:resource) do - resource = Chef::Resource::RemoteFile.new("seattle", @run_context) - resource.path(resource_path) - resource.source("http://foo") - resource.cookbook_name = "monkey" - resource - end - - let(:content) do - 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(:enclosing_directory) { - canonicalize_path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates"))) - } - let(:resource_path) { - canonicalize_path(File.expand_path(File.join(enclosing_directory, "seattle.txt"))) - } - - subject(:provider) do - provider = described_class.new(resource, run_context) - provider.stub(:content).and_return(content) - provider.stub(:update_new_resource_checksum).and_return(nil) # Otherwise it doesn't behave like a File provider - provider - end - - before do - Chef::FileCache.stub(:load).with("remote_file/#{resource.name}").and_raise(Chef::Exceptions::FileNotFound) - end - - it_behaves_like Chef::Provider::File - - 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 deleted file mode 100644 index 2a6d48c79e..0000000000 --- a/spec/unit/provider/route_spec.rb +++ /dev/null @@ -1,243 +0,0 @@ -# -# Author:: Bryan McLellan (btm@loftninjas.org) -# Copyright:: Copyright (c) 2009 Bryan McLellan -# 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::Route do - before do - @node = Chef::Node.new - @cookbook_collection = Chef::CookbookCollection.new([]) - @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.gateway "10.0.0.9" - @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) - @provider.current_resource = @current_resource - end - - describe Chef::Provider::Route, "hex2ip" do - it "should return nil if ip address is invalid" do - @provider.hex2ip('foo').should be_nil # does not even look like an ip - @provider.hex2ip('ABCDEFGH').should be_nil # 8 chars, but invalid - end - - it "should return quad-dotted notation for a valid IP" do - @provider.hex2ip('01234567').should == '103.69.35.1' - @provider.hex2ip('0064a8c0').should == '192.168.100.0' - @provider.hex2ip('00FFFFFF').should == '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' - 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) - File.stub(:open).with("/proc/net/route", "r").and_return(route_file) - 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.stub(:gateway).and_return("10.0.0.1") - resource.stub(:device).and_return("eth0") - provider = Chef::Provider::Route.new(resource, @run_context) - - provider.load_current_resource - provider.is_running.should be_false - end - - it "should detect existing routes and set is_running attribute correctly" do - resource = Chef::Resource::Route.new('192.168.100.0/24') - resource.stub(:gateway).and_return("192.168.132.9") - resource.stub(:device).and_return("eth0") - provider = Chef::Provider::Route.new(resource, @run_context) - - provider.load_current_resource - provider.is_running.should be_true - end - - it "should use gateway value when matching routes" do - resource = Chef::Resource::Route.new('192.168.100.0/24') - resource.stub(:gateway).and_return("10.10.10.10") - resource.stub(:device).and_return("eth0") - provider = Chef::Provider::Route.new(resource, @run_context) - - provider.load_current_resource - provider.is_running.should be_false - end - end - end - - describe Chef::Provider::Route, "action_add" do - it "should add the route if it does not exist" do - @provider.stub(:run_command).and_return(true) - @current_resource.stub(:gateway).and_return(nil) - @provider.should_receive(:generate_command).once.with(:add) - @provider.should_receive(:generate_config) - @provider.run_action(:add) - @new_resource.should be_updated - end - - it "should not add the route if it exists" do - @provider.stub(:run_command).and_return(true) - @provider.stub(:is_running).and_return(true) - @provider.should_not_receive(:generate_command).with(:add) - @provider.should_receive(:generate_config) - @provider.run_action(:add) - @new_resource.should_not be_updated - end - - it "should not delete config file for :add action (CHEF-3332)" do - @node.automatic_attrs[:platform] = 'centos' - - route_file = StringIO.new - File.should_receive(:new).and_return(route_file) - @resource_add = Chef::Resource::Route.new('192.168.1.0/24 via 192.168.0.1') - @run_context.resource_collection << @resource_add - @provider.stub(:run_command).and_return(true) - - @resource_add.action(:add) - @provider.run_action(:add) - route_file.string.split("\n").should have(1).items - route_file.string.should match(/^192\.168\.1\.0\/24 via 192\.168\.0\.1$/) - end - end - - describe Chef::Provider::Route, "action_delete" do - it "should delete the route if it exists" do - @provider.stub(:run_command).and_return(true) - @provider.should_receive(:generate_command).once.with(:delete) - @provider.stub(:is_running).and_return(true) - @provider.run_action(:delete) - @new_resource.should be_updated - end - - it "should not delete the route if it does not exist" do - @current_resource.stub(:gateway).and_return(nil) - @provider.stub(:run_command).and_return(true) - @provider.should_not_receive(:generate_command).with(:add) - @provider.run_action(:delete) - @new_resource.should_not be_updated - end - end - - describe Chef::Provider::Route, "generate_command for action_add" do - it "should include a netmask when a one is specified" do - @new_resource.stub(:netmask).and_return('255.255.0.0') - @provider.generate_command(:add).should match(/\/\d{1,2}\s/) - end - - it "should not include a netmask when a one is specified" do - @new_resource.stub(:netmask).and_return(nil) - @provider.generate_command(:add).should_not match(/\/\d{1,2}\s/) - end - - it "should include ' via $gateway ' when a gateway is specified" do - @provider.generate_command(:add).should match(/\svia\s#{Regexp.escape(@new_resource.gateway.to_s)}\s/) - end - - it "should not include ' via $gateway ' when a gateway is not specified" do - @new_resource.stub(:gateway).and_return(nil) - @provider.generate_command(:add).should_not match(/\svia\s#{Regexp.escape(@new_resource.gateway.to_s)}\s/) - end - end - - describe Chef::Provider::Route, "generate_command for action_delete" do - it "should include a netmask when a one is specified" do - @new_resource.stub(:netmask).and_return('255.255.0.0') - @provider.generate_command(:delete).should match(/\/\d{1,2}\s/) - end - - it "should not include a netmask when a one is specified" do - @new_resource.stub(:netmask).and_return(nil) - @provider.generate_command(:delete).should_not match(/\/\d{1,2}\s/) - end - - it "should include ' via $gateway ' when a gateway is specified" do - @provider.generate_command(:delete).should match(/\svia\s#{Regexp.escape(@new_resource.gateway.to_s)}\s/) - end - - it "should not include ' via $gateway ' when a gateway is not specified" do - @new_resource.stub(:gateway).and_return(nil) - @provider.generate_command(:delete).should_not match(/\svia\s#{Regexp.escape(@new_resource.gateway.to_s)}\s/) - end - end - - describe Chef::Provider::Route, "config_file_contents for action_add" do - it "should include a netmask when a one is specified" do - @new_resource.stub(:netmask).and_return('255.255.0.0') - @provider.config_file_contents(:add, { :target => @new_resource.target, :netmask => @new_resource.netmask}).should match(/\/\d{1,2}.*\n$/) - end - - it "should not include a netmask when a one is specified" do - @provider.config_file_contents(:add, { :target => @new_resource.target}).should_not match(/\/\d{1,2}.*\n$/) - end - - it "should include ' via $gateway ' when a gateway is specified" do - @provider.config_file_contents(:add, { :target => @new_resource.target, :gateway => @new_resource.gateway}).should 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 - @provider.generate_command(:add).should_not match(/\svia\s#{Regexp.escape(@new_resource.gateway.to_s)}\n/) - end - end - - describe Chef::Provider::Route, "config_file_contents for action_delete" do - it "should return an empty string" do - @provider.config_file_contents(:delete).should match(/^$/) - end - end - - describe Chef::Provider::Route, "generate_config method" do - %w[ centos redhat fedora ].each do |platform| - it "should write a route file on #{platform} platform" do - @node.automatic_attrs[:platform] = platform - - route_file = StringIO.new - File.should_receive(:new).with("/etc/sysconfig/network-scripts/route-eth0", "w").and_return(route_file) - #Chef::Log.should_receive(:debug).with("route[10.0.0.10] writing route.eth0\n10.0.0.10 via 10.0.0.9\n") - @run_context.resource_collection << @new_resource - @provider.generate_config - end - end - - it "should put all routes for a device in a route config file" do - @node.automatic_attrs[:platform] = 'centos' - - route_file = StringIO.new - File.should_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') - - @provider.action = :add - @provider.generate_config - route_file.string.split("\n").should have(3).items - route_file.string.should match(/^192\.168\.1\.0\/24 via 192\.168\.0\.1$/) - route_file.string.should match(/^192\.168\.2\.0\/24 via 192\.168\.0\.1$/) - route_file.string.should match(/^192\.168\.3\.0\/24 via 192\.168\.0\.1$/) - end - end -end diff --git a/spec/unit/provider/ruby_block_spec.rb b/spec/unit/provider/ruby_block_spec.rb deleted file mode 100644 index 6e5c9a638b..0000000000 --- a/spec/unit/provider/ruby_block_spec.rb +++ /dev/null @@ -1,46 +0,0 @@ -# -# Author:: AJ Christensen (<aj@opscode.com>) -# Copyright:: Copyright (c) 2009 Opscode -# 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::RubyBlock, "initialize" do - before(:each) do - $evil_global_evil_laugh = :wahwah - @node = Chef::Node.new - @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} - @provider = Chef::Provider::RubyBlock.new(@new_resource, @run_context) - end - - it "should call the block and flag the resource as updated" do - @provider.run_action(:run) - $evil_global_evil_laugh.should == :mwahahaha - @new_resource.should be_updated - end - - it "accepts `create' as an alias for `run'" do - # SEE ALSO: CHEF-3500 - # "create" used to be the default action, it was renamed. - @provider.run_action(:create) - $evil_global_evil_laugh.should == :mwahahaha - @new_resource.should be_updated - end -end - diff --git a/spec/unit/provider/script_spec.rb b/spec/unit/provider/script_spec.rb deleted file mode 100644 index d072eddd04..0000000000 --- a/spec/unit/provider/script_spec.rb +++ /dev/null @@ -1,96 +0,0 @@ -# -# Author:: Adam Jacob (adam@opscode.com) -# Copyright:: Copyright (c) 2009 Opscode -# 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::Script, "action_run" do - before(:each) do - @node = Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - @new_resource = Chef::Resource::Script.new('run some perl code') - @new_resource.code "$| = 1; print 'i like beans'" - @new_resource.interpreter 'perl' - - @provider = Chef::Provider::Script.new(@new_resource, @run_context) - - @script_file = StringIO.new - @script_file.stub(:path).and_return('/tmp/the_script_file') - - @provider.stub(:shell_out!).and_return(true) - end - - it "creates a temporary file to store the script" do - @provider.script_file.should be_an_instance_of(Tempfile) - end - - it "unlinks the tempfile when finished" do - tempfile_path = @provider.script_file.path - @provider.unlink_script_file - File.exist?(tempfile_path).should be_false - end - - it "sets the owner and group for the script file" do - @new_resource.user 'toor' - @new_resource.group 'wheel' - @provider.stub(:script_file).and_return(@script_file) - FileUtils.should_receive(:chown).with('toor', 'wheel', "/tmp/the_script_file") - @provider.set_owner_and_group - end - - context "with the script file set to the correct owner and group" do - before do - @provider.stub(:set_owner_and_group) - @provider.stub(:script_file).and_return(@script_file) - end - describe "when writing the script to the file" do - it "should put the contents of the script in the temp file" do - @provider.action_run - @script_file.rewind - @script_file.string.should == "$| = 1; print 'i like beans'\n" - end - - it "closes before executing the script and unlinks it when finished" do - @provider.action_run - @script_file.should be_closed - end - - end - - describe "when running the script" do - it 'should set the command to "interpreter" "tempfile"' do - @provider.action_run - @new_resource.command.should == '"perl" "/tmp/the_script_file"' - end - - describe "with flags set on the resource" do - before do - @new_resource.flags '-f' - end - - it "should set the command to 'interpreter flags tempfile'" do - @provider.action_run - @new_resource.command.should == '"perl" -f "/tmp/the_script_file"' - end - - end - - end - end - -end diff --git a/spec/unit/provider/service/arch_service_spec.rb b/spec/unit/provider/service/arch_service_spec.rb deleted file mode 100644 index 38ed74cdee..0000000000 --- a/spec/unit/provider/service/arch_service_spec.rb +++ /dev/null @@ -1,324 +0,0 @@ -# -# Author:: Jan Zimmek (<jan.zimmek@web.de>) -# Author:: AJ Christensen (<aj@hjksolutions.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 'ostruct' - -# most of this code has been ripped from init_service_spec.rb -# and is only slightly modified to match "arch" needs. - -describe Chef::Provider::Service::Arch, "load_current_resource" do - before(:each) do - @node = Chef::Node.new - @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}) - - @provider = Chef::Provider::Service::Arch.new(@new_resource, @run_context) - - ::File.stub(:exists?).with("/etc/rc.conf").and_return(true) - ::File.stub(:read).with("/etc/rc.conf").and_return("DAEMONS=(network apache sshd)") - end - - describe "when first created" do - it "should set the current resources service name to the new resources service name" do - @provider.stub(:shell_out).and_return(OpenStruct.new(:exitstatus => 0, :stdout => "")) - @provider.load_current_resource - @provider.current_resource.service_name.should == 'chef' - end - end - - describe "when the service supports status" do - before do - @new_resource.supports({:status => true}) - end - - it "should run '/etc/rc.d/service_name status'" do - @provider.should_receive(:shell_out).with("/etc/rc.d/chef status").and_return(OpenStruct.new(:exitstatus => 0)) - @provider.load_current_resource - end - - it "should set running to true if the status command returns 0" do - @provider.stub(:shell_out).with("/etc/rc.d/chef status").and_return(OpenStruct.new(:exitstatus => 0)) - @provider.load_current_resource - @provider.current_resource.running.should be_true - end - - it "should set running to false if the status command returns anything except 0" do - @provider.stub(:shell_out).with("/etc/rc.d/chef status").and_return(OpenStruct.new(:exitstatus => 1)) - @provider.load_current_resource - @provider.current_resource.running.should be_false - end - - it "should set running to false if the status command raises" do - @provider.stub(:shell_out).with("/etc/rc.d/chef status").and_raise(Mixlib::ShellOut::ShellCommandFailed) - @provider.load_current_resource - @provider.current_resource.running.should be_false - end - - end - - describe "when a status command has been specified" do - before do - @new_resource.status_command("/etc/rc.d/chefhasmonkeypants status") - end - - it "should run the services status command if one has been specified" do - @provider.should_receive(:shell_out).with("/etc/rc.d/chefhasmonkeypants status").and_return(OpenStruct.new(:exitstatus => 0)) - @provider.load_current_resource - end - - 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} - @provider.define_resource_requirements - @provider.action = :start - lambda { @provider.process_resource_requirements }.should 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 => ""} - @provider.define_resource_requirements - @provider.action = :start - lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) - end - - it "should fail if file /etc/rc.conf does not exist" do - ::File.stub(:exists?).with("/etc/rc.conf").and_return(false) - lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Service) - end - - it "should fail if file /etc/rc.conf does not contain DAEMONS array" do - ::File.stub(:read).with("/etc/rc.conf").and_return("") - lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Service) - end - - describe "when discovering service status with ps" do - before do - @stdout = StringIO.new(<<-DEFAULT_PS) -aj 7842 5057 0 21:26 pts/2 00:00:06 vi init.rb -aj 7903 5016 0 21:26 pts/5 00:00:00 /bin/bash -aj 8119 6041 0 21:34 pts/3 00:00:03 vi init_service_spec.rb -DEFAULT_PS - @status = double("Status", :exitstatus => 0, :stdout => @stdout) - @provider.stub(:shell_out!).and_return(@status) - - @node.automatic_attrs[:command] = {:ps => "ps -ef"} - end - - it "determines the service is running when it appears in ps" do - @stdout = StringIO.new(<<-RUNNING_PS) -aj 7842 5057 0 21:26 pts/2 00:00:06 chef -aj 7842 5057 0 21:26 pts/2 00:00:06 poos -RUNNING_PS - @status.stub(:stdout).and_return(@stdout) - @provider.load_current_resource - @provider.current_resource.running.should be_true - end - - it "determines the service is not running when it does not appear in ps" do - @provider.stub(:shell_out!).and_return(@status) - @provider.load_current_resource - @provider.current_resource.running.should be_false - end - - it "should raise an exception if ps fails" do - @provider.stub(:shell_out!).and_raise(Mixlib::ShellOut::ShellCommandFailed) - @provider.load_current_resource - @provider.action = :start - @provider.define_resource_requirements - lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) - end - end - - it "should return existing entries in DAEMONS array" do - ::File.stub(:read).with("/etc/rc.conf").and_return("DAEMONS=(network !apache ssh)") - @provider.daemons.should == ['network', '!apache', 'ssh'] - end - - context "when the current service status is known" do - before do - @current_resource = Chef::Resource::Service.new("chef") - @provider.current_resource = @current_resource - end - - describe Chef::Provider::Service::Arch, "enable_service" do - # before(:each) do - # @new_resource = double("Chef::Resource::Service", - # :null_object => true, - # :name => "chef", - # :service_name => "chef", - # :running => false - # ) - # @new_resource.stub(:start_command).and_return(false) - # - # @provider = Chef::Provider::Service::Arch.new(@node, @new_resource) - # Chef::Resource::Service.stub(:new).and_return(@current_resource) - # end - - it "should add chef to DAEMONS array" do - ::File.stub(:read).with("/etc/rc.conf").and_return("DAEMONS=(network)") - @provider.should_receive(:update_daemons).with(['network', 'chef']) - @provider.enable_service() - end - end - - describe Chef::Provider::Service::Arch, "disable_service" do - # before(:each) do - # @new_resource = double("Chef::Resource::Service", - # :null_object => true, - # :name => "chef", - # :service_name => "chef", - # :running => false - # ) - # @new_resource.stub(:start_command).and_return(false) - # - # @provider = Chef::Provider::Service::Arch.new(@node, @new_resource) - # Chef::Resource::Service.stub(:new).and_return(@current_resource) - # end - - it "should remove chef from DAEMONS array" do - ::File.stub(:read).with("/etc/rc.conf").and_return("DAEMONS=(network chef)") - @provider.should_receive(:update_daemons).with(['network', '!chef']) - @provider.disable_service() - end - end - - describe Chef::Provider::Service::Arch, "start_service" do - # before(:each) do - # @new_resource = double("Chef::Resource::Service", - # :null_object => true, - # :name => "chef", - # :service_name => "chef", - # :running => false - # ) - # @new_resource.stub(:start_command).and_return(false) - # - # @provider = Chef::Provider::Service::Arch.new(@node, @new_resource) - # Chef::Resource::Service.stub(:new).and_return(@current_resource) - # end - - it "should call the start command if one is specified" do - @new_resource.stub(:start_command).and_return("/etc/rc.d/chef startyousillysally") - @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/rc.d/chef startyousillysally") - @provider.start_service() - end - - it "should call '/etc/rc.d/service_name start' if no start command is specified" do - @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/rc.d/#{@new_resource.service_name} start") - @provider.start_service() - end - end - - describe Chef::Provider::Service::Arch, "stop_service" do - # before(:each) do - # @new_resource = double("Chef::Resource::Service", - # :null_object => true, - # :name => "chef", - # :service_name => "chef", - # :running => false - # ) - # @new_resource.stub(:stop_command).and_return(false) - # - # @provider = Chef::Provider::Service::Arch.new(@node, @new_resource) - # Chef::Resource::Service.stub(:new).and_return(@current_resource) - # end - - it "should call the stop command if one is specified" do - @new_resource.stub(:stop_command).and_return("/etc/rc.d/chef itoldyoutostop") - @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/rc.d/chef itoldyoutostop") - @provider.stop_service() - end - - it "should call '/etc/rc.d/service_name stop' if no stop command is specified" do - @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/rc.d/#{@new_resource.service_name} stop") - @provider.stop_service() - end - end - - describe Chef::Provider::Service::Arch, "restart_service" do - # before(:each) do - # @new_resource = double("Chef::Resource::Service", - # :null_object => true, - # :name => "chef", - # :service_name => "chef", - # :running => false - # ) - # @new_resource.stub(:restart_command).and_return(false) - # @new_resource.stub(:supports).and_return({:restart => false}) - # - # @provider = Chef::Provider::Service::Arch.new(@node, @new_resource) - # Chef::Resource::Service.stub(:new).and_return(@current_resource) - # end - - it "should call 'restart' on the service_name if the resource supports it" do - @new_resource.stub(:supports).and_return({:restart => true}) - @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/rc.d/#{@new_resource.service_name} restart") - @provider.restart_service() - end - - it "should call the restart_command if one has been specified" do - @new_resource.stub(:restart_command).and_return("/etc/rc.d/chef restartinafire") - @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/rc.d/#{@new_resource.service_name} restartinafire") - @provider.restart_service() - end - - it "should just call stop, then start when the resource doesn't support restart and no restart_command is specified" do - @provider.should_receive(:stop_service) - @provider.should_receive(:sleep).with(1) - @provider.should_receive(:start_service) - @provider.restart_service() - end - end - - describe Chef::Provider::Service::Arch, "reload_service" do - # before(:each) do - # @new_resource = double("Chef::Resource::Service", - # :null_object => true, - # :name => "chef", - # :service_name => "chef", - # :running => false - # ) - # @new_resource.stub(:reload_command).and_return(false) - # @new_resource.stub(:supports).and_return({:reload => false}) - # - # @provider = Chef::Provider::Service::Arch.new(@node, @new_resource) - # Chef::Resource::Service.stub(:new).and_return(@current_resource) - # end - - it "should call 'reload' on the service if it supports it" do - @new_resource.stub(:supports).and_return({:reload => true}) - @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/rc.d/#{@new_resource.service_name} reload") - @provider.reload_service() - end - - it "should should run the user specified reload command if one is specified and the service doesn't support reload" do - @new_resource.stub(:reload_command).and_return("/etc/rc.d/chef lollerpants") - @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/rc.d/#{@new_resource.service_name} lollerpants") - @provider.reload_service() - end - end - end -end diff --git a/spec/unit/provider/service/debian_service_spec.rb b/spec/unit/provider/service/debian_service_spec.rb deleted file mode 100644 index 3e60857cbf..0000000000 --- a/spec/unit/provider/service/debian_service_spec.rb +++ /dev/null @@ -1,375 +0,0 @@ -# -# Author:: AJ Christensen (<aj@hjksolutions.com>) -# Copyright:: Copyright (c) 2008 HJK Solutions, LLC -# 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::Service::Debian do - before(:each) do - @node = Chef::Node.new - @node.automatic_attrs[:command] = {:ps => 'fuuuu'} - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - - @new_resource = Chef::Resource::Service.new("chef") - @provider = Chef::Provider::Service::Debian.new(@new_resource, @run_context) - - @current_resource = Chef::Resource::Service.new("chef") - @provider.current_resource = @current_resource - - @pid, @stdin, @stdout, @stderr = nil, nil, nil, nil - end - - describe "load_current_resource" do - it "ensures /usr/sbin/update-rc.d is available" do - File.should_receive(:exists?).with("/usr/sbin/update-rc.d") .and_return(false) - - @provider.define_resource_requirements - lambda { - @provider.process_resource_requirements - }.should raise_error(Chef::Exceptions::Service) - end - - context "when update-rc.d shows init linked to rc*.d/" do - before do - @provider.stub(:assert_update_rcd_available) - - result = <<-UPDATE_RC_D_SUCCESS - Removing any system startup links for /etc/init.d/chef ... - /etc/rc0.d/K20chef - /etc/rc1.d/K20chef - /etc/rc2.d/S20chef - /etc/rc3.d/S20chef - /etc/rc4.d/S20chef - /etc/rc5.d/S20chef - /etc/rc6.d/K20chef - UPDATE_RC_D_SUCCESS - - @stdout = StringIO.new(result) - @stderr = StringIO.new - @status = double("Status", :exitstatus => 0, :stdout => @stdout) - @provider.stub(:shell_out!).and_return(@status) - @provider.stub(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - end - - it "says the service is enabled" do - @provider.service_currently_enabled?(@provider.get_priority).should be_true - end - - it "stores the 'enabled' state" do - Chef::Resource::Service.stub(:new).and_return(@current_resource) - @provider.load_current_resource.should equal(@current_resource) - @current_resource.enabled.should be_true - end - end - - context "when update-rc.d shows init isn't linked to rc*.d/" do - before do - @provider.stub(:assert_update_rcd_available) - @status = double("Status", :exitstatus => 0) - @stdout = StringIO.new( - " Removing any system startup links for /etc/init.d/chef ...") - @stderr = StringIO.new - @status = double("Status", :exitstatus => 0, :stdout => @stdout) - @provider.stub(:shell_out!).and_return(@status) - @provider.stub(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - end - - it "says the service is disabled" do - @provider.service_currently_enabled?(@provider.get_priority).should be_false - end - - it "stores the 'disabled' state" do - Chef::Resource::Service.stub(:new).and_return(@current_resource) - @provider.load_current_resource.should equal(@current_resource) - @current_resource.enabled.should be_false - end - end - - context "when update-rc.d fails" do - before do - @status = double("Status", :exitstatus => -1) - @provider.stub(:popen4).and_return(@status) - end - - it "raises an error" do - @provider.define_resource_requirements - lambda { - @provider.process_resource_requirements - }.should raise_error(Chef::Exceptions::Service) - end - end - - {"Debian/Lenny and older" => { - "linked" => { - "stdout" => <<-STDOUT, - Removing any system startup links for /etc/init.d/chef ... - /etc/rc0.d/K20chef - /etc/rc1.d/K20chef - /etc/rc2.d/S20chef - /etc/rc3.d/S20chef - /etc/rc4.d/S20chef - /etc/rc5.d/S20chef - /etc/rc6.d/K20chef - STDOUT - "stderr" => "", - "priorities" => { - "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" => "" - }, - }, - "Debian/Squeeze and earlier" => { - "linked" => { - "stdout" => "update-rc.d: using dependency based boot sequencing", - "stderr" => <<-STDERR, -insserv: remove service /etc/init.d/../rc0.d/K20chef-client - insserv: remove service /etc/init.d/../rc1.d/K20chef-client - insserv: remove service /etc/init.d/../rc2.d/S20chef-client - insserv: remove service /etc/init.d/../rc3.d/S20chef-client - insserv: remove service /etc/init.d/../rc4.d/S20chef-client - insserv: remove service /etc/init.d/../rc5.d/S20chef-client - insserv: remove service /etc/init.d/../rc6.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"] - } - }, - "not linked" => { - "stdout" => "update-rc.d: using dependency based boot sequencing", - "stderr" => "" - } - }, - "Debian/Wheezy and earlier, a service only starting at run level S" => { - "linked" => { - "stdout" => "", - "stderr" => <<-STDERR, -insserv: remove service /etc/init.d/../rc0.d/K06rpcbind -insserv: remove service /etc/init.d/../rc1.d/K06rpcbind -insserv: remove service /etc/init.d/../rc6.d/K06rpcbind -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"] - } - }, - "not linked" => { - "stdout" => "", - "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 - before do - @provider.stub(:assert_update_rcd_available) - - @stdout = StringIO.new(expected_results["linked"]["stdout"]) - @stderr = StringIO.new(expected_results["linked"]["stderr"]) - @status = double("Status", :exitstatus => 0, :stdout => @stdout) - @provider.stub(:shell_out!).and_return(@status) - @provider.stub(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - end - - it "says the service is enabled" do - @provider.service_currently_enabled?(@provider.get_priority).should be_true - end - - it "stores the 'enabled' state" do - Chef::Resource::Service.stub(:new).and_return(@current_resource) - @provider.load_current_resource.should equal(@current_resource) - @current_resource.enabled.should be_true - end - - it "stores the start/stop priorities of the service" do - @provider.load_current_resource - @provider.current_resource.priority.should == expected_results["linked"]["priorities"] - end - end - - context "when update-rc.d shows init isn't linked to rc*.d/" do - before do - @provider.stub(:assert_update_rcd_available) - @stdout = StringIO.new(expected_results["not linked"]["stdout"]) - @stderr = StringIO.new(expected_results["not linked"]["stderr"]) - @status = double("Status", :exitstatus => 0, :stdout => @stdout) - @provider.stub(:shell_out!).and_return(@status) - @provider.stub(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - end - - it "says the service is disabled" do - @provider.service_currently_enabled?(@provider.get_priority).should be_false - end - - it "stores the 'disabled' state" do - Chef::Resource::Service.stub(:new).and_return(@current_resource) - @provider.load_current_resource.should equal(@current_resource) - @current_resource.enabled.should be_false - end - end - end - end - - end - - describe "action_enable" do - shared_examples_for "the service is up to date" do - it "does not enable the service" do - @provider.should_not_receive(:enable_service) - @provider.action_enable - @provider.set_updated_status - @provider.new_resource.should_not be_updated - end - end - - shared_examples_for "the service is not up to date" do - it "enables the service and sets the resource as updated" do - @provider.should_receive(:enable_service).and_return(true) - @provider.action_enable - @provider.set_updated_status - @provider.new_resource.should be_updated - end - end - - context "when the service is disabled" do - before do - @current_resource.enabled(false) - end - - it_behaves_like "the service is not up to date" - end - - context "when the service is enabled" do - before do - @current_resource.enabled(true) - @current_resource.priority(80) - end - - context "and the service sets no priority" do - it_behaves_like "the service is up to date" - end - - context "and the service requests the same priority as is set" do - before do - @new_resource.priority(80) - end - it_behaves_like "the service is up to date" - end - - context "and the service requests a different priority than is set" do - before do - @new_resource.priority(20) - end - it_behaves_like "the service is not up to date" - end - end - end - - def expect_commands(provider, commands) - commands.each do |command| - provider.should_receive(:shell_out!).with(command) - end - end - - describe "enable_service" do - let(:service_name) { @new_resource.service_name } - context "when the service doesn't set a priority" do - 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" - ]) - @provider.enable_service - end - end - - context "when the service sets a simple priority" do - before do - @new_resource.priority(75) - end - - 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" - ]) - @provider.enable_service - end - end - - context "when the service sets complex priorities" do - before do - @new_resource.priority(2 => [:start, 20], 3 => [:stop, 55]) - end - - 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 . " - ]) - @provider.enable_service - end - end - end - - describe "disable_service" do - let(:service_name) { @new_resource.service_name } - context "when the service doesn't set a priority" do - 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 ." - ]) - @provider.disable_service - end - end - - context "when the service sets a simple priority" do - before do - @new_resource.priority(75) - end - - 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 ." - ]) - @provider.disable_service - end - end - end -end diff --git a/spec/unit/provider/service/freebsd_service_spec.rb b/spec/unit/provider/service/freebsd_service_spec.rb deleted file mode 100644 index eb55fac820..0000000000 --- a/spec/unit/provider/service/freebsd_service_spec.rb +++ /dev/null @@ -1,611 +0,0 @@ -# -# Author:: Bryan McLellan (btm@loftninjas.org) -# Copyright:: Copyright (c) 2009 Bryan McLellan -# 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 Chef::Provider::Service::Freebsd - public :service_enable_variable_name - public :determine_enabled_status! - public :determine_current_status! -end - -describe Chef::Provider::Service::Freebsd do - let(:node) do - node = Chef::Node.new - 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 - end - - let(:current_resource) do - current_resource = Chef::Resource::Service.new("apache22") - current_resource - end - - 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.action = :start - provider - end - - before do - allow(Chef::Resource::Service).to receive(:new).and_return(current_resource) - end - - def stub_etc_rcd_script - allow(::File).to receive(:exist?).and_return(false) - expect(::File).to receive(:exist?).with("/etc/rc.d/#{new_resource.service_name}").and_return(true) - end - - def stub_usr_local_rcd_script - allow(::File).to receive(:exist?).and_return(false) - expect(::File).to receive(:exist?).with("/usr/local/etc/rc.d/#{new_resource.service_name}").and_return(true) - end - - def run_load_current_resource - stub_usr_local_rcd_script - provider.load_current_resource - end - - describe Chef::Provider::Service::Freebsd, "initialize" do - it "should default enabled_state_found to false" do - expect(provider.enabled_state_found).to be false - end - - it "should find /usr/local/etc/rc.d init scripts" do - stub_usr_local_rcd_script - expect(provider.init_command).to eql "/usr/local/etc/rc.d/apache22" - end - - it "should find /etc/rc.d init scripts" do - stub_etc_rcd_script - expect(provider.init_command).to eql "/etc/rc.d/apache22" - end - - it "should set init_command to nil if it can't find anything" do - allow(::File).to receive(:exist?).and_return(false) - expect(provider.init_command).to be nil - end - end - - describe Chef::Provider::Service::Freebsd, "determine_current_status!" do - before do - stub_usr_local_rcd_script - provider.current_resource = current_resource - current_resource.service_name(new_resource.service_name) - end - - context "when a status command has been specified" do - let(:status) { double(:stdout => "", :exitstatus => 0) } - - before do - new_resource.status_command("/bin/chefhasmonkeypants status") - end - - it "should run the services status command if one has been specified" do - expect(provider).to receive(:shell_out).with("/bin/chefhasmonkeypants status").and_return(status) - provider.determine_current_status! - end - end - - context "when the service supports status" do - let(:status) { double(:stdout => "", :exitstatus => 0) } - - before do - new_resource.supports({:status => true}) - end - - it "should run '/etc/init.d/service_name status'" do - expect(provider).to receive(:shell_out).with("/usr/local/etc/rc.d/#{new_resource.service_name} status").and_return(status) - provider.determine_current_status! - end - - it "should set running to true if the status command returns 0" do - expect(provider).to receive(:shell_out).with("/usr/local/etc/rc.d/#{new_resource.service_name} status").and_return(status) - provider.determine_current_status! - expect(current_resource.running).to be true - end - - it "should set running to false if the status command returns anything except 0" do - expect(provider).to receive(:shell_out).with("/usr/local/etc/rc.d/#{new_resource.service_name} status").and_raise(Mixlib::ShellOut::ShellCommandFailed) - provider.determine_current_status! - expect(current_resource.running).to be false - end - end - - context "when we have a 'ps' attribute" do - let(:stdout) do - StringIO.new(<<-PS_SAMPLE) -413 ?? Ss 0:02.51 /usr/sbin/syslogd -s -539 ?? Is 0:00.14 /usr/sbin/sshd -545 ?? Ss 0:17.53 sendmail: accepting connections (sendmail) -PS_SAMPLE - end - let(:status) { double(:stdout => stdout, :exitstatus => 0) } - - before do - node.automatic_attrs[:command] = {:ps => "ps -ax"} - end - - it "should shell_out! the node's ps command" do - expect(provider).to receive(:shell_out!).with(node[:command][:ps]).and_return(status) - provider.determine_current_status! - end - - it "should read stdout of the ps command" do - allow(provider).to receive(:shell_out!).and_return(status) - expect(stdout).to receive(:each_line).and_return(true) - provider.determine_current_status! - end - - context "when the regex matches the output" do - let(:stdout) do - StringIO.new(<<-PS_SAMPLE) -555 ?? Ss 0:05.16 /usr/sbin/cron -s - 9881 ?? Ss 0:06.67 /usr/local/sbin/httpd -DNOHTTPACCEPT - PS_SAMPLE - end - - it "should set running to true" do - allow(provider).to receive(:shell_out!).and_return(status) - provider.determine_current_status! - expect(current_resource.running).to be_true - end - end - - it "should set running to false if the regex doesn't match" do - allow(provider).to receive(:shell_out!).and_return(status) - provider.determine_current_status! - expect(current_resource.running).to be_false - end - - it "should set running to nil if ps fails" do - allow(provider).to receive(:shell_out!).and_raise(Mixlib::ShellOut::ShellCommandFailed) - provider.determine_current_status! - expect(current_resource.running).to be_nil - 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 => ""} - end - - it "should set running to nil" do - provider.determine_current_status! - expect(current_resource.running).to be_nil - end - end - end - end - - describe Chef::Provider::Service::Freebsd, "determine_enabled_status!" do - before do - stub_usr_local_rcd_script - provider.current_resource = current_resource - current_resource.service_name(new_resource.service_name) - - allow(provider).to receive(:service_enable_variable_name).and_return("#{new_resource.service_name}_enable") - end - - context "when /etc/rc.conf does not exist" do - before do - expect(::File).to receive(:exist?).with("/etc/rc.conf").and_return(false) - end - - it "sets enabled to false" do - provider.determine_enabled_status! - expect(current_resource.enabled).to be false - end - end - - context "when /etc/rc.conf does exist" do - before do - expect(::File).to receive(:exist?).with("/etc/rc.conf").and_return(true) - expect(provider).to receive(:read_rc_conf).and_return(lines) - end - - %w{YES Yes yes yEs YeS}.each do |setting| - context "when the enable variable is set to #{setting}" do - let(:lines) { [ %Q{#{new_resource.service_name}_enable="#{setting}"} ] } - it "sets enabled to true" do - provider.determine_enabled_status! - expect(current_resource.enabled).to be true - end - end - end - - %w{No NO no nO None NONE none nOnE}.each do |setting| - context "when the enable variable is set to #{setting}" do - let(:lines) { [ %Q{#{new_resource.service_name}_enable="#{setting}"} ] } - it "sets enabled to false" do - provider.determine_enabled_status! - expect(current_resource.enabled).to be false - end - end - end - - context "when the enable variable is garbage" do - let(:lines) { [ %Q{#{new_resource.service_name}_enable="alskdjflasdkjflakdfj"} ] } - it "sets enabled to false" do - provider.determine_enabled_status! - expect(current_resource.enabled).to be false - end - end - - context "when the enable variable partial matches (left) some other service and we are disabled" do - let(:lines) { [ - %Q{thing_#{new_resource.service_name}_enable="YES"}, - %Q{#{new_resource.service_name}_enable="NO"}, - ] } - it "sets enabled based on the exact match (false)" do - provider.determine_enabled_status! - expect(current_resource.enabled).to be false - end - end - - context "when the enable variable partial matches (right) some other service and we are disabled" do - let(:lines) { [ - %Q{#{new_resource.service_name}_thing_enable="YES"}, - %Q{#{new_resource.service_name}_enable="NO"}, - ] } - it "sets enabled based on the exact match (false)" do - provider.determine_enabled_status! - expect(current_resource.enabled).to be false - end - end - - context "when the enable variable partial matches (left) some other disabled service and we are enabled" do - let(:lines) { [ - %Q{thing_#{new_resource.service_name}_enable="NO"}, - %Q{#{new_resource.service_name}_enable="YES"}, - ] } - it "sets enabled based on the exact match (true)" do - provider.determine_enabled_status! - expect(current_resource.enabled).to be true - end - end - - context "when the enable variable partial matches (right) some other disabled service and we are enabled" do - let(:lines) { [ - %Q{#{new_resource.service_name}_thing_enable="NO"}, - %Q{#{new_resource.service_name}_enable="YES"}, - ] } - it "sets enabled based on the exact match (true)" do - provider.determine_enabled_status! - expect(current_resource.enabled).to be true - end - end - - context "when the enable variable only partial matches (left) some other enabled service" do - let(:lines) { [ %Q{thing_#{new_resource.service_name}_enable="YES"} ] } - it "sets enabled to false" do - provider.determine_enabled_status! - expect(current_resource.enabled).to be false - end - end - - context "when the enable variable only partial matches (right) some other enabled service" do - let(:lines) { [ %Q{#{new_resource.service_name}_thing_enable="YES"} ] } - it "sets enabled to false" do - provider.determine_enabled_status! - expect(current_resource.enabled).to be false - end - end - - context "when nothing matches" do - let(:lines) { [] } - it "sets enabled to true" do - provider.determine_enabled_status! - expect(current_resource.enabled).to be false - end - end - end - end - - describe Chef::Provider::Service::Freebsd, "service_enable_variable_name" do - before do - stub_usr_local_rcd_script - provider.current_resource = current_resource - current_resource.service_name(new_resource.service_name) - - expect(::File).to receive(:open).with("/usr/local/etc/rc.d/#{new_resource.service_name}").and_yield(rcscript) - end - - context "when the rc script has a 'name' variable" do - let(:rcscript) do - StringIO.new(<<-EOF) -name="#{new_resource.service_name}" -rcvar=`set_rcvar` -EOF - end - - it "should not raise an exception if the rcscript have a name variable" do - expect { provider.service_enable_variable_name }.not_to raise_error - end - - it "should not run rcvar" do - expect(provider).not_to receive(:shell_out!) - provider.service_enable_variable_name - end - - it "should return the enable variable determined from the rcscript name" do - expect(provider.service_enable_variable_name).to eql "#{new_resource.service_name}_enable" - end - end - - describe "when the rcscript does not have a name variable" do - let(:rcscript) do - StringIO.new <<-EOF -rcvar=`set_rcvar` -EOF - end - - before do - status = double(:stdout => rcvar_stdout, :exitstatus => 0) - allow(provider).to receive(:shell_out!).with("/usr/local/etc/rc.d/#{new_resource.service_name} rcvar").and_return(status) - end - - describe "when rcvar returns foobar_enable" do - let(:rcvar_stdout) do - rcvar_stdout = <<-EOF -# apache22 -# -# #{new_resource.service_name}_enable="YES" -# (default: "") -EOF - end - - it "should get the service name from rcvar if the rcscript does not have a name variable" do - expect(provider.service_enable_variable_name).to eq("#{new_resource.service_name}_enable") - end - - it "should not raise an exception if the rcscript does not have a name variable" do - expect { provider.service_enable_variable_name }.not_to raise_error - end - end - - describe "when rcvar does not return foobar_enable" do - let(:rcvar_stdout) do - rcvar_stdout = <<-EOF -# service_with_noname -# -EOF - end - - it "should return nil" do - expect(provider.service_enable_variable_name).to be nil - end - end - end - end - - describe Chef::Provider::Service::Freebsd, "load_current_resource" do - before(:each) do - stub_usr_local_rcd_script - expect(provider).to receive(:determine_current_status!) - current_resource.running(false) - allow(provider).to receive(:service_enable_variable_name).and_return "#{new_resource.service_name}_enable" - 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) - provider.load_current_resource - end - - 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(new_resource.service_name) - end - - it "should return the current resource" do - expect(provider.load_current_resource).to eql(current_resource) - end - - end - - context "when testing actions" do - before(:each) do - stub_usr_local_rcd_script - expect(provider).to receive(:determine_current_status!) - current_resource.running(false) - expect(provider).to receive(:determine_enabled_status!) - current_resource.enabled(false) - provider.load_current_resource - end - - describe Chef::Provider::Service::Freebsd, "start_service" do - it "should call the start command if one is specified" do - new_resource.start_command("/etc/rc.d/chef startyousillysally") - expect(provider).to receive(:shell_out_with_systems_locale!).with("/etc/rc.d/chef startyousillysally") - provider.start_service() - end - - it "should call '/usr/local/etc/rc.d/service_name faststart' if no start command is specified" do - expect(provider).to receive(:shell_out_with_systems_locale!).with("/usr/local/etc/rc.d/#{new_resource.service_name} faststart") - provider.start_service() - end - end - - describe Chef::Provider::Service::Freebsd, "stop_service" do - it "should call the stop command if one is specified" do - new_resource.stop_command("/etc/init.d/chef itoldyoutostop") - expect(provider).to receive(:shell_out_with_systems_locale!).with("/etc/init.d/chef itoldyoutostop") - provider.stop_service() - end - - it "should call '/usr/local/etc/rc.d/service_name faststop' if no stop command is specified" do - expect(provider).to receive(:shell_out_with_systems_locale!).with("/usr/local/etc/rc.d/#{new_resource.service_name} faststop") - provider.stop_service() - end - end - - 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}) - expect(provider).to receive(:shell_out_with_systems_locale!).with("/usr/local/etc/rc.d/#{new_resource.service_name} fastrestart") - provider.restart_service() - end - - it "should call the restart_command if one has been specified" do - new_resource.restart_command("/etc/init.d/chef restartinafire") - expect(provider).to receive(:shell_out_with_systems_locale!).with("/etc/init.d/chef restartinafire") - provider.restart_service() - end - - it "otherwise it should call stop and start" do - expect(provider).to receive(:stop_service) - expect(provider).to receive(:start_service) - provider.restart_service() - end - end - end - - describe Chef::Provider::Service::Freebsd, "define_resource_requirements" do - before do - provider.current_resource = current_resource - end - - context "when the init script is not found" do - before do - provider.init_command = nil - allow(provider).to receive(:service_enable_variable_name).and_return("#{new_resource.service_name}_enable") - end - - [ "start", "reload", "restart", "enable" ].each do |action| - it "should raise an exception when the action is #{action}" do - provider.define_resource_requirements - provider.action = action - expect { provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Service) - end - end - - [ "stop", "disable" ].each do |action| - it "should not raise an error when the action is #{action}" do - provider.define_resource_requirements - provider.action = action - expect { provider.process_resource_requirements }.not_to raise_error - end - end - end - - context "when the init script is found, but the service_enable_variable_name is nil" do - before do - provider.init_command = nil - allow(provider).to receive(:service_enable_variable_name).and_return(nil) - end - - [ "start", "reload", "restart", "enable" ].each do |action| - it "should raise an exception when the action is #{action}" do - provider.action = action - provider.define_resource_requirements - expect { provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Service) - end - end - - [ "stop", "disable" ].each do |action| - it "should not raise an error when the action is #{action}" do - provider.action = action - provider.define_resource_requirements - expect { provider.process_resource_requirements }.not_to raise_error - end - end - end - end - - describe Chef::Provider::Service::Freebsd, "enable_service" do - before do - provider.current_resource = current_resource - allow(provider).to receive(:service_enable_variable_name).and_return("#{new_resource.service_name}_enable") - end - - it "should enable the service if it is not enabled" do - allow(current_resource).to receive(:enabled).and_return(false) - expect(provider).to receive(:read_rc_conf).and_return([ "foo", "#{new_resource.service_name}_enable=\"NO\"", "bar" ]) - expect(provider).to receive(:write_rc_conf).with(["foo", "bar", "#{new_resource.service_name}_enable=\"YES\""]) - provider.enable_service() - end - - it "should not partial match an already enabled service" do - allow(current_resource).to receive(:enabled).and_return(false) - expect(provider).to receive(:read_rc_conf).and_return([ "foo", "thing_#{new_resource.service_name}_enable=\"NO\"", "bar" ]) - expect(provider).to receive(:write_rc_conf).with(["foo", "thing_#{new_resource.service_name}_enable=\"NO\"", "bar", "#{new_resource.service_name}_enable=\"YES\""]) - provider.enable_service() - end - - it "should enable the service if it is not enabled and not already specified in the rc.conf file" do - allow(current_resource).to receive(:enabled).and_return(false) - expect(provider).to receive(:read_rc_conf).and_return([ "foo", "bar" ]) - expect(provider).to receive(:write_rc_conf).with(["foo", "bar", "#{new_resource.service_name}_enable=\"YES\""]) - provider.enable_service() - end - - it "should not enable the service if it is already enabled" do - allow(current_resource).to receive(:enabled).and_return(true) - expect(provider).not_to receive(:write_rc_conf) - provider.enable_service - end - end - - describe Chef::Provider::Service::Freebsd, "disable_service" do - before do - provider.current_resource = current_resource - allow(provider).to receive(:service_enable_variable_name).and_return("#{new_resource.service_name}_enable") - end - - it "should disable the service if it is not disabled" do - allow(current_resource).to receive(:enabled).and_return(true) - expect(provider).to receive(:read_rc_conf).and_return([ "foo", "#{new_resource.service_name}_enable=\"YES\"", "bar" ]) - expect(provider).to receive(:write_rc_conf).with(["foo", "bar", "#{new_resource.service_name}_enable=\"NO\""]) - provider.disable_service() - end - - it "should not disable an enabled service that partially matches" do - allow(current_resource).to receive(:enabled).and_return(true) - expect(provider).to receive(:read_rc_conf).and_return([ "foo", "thing_#{new_resource.service_name}_enable=\"YES\"", "bar" ]) - expect(provider).to receive(:write_rc_conf).with(["foo", "thing_#{new_resource.service_name}_enable=\"YES\"", "bar", "#{new_resource.service_name}_enable=\"NO\""]) - provider.disable_service() - end - - it "should not disable the service if it is already disabled" do - allow(current_resource).to receive(:enabled).and_return(false) - expect(provider).not_to receive(:write_rc_conf) - provider.disable_service() - end - end -end diff --git a/spec/unit/provider/service/gentoo_service_spec.rb b/spec/unit/provider/service/gentoo_service_spec.rb deleted file mode 100644 index 022a73cc9a..0000000000 --- a/spec/unit/provider/service/gentoo_service_spec.rb +++ /dev/null @@ -1,144 +0,0 @@ -# -# Author:: Lee Jensen (<ljensen@engineyard.com>) -# Author:: AJ Christensen (<aj@opscode.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' - -describe Chef::Provider::Service::Gentoo do - before(:each) do - @node = Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - - @new_resource = Chef::Resource::Service.new("chef") - @current_resource = Chef::Resource::Service.new("chef") - - @provider = Chef::Provider::Service::Gentoo.new(@new_resource, @run_context) - Chef::Resource::Service.stub(:new).and_return(@current_resource) - @status = double("Status", :exitstatus => 0, :stdout => @stdout) - @provider.stub(:shell_out).and_return(@status) - File.stub(:exists?).with("/etc/init.d/chef").and_return(true) - File.stub(:exists?).with("/sbin/rc-update").and_return(true) - File.stub(:exists?).with("/etc/runlevels/default/chef").and_return(false) - File.stub(:readable?).with("/etc/runlevels/default/chef").and_return(false) - end - # new test: found_enabled state - # - describe "load_current_resource" do - it "should raise Chef::Exceptions::Service if /sbin/rc-update does not exist" do - File.should_receive(:exists?).with("/sbin/rc-update").and_return(false) - @provider.define_resource_requirements - lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) - end - - it "should track when service file is not found in /etc/runlevels" do - @provider.load_current_resource - @provider.instance_variable_get("@found_script").should be_false - end - - it "should track when service file is found in /etc/runlevels/**/" do - Dir.stub(:glob).with("/etc/runlevels/**/chef").and_return(["/etc/runlevels/default/chef"]) - @provider.load_current_resource - @provider.instance_variable_get("@found_script").should be_true - end - - describe "when detecting the service enable state" do - describe "and the glob returns a default service script file" do - before do - Dir.stub(:glob).with("/etc/runlevels/**/chef").and_return(["/etc/runlevels/default/chef"]) - end - - describe "and the file exists and is readable" do - before do - File.stub(:exists?).with("/etc/runlevels/default/chef").and_return(true) - File.stub(:readable?).with("/etc/runlevels/default/chef").and_return(true) - end - it "should set enabled to true" do - @provider.load_current_resource - @current_resource.enabled.should be_true - end - end - - describe "and the file exists but is not readable" do - before do - File.stub(:exists?).with("/etc/runlevels/default/chef").and_return(true) - File.stub(:readable?).with("/etc/runlevels/default/chef").and_return(false) - end - - it "should set enabled to false" do - @provider.load_current_resource - @current_resource.enabled.should be_false - end - end - - describe "and the file does not exist" do - before do - File.stub(:exists?).with("/etc/runlevels/default/chef").and_return(false) - File.stub(:readable?).with("/etc/runlevels/default/chef").and_return("foobarbaz") - end - - it "should set enabled to false" do - @provider.load_current_resource - @current_resource.enabled.should be_false - end - - end - end - - end - - it "should return the current_resource" do - @provider.load_current_resource.should == @current_resource - end - - it "should support the status command automatically" do - @provider.load_current_resource - @new_resource.supports[:status].should be_true - end - - it "should support the restart command automatically" do - @provider.load_current_resource - @new_resource.supports[:restart].should be_true - end - - it "should not support the reload command automatically" do - @provider.load_current_resource - @new_resource.supports[:reload].should_not be_true - end - - end - - describe "action_methods" do - before(:each) { @provider.stub(:load_current_resource).and_return(@current_resource) } - - describe Chef::Provider::Service::Gentoo, "enable_service" do - it "should call rc-update add *service* default" do - @provider.should_receive(:shell_out!).with("/sbin/rc-update add chef default") - @provider.enable_service() - end - end - - describe Chef::Provider::Service::Gentoo, "disable_service" do - it "should call rc-update del *service* default" do - @provider.should_receive(:shell_out!).with("/sbin/rc-update del chef default") - @provider.disable_service() - end - end - end - -end diff --git a/spec/unit/provider/service/init_service_spec.rb b/spec/unit/provider/service/init_service_spec.rb deleted file mode 100644 index b523f6d3a9..0000000000 --- a/spec/unit/provider/service/init_service_spec.rb +++ /dev/null @@ -1,235 +0,0 @@ -# -# Author:: AJ Christensen (<aj@hjksolutions.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' - -describe Chef::Provider::Service::Init, "load_current_resource" do - before(:each) do - @node = Chef::Node.new - @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") - - @current_resource = Chef::Resource::Service.new("chef") - - @provider = Chef::Provider::Service::Init.new(@new_resource, @run_context) - Chef::Resource::Service.stub(:new).and_return(@current_resource) - - @stdout = StringIO.new(<<-PS) -aj 7842 5057 0 21:26 pts/2 00:00:06 vi init.rb -aj 7903 5016 0 21:26 pts/5 00:00:00 /bin/bash -aj 8119 6041 0 21:34 pts/3 00:00:03 vi init_service_spec.rb -PS - @status = double("Status", :exitstatus => 0, :stdout => @stdout) - @provider.stub(:shell_out!).and_return(@status) - end - - it "should create a current resource with the name of the new resource" do - @provider.load_current_resource - @provider.current_resource.should equal(@current_resource) - end - - it "should set the current resources service name to the new resources service name" do - @provider.load_current_resource - @current_resource.service_name.should == 'chef' - end - - describe "when the service supports status" do - before do - @new_resource.supports({:status => true}) - end - - it "should run '/etc/init.d/service_name status'" do - @provider.should_receive(:shell_out).with("/etc/init.d/#{@current_resource.service_name} status").and_return(@status) - @provider.load_current_resource - end - - it "should set running to true if the status command returns 0" do - @provider.stub(:shell_out).with("/etc/init.d/#{@current_resource.service_name} status").and_return(@status) - @provider.load_current_resource - @current_resource.running.should be_true - end - - it "should set running to false if the status command returns anything except 0" do - @status.stub(:exitstatus).and_return(1) - @provider.stub(:shell_out).with("/etc/init.d/#{@current_resource.service_name} status").and_return(@status) - @provider.load_current_resource - @current_resource.running.should be_false - end - - it "should set running to false if the status command raises" do - @provider.stub(:shell_out).and_raise(Mixlib::ShellOut::ShellCommandFailed) - @provider.load_current_resource - @current_resource.running.should be_false - end - end - - describe "when a status command has been specified" do - before do - @new_resource.stub(:status_command).and_return("/etc/init.d/chefhasmonkeypants status") - end - - it "should run the services status command if one has been specified" do - @provider.should_receive(:shell_out).with("/etc/init.d/chefhasmonkeypants status").and_return(@status) - @provider.load_current_resource - end - - end - - describe "when an init command has been specified" do - before do - @new_resource.stub(:init_command).and_return("/opt/chef-server/service/erchef") - @provider = Chef::Provider::Service::Init.new(@new_resource, @run_context) - end - - it "should use the init_command if one has been specified" do - @provider.should_receive(:shell_out_with_systems_locale!).with("/opt/chef-server/service/erchef start") - @provider.start_service - end - - end - - 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} - @provider.load_current_resource - @provider.action = :start - @provider.define_resource_requirements - lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) - end - - it "should raise an error if the node has an empty ps attribute" do - @node.automatic_attrs[:command] = {:ps => ""} - @provider.load_current_resource - @provider.action = :start - @provider.define_resource_requirements - lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) - end - - end - - describe "when we have a 'ps' attribute" do - it "should shell_out! the node's ps command" do - @provider.should_receive(:shell_out!).and_return(@status) - @provider.load_current_resource - end - - it "should set running to true if the regex matches the output" do - @stdout = StringIO.new(<<-RUNNING_PS) -aj 7842 5057 0 21:26 pts/2 00:00:06 chef -aj 7842 5057 0 21:26 pts/2 00:00:06 poos -RUNNING_PS - @status.stub(:stdout).and_return(@stdout) - @provider.load_current_resource - @current_resource.running.should be_true - end - - it "should set running to false if the regex doesn't match" do - @provider.stub(:shell_out!).and_return(@status) - @provider.load_current_resource - @current_resource.running.should be_false - end - - it "should raise an exception if ps fails" do - @provider.stub(:shell_out!).and_raise(Mixlib::ShellOut::ShellCommandFailed) - @provider.load_current_resource - @provider.action = :start - @provider.define_resource_requirements - lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) - end - end - - it "should return the current resource" do - @provider.load_current_resource.should eql(@current_resource) - end - - describe "when starting the service" do - it "should call the start command if one is specified" do - @new_resource.start_command("/etc/init.d/chef startyousillysally") - @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/init.d/chef startyousillysally") - @provider.start_service() - end - - it "should call '/etc/init.d/service_name start' if no start command is specified" do - @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/init.d/#{@new_resource.service_name} start") - @provider.start_service() - end - end - - describe Chef::Provider::Service::Init, "stop_service" do - it "should call the stop command if one is specified" do - @new_resource.stop_command("/etc/init.d/chef itoldyoutostop") - @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/init.d/chef itoldyoutostop") - @provider.stop_service() - end - - it "should call '/etc/init.d/service_name stop' if no stop command is specified" do - @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/init.d/#{@new_resource.service_name} stop") - @provider.stop_service() - end - end - - 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}) - @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/init.d/#{@new_resource.service_name} restart") - @provider.restart_service() - end - - it "should call the restart_command if one has been specified" do - @new_resource.restart_command("/etc/init.d/chef restartinafire") - @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/init.d/#{@new_resource.service_name} restartinafire") - @provider.restart_service() - end - - it "should just call stop, then start when the resource doesn't support restart and no restart_command is specified" do - @provider.should_receive(:stop_service) - @provider.should_receive(:sleep).with(1) - @provider.should_receive(:start_service) - @provider.restart_service() - end - end - - describe "when reloading a service" do - it "should call 'reload' on the service if it supports it" do - @new_resource.supports({:reload => true}) - @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/init.d/chef reload") - @provider.reload_service() - end - - it "should should run the user specified reload command if one is specified and the service doesn't support reload" do - @new_resource.reload_command("/etc/init.d/chef lollerpants") - @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/init.d/chef lollerpants") - @provider.reload_service() - end - end - - describe "when a custom command has been specified" do - before do - @new_resource.start_command("/etc/init.d/chef startyousillysally") - @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/init.d/chef startyousillysally") - end - - it "should still pass all why run assertions" do - lambda { @provider.run_action(:start) }.should_not raise_error - end - end -end diff --git a/spec/unit/provider/service/insserv_service_spec.rb b/spec/unit/provider/service/insserv_service_spec.rb deleted file mode 100644 index 9ed03b519f..0000000000 --- a/spec/unit/provider/service/insserv_service_spec.rb +++ /dev/null @@ -1,75 +0,0 @@ -# -# Author:: Bryan McLellan <btm@loftninjas.org> -# Copyright:: Copyright (c) 2011 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::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"} - - @new_resource = Chef::Resource::Service.new("initgrediant") - @current_resource = Chef::Resource::Service.new("initgrediant") - - @provider = Chef::Provider::Service::Insserv.new(@new_resource, @run_context) - @status = double("Process::Status mock", :exitstatus => 0, :stdout => "") - @provider.stub(:shell_out!).and_return(@status) - end - - describe "load_current_resource" do - describe "when startup links exist" do - before do - Dir.stub(:glob).with("/etc/rc**/S*initgrediant").and_return(["/etc/rc5.d/S18initgrediant", "/etc/rc2.d/S18initgrediant", "/etc/rc4.d/S18initgrediant", "/etc/rc3.d/S18initgrediant"]) - end - - it "sets the current enabled status to true" do - @provider.load_current_resource - @provider.current_resource.enabled.should be_true - end - end - - describe "when startup links do not exist" do - before do - Dir.stub(:glob).with("/etc/rc**/S*initgrediant").and_return([]) - end - - it "sets the current enabled status to false" do - @provider.load_current_resource - @provider.current_resource.enabled.should be_false - end - end - - end - - describe "enable_service" do - it "should call insserv and create the default links" do - @provider.should_receive(:shell_out!).with("/sbin/insserv -r -f #{@new_resource.service_name}") - @provider.should_receive(:shell_out!).with("/sbin/insserv -d -f #{@new_resource.service_name}") - @provider.enable_service - end - end - - describe "disable_service" do - it "should call insserv and remove the links" do - @provider.should_receive(:shell_out!).with("/sbin/insserv -r -f #{@new_resource.service_name}") - @provider.disable_service - end - end -end diff --git a/spec/unit/provider/service/invokercd_service_spec.rb b/spec/unit/provider/service/invokercd_service_spec.rb deleted file mode 100644 index d8a9851837..0000000000 --- a/spec/unit/provider/service/invokercd_service_spec.rb +++ /dev/null @@ -1,211 +0,0 @@ -# -# Author:: AJ Christensen (<aj@hjksolutions.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' - -describe Chef::Provider::Service::Invokercd, "load_current_resource" do - before(:each) do - @node = Chef::Node.new - @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") - - @current_resource = Chef::Resource::Service.new("chef") - - @provider = Chef::Provider::Service::Invokercd.new(@new_resource, @run_context) - Chef::Resource::Service.stub(:new).and_return(@current_resource) - - @stdout = StringIO.new(<<-PS) -aj 7842 5057 0 21:26 pts/2 00:00:06 vi init.rb -aj 7903 5016 0 21:26 pts/5 00:00:00 /bin/bash -aj 8119 6041 0 21:34 pts/3 00:00:03 vi init_service_spec.rb -PS - @status = double("Status", :exitstatus => 0, :stdout => @stdout) - @provider.stub(:shell_out!).and_return(@status) - end - - it "should create a current resource with the name of the new resource" do - @provider.load_current_resource - @provider.current_resource.should equal(@current_resource) - end - - it "should set the current resources service name to the new resources service name" do - @provider.load_current_resource - @current_resource.service_name.should == 'chef' - end - - describe "when the service supports status" do - before do - @new_resource.supports({:status => true}) - end - - it "should run '/usr/sbin/invoke-rc.d service_name status'" do - @provider.should_receive(:shell_out).with("/usr/sbin/invoke-rc.d #{@current_resource.service_name} status").and_return(@status) - @provider.load_current_resource - end - - it "should set running to true if the status command returns 0" do - @provider.stub(:shell_out).with("/usr/sbin/invoke-rc.d #{@current_resource.service_name} status").and_return(@status) - @provider.load_current_resource - @current_resource.running.should be_true - end - - it "should set running to false if the status command returns anything except 0" do - @status.stub(:exitstatus).and_return(1) - @provider.stub(:shell_out).with("/usr/sbin/invoke-rc.d #{@current_resource.service_name} status").and_return(@status) - @provider.load_current_resource - @current_resource.running.should be_false - end - - it "should set running to false if the status command raises" do - @provider.stub(:shell_out).with("/usr/sbin/invoke-rc.d #{@current_resource.service_name} status").and_raise(Mixlib::ShellOut::ShellCommandFailed) - @provider.load_current_resource - @current_resource.running.should be_false - end - end - - describe "when a status command has been specified" do - before do - @new_resource.stub(:status_command).and_return("/usr/sbin/invoke-rc.d chefhasmonkeypants status") - end - - it "should run the services status command if one has been specified" do - @provider.should_receive(:shell_out).with("/usr/sbin/invoke-rc.d chefhasmonkeypants status").and_return(@status) - @provider.load_current_resource - end - - end - - 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} - @provider.action = :start - @provider.define_resource_requirements - lambda { @provider.process_resource_requirements }.should 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 => ""} - @provider.action = :start - @provider.define_resource_requirements - lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) - end - - end - - describe "when we have a 'ps' attribute" do - it "should shell_out! the node's ps command" do - @status = double("Status", :exitstatus => 0, :stdout => @stdout) - @provider.should_receive(:shell_out!).with(@node[:command][:ps]).and_return(@status) - @provider.load_current_resource - end - - it "should set running to true if the regex matches the output" do - @stdout = StringIO.new(<<-RUNNING_PS) -aj 7842 5057 0 21:26 pts/2 00:00:06 chef -aj 7842 5057 0 21:26 pts/2 00:00:06 poos -RUNNING_PS - @status = double("Status", :exitstatus => 0, :stdout => @stdout) - @provider.should_receive(:shell_out!).and_return(@status) - @provider.load_current_resource - @current_resource.running.should be_true - end - - it "should set running to false if the regex doesn't match" do - @status = double("Status", :exitstatus => 0, :stdout => @stdout) - @provider.should_receive(:shell_out!).and_return(@status) - @provider.load_current_resource - @current_resource.running.should be_false - end - - it "should raise an exception if ps fails" do - @provider.stub(:shell_out!).and_raise(Mixlib::ShellOut::ShellCommandFailed) - @provider.action = :start - @provider.load_current_resource - @provider.define_resource_requirements - lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) - end - end - - it "should return the current resource" do - @provider.load_current_resource.should eql(@current_resource) - end - - describe "when starting the service" do - it "should call the start command if one is specified" do - @new_resource.start_command("/usr/sbin/invoke-rc.d chef startyousillysally") - @provider.should_receive(:shell_out_with_systems_locale!).with("/usr/sbin/invoke-rc.d chef startyousillysally") - @provider.start_service() - end - - it "should call '/usr/sbin/invoke-rc.d service_name start' if no start command is specified" do - @provider.should_receive(:shell_out_with_systems_locale!).with("/usr/sbin/invoke-rc.d #{@new_resource.service_name} start") - @provider.start_service() - end - end - - describe Chef::Provider::Service::Invokercd, "stop_service" do - it "should call the stop command if one is specified" do - @new_resource.stop_command("/usr/sbin/invoke-rc.d chef itoldyoutostop") - @provider.should_receive(:shell_out_with_systems_locale!).with("/usr/sbin/invoke-rc.d chef itoldyoutostop") - @provider.stop_service() - end - - it "should call '/usr/sbin/invoke-rc.d service_name stop' if no stop command is specified" do - @provider.should_receive(:shell_out_with_systems_locale!).with("/usr/sbin/invoke-rc.d #{@new_resource.service_name} stop") - @provider.stop_service() - end - end - - 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}) - @provider.should_receive(:shell_out_with_systems_locale!).with("/usr/sbin/invoke-rc.d #{@new_resource.service_name} restart") - @provider.restart_service() - end - - it "should call the restart_command if one has been specified" do - @new_resource.restart_command("/usr/sbin/invoke-rc.d chef restartinafire") - @provider.should_receive(:shell_out_with_systems_locale!).with("/usr/sbin/invoke-rc.d #{@new_resource.service_name} restartinafire") - @provider.restart_service() - end - - it "should just call stop, then start when the resource doesn't support restart and no restart_command is specified" do - @provider.should_receive(:stop_service) - @provider.should_receive(:sleep).with(1) - @provider.should_receive(:start_service) - @provider.restart_service() - end - end - - describe "when reloading a service" do - it "should call 'reload' on the service if it supports it" do - @new_resource.supports({:reload => true}) - @provider.should_receive(:shell_out_with_systems_locale!).with("/usr/sbin/invoke-rc.d chef reload") - @provider.reload_service() - end - - it "should should run the user specified reload command if one is specified and the service doesn't support reload" do - @new_resource.reload_command("/usr/sbin/invoke-rc.d chef lollerpants") - @provider.should_receive(:shell_out_with_systems_locale!).with("/usr/sbin/invoke-rc.d chef lollerpants") - @provider.reload_service() - end - end -end diff --git a/spec/unit/provider/service/macosx_spec.rb b/spec/unit/provider/service/macosx_spec.rb deleted file mode 100644 index c5df1e0637..0000000000 --- a/spec/unit/provider/service/macosx_spec.rb +++ /dev/null @@ -1,308 +0,0 @@ -# -# Author:: Igor Afonov <afonov@gmail.com> -# Copyright:: Copyright (c) 2011 Igor Afonov -# 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::Service::Macosx do - describe ".gather_plist_dirs" do - context "when HOME directory is set" do - before do - ENV.stub(:[]).with('HOME').and_return("/User/someuser") - end - - it "includes users's LaunchAgents folder" do - described_class.gather_plist_dirs.should include("#{ENV['HOME']}/Library/LaunchAgents") - end - end - - context "when HOME directory is not set" do - before do - ENV.stub(:[]).with('HOME').and_return(nil) - end - - it "doesn't include user's LaunchAgents folder" do - described_class.gather_plist_dirs.should_not include("~/Library/LaunchAgents") - end - end - end - - context "when service name is given as" do - let(:node) { Chef::Node.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 } - let(:plutil_stdout) { String.new <<-XML } -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> -<plist version="1.0"> -<dict> - <key>Label</key> - <string>io.redis.redis-server</string> -</dict> -</plist> -XML - - ["redis-server", "io.redis.redis-server"].each do |service_name| - before do - Dir.stub(:glob).and_return(["/Users/igor/Library/LaunchAgents/io.redis.redis-server.plist"], []) - provider.stub(:shell_out!). - with("launchctl list", {:group => 1001, :user => 101}). - and_return(double("Status", :stdout => launchctl_stdout)) - provider.stub(:shell_out). - with(/launchctl list /, - {:group => nil, :user => nil}). - and_return(double("Status", - :stdout => launchctl_stdout, :exitstatus => 0)) - provider.stub(:shell_out!). - with(/plutil -convert xml1 -o/). - and_return(double("Status", :stdout => plutil_stdout)) - - File.stub(:stat).and_return(double("stat", :gid => 1001, :uid => 101)) - end - - context "#{service_name}" do - let(:new_resource) { Chef::Resource::Service.new(service_name) } - let!(:current_resource) { Chef::Resource::Service.new(service_name) } - - describe "#load_current_resource" do - - # CHEF-5223 "you can't glob for a file that hasn't been converged - # onto the node yet." - context "when the plist doesn't exist" do - - def run_resource_setup_for_action(action) - new_resource.action(action) - provider.action = action - provider.load_current_resource - provider.define_resource_requirements - provider.process_resource_requirements - end - - before do - Dir.stub(:glob).and_return([]) - provider.stub(:shell_out!). - with(/plutil -convert xml1 -o/). - and_raise(Mixlib::ShellOut::ShellCommandFailed) - end - - it "works for action :nothing" do - lambda { run_resource_setup_for_action(:nothing) }.should_not raise_error - end - - it "works for action :start" do - lambda { run_resource_setup_for_action(:start) }.should_not raise_error - end - - it "errors if action is :enable" do - lambda { run_resource_setup_for_action(:enable) }.should raise_error(Chef::Exceptions::Service) - end - - it "errors if action is :disable" do - lambda { run_resource_setup_for_action(:disable) }.should raise_error(Chef::Exceptions::Service) - end - end - - context "when launchctl returns pid in service list" do - let(:launchctl_stdout) { StringIO.new <<-SVC_LIST } - 12761 - 0x100114220.old.machinit.thing - 7777 - io.redis.redis-server - - - com.lol.stopped-thing - SVC_LIST - - before do - provider.load_current_resource - end - - it "sets resource running state to true" do - provider.current_resource.running.should be_true - end - - it "sets resouce enabled state to true" do - provider.current_resource.enabled.should be_true - end - end - - describe "running unsupported actions" do - let(:launchctl_stdout) { StringIO.new <<-SVC_LIST } -12761 - 0x100114220.old.machinit.thing -7777 - io.redis.redis-server -- - com.lol.stopped-thing -SVC_LIST - - before do - Dir.stub(:glob).and_return(["/Users/igor/Library/LaunchAgents/io.redis.redis-server.plist"], []) - end - it "should throw an exception when reload action is attempted" do - lambda {provider.run_action(:reload)}.should raise_error(Chef::Exceptions::UnsupportedAction) - end - end - context "when launchctl returns empty service pid" do - let(:launchctl_stdout) { StringIO.new <<-SVC_LIST } - 12761 - 0x100114220.old.machinit.thing - - - io.redis.redis-server - - - com.lol.stopped-thing - SVC_LIST - - before do - provider.load_current_resource - end - - it "sets resource running state to false" do - provider.current_resource.running.should be_false - end - - it "sets resouce enabled state to true" do - provider.current_resource.enabled.should be_true - end - end - - context "when launchctl doesn't return service entry at all" do - let(:launchctl_stdout) { StringIO.new <<-SVC_LIST } - 12761 - 0x100114220.old.machinit.thing - - - com.lol.stopped-thing - SVC_LIST - - it "sets service running state to false" do - provider.load_current_resource - provider.current_resource.running.should be_false - end - - context "and plist for service is not available" do - before do - Dir.stub(:glob).and_return([]) - provider.load_current_resource - end - - it "sets resouce enabled state to false" do - provider.current_resource.enabled.should be_false - end - end - - context "and plist for service is available" do - before do - Dir.stub(:glob).and_return(["/Users/igor/Library/LaunchAgents/io.redis.redis-server.plist"], []) - provider.load_current_resource - end - - it "sets resouce enabled state to true" do - provider.current_resource.enabled.should be_true - end - end - - describe "and several plists match service name" do - it "throws exception" do - Dir.stub(:glob).and_return(["/Users/igor/Library/LaunchAgents/io.redis.redis-server.plist", - "/Users/wtf/something.plist"]) - provider.load_current_resource - provider.define_resource_requirements - lambda { provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) - end - end - end - end - describe "#start_service" do - before do - Chef::Resource::Service.stub(:new).and_return(current_resource) - provider.load_current_resource - current_resource.stub(:running).and_return(false) - end - - it "calls the start command if one is specified and service is not running" do - new_resource.stub(:start_command).and_return("cowsay dirty") - - provider.should_receive(:shell_out_with_systems_locale!).with("cowsay dirty") - provider.start_service - end - - it "shows warning message if service is already running" do - current_resource.stub(:running).and_return(true) - Chef::Log.should_receive(:debug).with("service[#{service_name}] already running, not starting") - - provider.start_service - end - - it "starts service via launchctl if service found" do - provider.should_receive(:shell_out_with_systems_locale!). - with("launchctl load -w '/Users/igor/Library/LaunchAgents/io.redis.redis-server.plist'", - :group => 1001, :user => 101). - and_return(0) - - provider.start_service - end - end - - describe "#stop_service" do - before do - Chef::Resource::Service.stub(:new).and_return(current_resource) - - provider.load_current_resource - current_resource.stub(:running).and_return(true) - end - - it "calls the stop command if one is specified and service is running" do - new_resource.stub(:stop_command).and_return("kill -9 123") - - provider.should_receive(:shell_out_with_systems_locale!).with("kill -9 123") - provider.stop_service - end - - it "shows warning message if service is not running" do - current_resource.stub(:running).and_return(false) - Chef::Log.should_receive(:debug).with("service[#{service_name}] not running, not stopping") - - provider.stop_service - end - - it "stops the service via launchctl if service found" do - provider.should_receive(:shell_out_with_systems_locale!). - with("launchctl unload '/Users/igor/Library/LaunchAgents/io.redis.redis-server.plist'", - :group => 1001, :user => 101). - and_return(0) - - provider.stop_service - end - end - - describe "#restart_service" do - before do - Chef::Resource::Service.stub(:new).and_return(current_resource) - - provider.load_current_resource - current_resource.stub(:running).and_return(true) - provider.stub(:sleep) - end - - it "issues a command if given" do - new_resource.stub(:restart_command).and_return("reload that thing") - - provider.should_receive(:shell_out_with_systems_locale!).with("reload that thing") - provider.restart_service - end - - it "stops and then starts service" do - provider.should_receive(:stop_service) - provider.should_receive(:start_service); - - provider.restart_service - end - end - end - end - end -end diff --git a/spec/unit/provider/service/redhat_spec.rb b/spec/unit/provider/service/redhat_spec.rb deleted file mode 100644 index 8cc6fb6549..0000000000 --- a/spec/unit/provider/service/redhat_spec.rb +++ /dev/null @@ -1,156 +0,0 @@ -# -# Author:: AJ Christensen (<aj@hjksolutions.com>) -# Copyright:: Copyright (c) 2008 HJK Solutions, LLC -# 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 File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "spec_helper")) -require 'ostruct' - -shared_examples_for "define_resource_requirements_common" do - it "should raise an error if /sbin/chkconfig does not exist" do - File.stub(:exists?).with("/sbin/chkconfig").and_return(false) - @provider.stub(:shell_out).with("/sbin/service chef status").and_raise(Errno::ENOENT) - @provider.stub(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_raise(Errno::ENOENT) - @provider.load_current_resource - @provider.define_resource_requirements - lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) - end - - it "should not raise an error if the service exists but is not added to any runlevels" do - status = double("Status", :exitstatus => 0, :stdout => "" , :stderr => "") - @provider.should_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')") - @provider.should_receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_return(chkconfig) - @provider.load_current_resource - @provider.define_resource_requirements - lambda { @provider.process_resource_requirements }.should_not raise_error - end -end - -describe "Chef::Provider::Service::Redhat" do - - before(:each) do - @node = Chef::Node.new - @node.automatic_attrs[:command] = {:ps => 'foo'} - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - - @new_resource = Chef::Resource::Service.new("chef") - - @current_resource = Chef::Resource::Service.new("chef") - - @provider = Chef::Provider::Service::Redhat.new(@new_resource, @run_context) - @provider.action = :start - Chef::Resource::Service.stub(:new).and_return(@current_resource) - File.stub(:exists?).with("/sbin/chkconfig").and_return(true) - end - - describe "while not in why run mode" do - before(:each) do - Chef::Config[:why_run] = false - end - - describe "load current resource" do - it "sets the current enabled status to true if the service is enabled for any run level" do - status = double("Status", :exitstatus => 0, :stdout => "" , :stderr => "") - @provider.should_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:on 6:off", :stderr => "") - @provider.should_receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_return(chkconfig) - @provider.instance_variable_get("@service_missing").should be_false - @provider.load_current_resource - @current_resource.enabled.should 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 => "") - @provider.should_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 => "") - @provider.should_receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_return(chkconfig) - @provider.instance_variable_get("@service_missing").should be_false - @provider.load_current_resource.should eql(@current_resource) - @current_resource.enabled.should be_false - end - end - - describe "define resource requirements" do - it_should_behave_like "define_resource_requirements_common" - - context "when the service does not exist" do - before do - status = double("Status", :exitstatus => 1, :stdout => "", :stderr => "chef: unrecognized service") - @provider.should_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") - @provider.should_receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_return(chkconfig) - @provider.load_current_resource - @provider.define_resource_requirements - end - - [ "start", "reload", "restart", "enable" ].each do |action| - it "should raise an error when the action is #{action}" do - @provider.action = action - lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) - end - end - - [ "stop", "disable" ].each do |action| - it "should not raise an error when the action is #{action}" do - @provider.action = action - lambda { @provider.process_resource_requirements }.should_not raise_error - end - end - end - end - end - - describe "while in why run mode" do - before(:each) do - Chef::Config[:why_run] = true - end - - after do - Chef::Config[:why_run] = false - end - - describe "define resource requirements" do - it_should_behave_like "define_resource_requirements_common" - - it "should not raise an error if the service does not exist" do - status = double("Status", :exitstatus => 1, :stdout => "", :stderr => "chef: unrecognized service") - @provider.should_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") - @provider.should_receive(:shell_out!).with("/sbin/chkconfig --list chef", :returns => [0,1]).and_return(chkconfig) - @provider.load_current_resource - @provider.define_resource_requirements - lambda { @provider.process_resource_requirements }.should_not raise_error - end - end - end - - describe "enable_service" do - it "should call chkconfig to add 'service_name'" do - @provider.should_receive(:shell_out!).with("/sbin/chkconfig #{@new_resource.service_name} on") - @provider.enable_service - end - end - - describe "disable_service" do - it "should call chkconfig to del 'service_name'" do - @provider.should_receive(:shell_out!).with("/sbin/chkconfig #{@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 deleted file mode 100644 index 11ebf74725..0000000000 --- a/spec/unit/provider/service/simple_service_spec.rb +++ /dev/null @@ -1,169 +0,0 @@ -# -# Author:: Mathieu Sauve-Frankel <msf@kisoku.net> -# Copyright:: Copyright (c) 2009, Mathieu Sauve Frankel -# 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::Service::Simple, "load_current_resource" do - before(:each) do - @node = Chef::Node.new - @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") - @current_resource = Chef::Resource::Service.new("chef") - - @provider = Chef::Provider::Service::Simple.new(@new_resource, @run_context) - Chef::Resource::Service.stub(:new).and_return(@current_resource) - - @stdout = StringIO.new(<<-NOMOCKINGSTRINGSPLZ) -aj 7842 5057 0 21:26 pts/2 00:00:06 vi init.rb -aj 7903 5016 0 21:26 pts/5 00:00:00 /bin/bash -aj 8119 6041 0 21:34 pts/3 00:00:03 vi simple_service_spec.rb -NOMOCKINGSTRINGSPLZ - @status = double("Status", :exitstatus => 0, :stdout => @stdout) - @provider.stub(:shell_out!).and_return(@status) - end - - it "should create a current resource with the name of the new resource" do - Chef::Resource::Service.should_receive(:new).and_return(@current_resource) - @provider.load_current_resource - end - - it "should set the current resources service name to the new resources service name" do - @current_resource.should_receive(:service_name).with(@new_resource.service_name) - @provider.load_current_resource - 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} - @provider.define_resource_requirements - lambda { @provider.process_resource_requirements }.should 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 => ""} - @provider.define_resource_requirements - lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) - end - - describe "when we have a 'ps' attribute" do - it "should shell_out! the node's ps command" do - @provider.should_receive(:shell_out!).with(@node[:command][:ps]).and_return(@status) - @provider.load_current_resource - end - - it "should read stdout of the ps command" do - @provider.stub(:shell_out!).and_return(@status) - @stdout.should_receive(:each_line).and_return(true) - @provider.load_current_resource - end - - it "should set running to true if the regex matches the output" do - @stdout = StringIO.new(<<-NOMOCKINGSTRINGSPLZ) -aj 7842 5057 0 21:26 pts/2 00:00:06 chef -aj 7842 5057 0 21:26 pts/2 00:00:06 poos -NOMOCKINGSTRINGSPLZ - @status = double("Status", :exitstatus => 0, :stdout => @stdout) - @provider.stub(:shell_out!).and_return(@status) - @provider.load_current_resource - @current_resource.running.should be_true - end - - it "should set running to false if the regex doesn't match" do - @provider.stub(:shell_out!).and_return(@status) - @provider.load_current_resource - @current_resource.running.should be_false - end - - it "should raise an exception if ps fails" do - @provider.stub(:shell_out!).and_raise(Mixlib::ShellOut::ShellCommandFailed) - @provider.action = :start - @provider.load_current_resource - @provider.define_resource_requirements - lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) - end - end - - it "should return the current resource" do - @provider.load_current_resource.should eql(@current_resource) - end - - describe "when starting the service" do - it "should call the start command if one is specified" do - @new_resource.stub(:start_command).and_return("#{@new_resource.start_command}") - @provider.should_receive(:shell_out_with_systems_locale!).with("#{@new_resource.start_command}") - @provider.start_service() - end - - it "should raise an exception if no start command is specified" do - @provider.define_resource_requirements - @provider.action = :start - lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) - end - end - - describe "when stopping a service" do - it "should call the stop command if one is specified" do - @new_resource.stop_command("/etc/init.d/themadness stop") - @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/init.d/themadness stop") - @provider.stop_service() - end - - it "should raise an exception if no stop command is specified" do - @provider.define_resource_requirements - @provider.action = :stop - lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) - end - end - - describe Chef::Provider::Service::Simple, "restart_service" do - it "should call the restart command if one has been specified" do - @new_resource.restart_command("/etc/init.d/foo restart") - @provider.should_receive(:shell_out_with_systems_locale!).with("/etc/init.d/foo restart") - @provider.restart_service() - end - - it "should raise an exception if the resource doesn't support restart, no restart command is provided, and no stop command is provided" do - @provider.define_resource_requirements - @provider.action = :restart - lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::Service) - end - - it "should just call stop, then start when the resource doesn't support restart and no restart_command is specified" do - @provider.should_receive(:stop_service) - @provider.should_receive(:sleep).with(1) - @provider.should_receive(:start_service) - @provider.restart_service() - end - end - - describe Chef::Provider::Service::Simple, "reload_service" do - it "should raise an exception if reload is requested but no command is specified" do - @provider.define_resource_requirements - @provider.action = :reload - lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::UnsupportedAction) - end - - it "should should run the user specified reload command if one is specified" do - @new_resource.reload_command("kill -9 1") - @provider.should_receive(:shell_out_with_systems_locale!).with("kill -9 1") - @provider.reload_service() - end - end -end diff --git a/spec/unit/provider/service/solaris_smf_service_spec.rb b/spec/unit/provider/service/solaris_smf_service_spec.rb deleted file mode 100644 index 8df22efa7e..0000000000 --- a/spec/unit/provider/service/solaris_smf_service_spec.rb +++ /dev/null @@ -1,187 +0,0 @@ -# -# Author:: Toomas Pelberg (<toomasp@gmx.net>) -# 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. -# - -require 'spec_helper' - -describe Chef::Provider::Service::Solaris do - before(:each) do - @node =Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - - @new_resource = Chef::Resource::Service.new('chef') - - @current_resource = Chef::Resource::Service.new('chef') - - @provider = Chef::Provider::Service::Solaris.new(@new_resource, @run_context) - Chef::Resource::Service.stub(:new).and_return(@current_resource) - - @stdin = StringIO.new - @stdout = StringIO.new - @stderr = StringIO.new - @pid = 2342 - @stdout_string = "state disabled" - @stdout.stub(:gets).and_return(@stdout_string) - @status = double("Status", :exitstatus => 0, :stdout => @stdout) - @provider.stub(:shell_out!).and_return(@status) - end - - it "should raise an error if /bin/svcs does not exist" do - File.should_receive(:exists?).with("/bin/svcs").and_return(false) - lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::Service) - end - - describe "on a host with /bin/svcs" do - - before do - File.stub(:exists?).with('/bin/svcs').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 - @provider.stub(:shell_out!).with("/bin/svcs -l chef").and_return(@status) - Chef::Resource::Service.should_receive(:new).and_return(@current_resource) - @provider.load_current_resource - end - - it "should return the current resource" do - @provider.stub(:shell_out!).with("/bin/svcs -l chef").and_return(@status) - @provider.load_current_resource.should eql(@current_resource) - end - - it "should call '/bin/svcs -l service_name'" do - @provider.should_receive(:shell_out!).with("/bin/svcs -l chef", {:returns=>[0, 1]}).and_return(@status) - @provider.load_current_resource - end - - it "should mark service as not running" do - @provider.stub(:shell_out!).and_return(@status) - @current_resource.should_receive(:running).with(false) - @provider.load_current_resource - end - - it "should mark service as running" do - @status = double("Status", :exitstatus => 0, :stdout => 'state online') - @provider.stub(:shell_out!).and_return(@status) - @current_resource.should_receive(:running).with(true) - @provider.load_current_resource - end - - it "should not mark service as maintenance" do - @provider.stub(:shell_out!).and_return(@status) - @provider.load_current_resource - @provider.maintenance.should be_false - end - - it "should mark service as maintenance" do - @status = double("Status", :exitstatus => 0, :stdout => 'state maintenance') - @provider.stub(:shell_out!).and_return(@status) - @provider.load_current_resource - @provider.maintenance.should be_true - end - end - - 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 - @new_resource.stub(:enable_command).and_return("#{@new_resource.enable_command}") - @provider.should_not_receive(:shell_out!).with("/usr/sbin/svcadm clear #{@current_resource.service_name}") - @provider.should_receive(:shell_out!).with("/usr/sbin/svcadm enable -s #{@current_resource.service_name}").and_return(@status) - @provider.enable_service.should be_true - @current_resource.enabled.should be_true - end - - it "should call svcadm enable -s chef for start_service" do - @new_resource.stub(:start_command).and_return("#{@new_resource.start_command}") - @provider.should_not_receive(:shell_out!).with("/usr/sbin/svcadm clear #{@current_resource.service_name}") - @provider.should_receive(:shell_out!).with("/usr/sbin/svcadm enable -s #{@current_resource.service_name}").and_return(@status) - @provider.start_service.should be_true - @current_resource.enabled.should be_true - end - - it "should call svcadm clear chef for start_service when state maintenance" do - @status = double("Status", :exitstatus => 0, :stdout => 'state maintenance') - @provider.stub(:shell_out!).and_return(@status) - @provider.load_current_resource - @new_resource.stub(:enable_command).and_return("#{@new_resource.enable_command}") - @provider.should_receive(:shell_out!).with("/usr/sbin/svcadm clear #{@current_resource.service_name}").and_return(@status) - @provider.should_receive(:shell_out!).with("/usr/sbin/svcadm enable -s #{@current_resource.service_name}").and_return(@status) - @provider.enable_service.should be_true - @current_resource.enabled.should be_true - end - end - - 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 - @provider.should_receive(:shell_out!).with("/usr/sbin/svcadm disable -s chef").and_return(@status) - @provider.disable_service.should be_true - @current_resource.enabled.should be_false - end - - it "should call svcadm disable -s chef for stop_service" do - @provider.should_receive(:shell_out!).with("/usr/sbin/svcadm disable -s chef").and_return(@status) - @provider.stop_service.should be_true - @current_resource.enabled.should be_false - end - - end - - describe "when reloading the service" do - before(:each) do - @status = double("Process::Status", :exitstatus => 0) - @provider.current_resource = @current_resource - end - - it "should call svcadm refresh chef" do - @provider.should_receive(:shell_out_with_systems_locale!).with("/usr/sbin/svcadm refresh chef").and_return(@status) - @provider.reload_service - end - - end - - 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 - end - - it "should be marked not running" do - @provider.should_receive(:shell_out!).with("/bin/svcs -l chef", {:returns=>[0, 1]}).and_return(@status) - @provider.service_status - @current_resource.running.should be_false - end - - it "should be marked not enabled" do - @provider.should_receive(:shell_out!).with("/bin/svcs -l chef", {:returns=>[0, 1]}).and_return(@status) - @provider.service_status - @current_resource.enabled.should be_false - end - - end - end -end diff --git a/spec/unit/provider/service/systemd_service_spec.rb b/spec/unit/provider/service/systemd_service_spec.rb deleted file mode 100644 index 7358f63b5e..0000000000 --- a/spec/unit/provider/service/systemd_service_spec.rb +++ /dev/null @@ -1,256 +0,0 @@ -# -# Author:: Stephen Haynes (<sh@nomitor.com>) -# Copyright:: Copyright (c) 2011 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::Service::Systemd do - before(:each) do - @node = Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - @new_resource = Chef::Resource::Service.new('rsyslog.service') - @provider = Chef::Provider::Service::Systemd.new(@new_resource, @run_context) - - @shell_out_success = double('shell_out_with_systems_locale', - :exitstatus => 0, :error? => false) - @shell_out_failure = double('shell_out_with_systems_locale', - :exitstatus => 1, :error? => true) - end - - describe "load_current_resource" do - before(:each) do - @current_resource = Chef::Resource::Service.new('rsyslog.service') - Chef::Resource::Service.stub(:new).and_return(@current_resource) - - @provider.stub(:is_active?).and_return(false) - @provider.stub(:is_enabled?).and_return(false) - end - - it "should create a current resource with the name of the new resource" do - Chef::Resource::Service.should_receive(:new).and_return(@current_resource) - @provider.load_current_resource - end - - it "should set the current resources service name to the new resources service name" do - @current_resource.should_receive(:service_name).with(@new_resource.service_name) - @provider.load_current_resource - end - - it "should check if the service is running" do - @provider.should_receive(:is_active?) - @provider.load_current_resource - end - - it "should set running to true if the service is running" do - @provider.stub(:is_active?).and_return(true) - @current_resource.should_receive(:running).with(true) - @provider.load_current_resource - end - - it "should set running to false if the service is not running" do - @provider.stub(:is_active?).and_return(false) - @current_resource.should_receive(:running).with(false) - @provider.load_current_resource - end - - describe "when a status command has been specified" do - before do - @new_resource.stub(:status_command).and_return("/bin/chefhasmonkeypants status") - end - - it "should run the services status command if one has been specified" do - @provider.stub(:shell_out).and_return(@shell_out_success) - @current_resource.should_receive(:running).with(true) - @provider.load_current_resource - end - - it "should run the services status command if one has been specified and properly set status check state" do - @provider.stub(:shell_out).with("/bin/chefhasmonkeypants status").and_return(@shell_out_success) - @provider.load_current_resource - @provider.instance_variable_get("@status_check_success").should be_true - end - - it "should set running to false if a status command fails" do - @provider.stub(:shell_out).and_return(@shell_out_failure) - @current_resource.should_receive(:running).with(false) - @provider.load_current_resource - end - - it "should update state to indicate status check failed when a status command fails" do - @provider.stub(:shell_out).and_return(@shell_out_failure) - @provider.load_current_resource - @provider.instance_variable_get("@status_check_success").should be_false - end - end - - it "should check if the service is enabled" do - @provider.should_receive(:is_enabled?) - @provider.load_current_resource - end - - it "should set enabled to true if the service is enabled" do - @provider.stub(:is_enabled?).and_return(true) - @current_resource.should_receive(:enabled).with(true) - @provider.load_current_resource - end - - it "should set enabled to false if the service is not enabled" do - @provider.stub(:is_enabled?).and_return(false) - @current_resource.should_receive(:enabled).with(false) - @provider.load_current_resource - end - - it "should return the current resource" do - @provider.load_current_resource.should eql(@current_resource) - end - end - - describe "start and stop service" do - before(:each) do - @current_resource = Chef::Resource::Service.new('rsyslog.service') - Chef::Resource::Service.stub(:new).and_return(@current_resource) - @provider.current_resource = @current_resource - end - - it "should call the start command if one is specified" do - @new_resource.stub(:start_command).and_return("/sbin/rsyslog startyousillysally") - @provider.should_receive(:shell_out_with_systems_locale!).with("/sbin/rsyslog startyousillysally") - @provider.start_service - end - - it "should call '/bin/systemctl start service_name' if no start command is specified" do - @provider.should_receive(:shell_out_with_systems_locale!).with("/bin/systemctl start #{@new_resource.service_name}").and_return(@shell_out_success) - @provider.start_service - end - - it "should not call '/bin/systemctl start service_name' if it is already running" do - @current_resource.stub(:running).and_return(true) - @provider.should_not_receive(:shell_out_with_systems_locale!).with("/bin/systemctl start #{@new_resource.service_name}") - @provider.start_service - end - - it "should call the restart command if one is specified" do - @current_resource.stub(:running).and_return(true) - @new_resource.stub(:restart_command).and_return("/sbin/rsyslog restartyousillysally") - @provider.should_receive(:shell_out_with_systems_locale!).with("/sbin/rsyslog restartyousillysally") - @provider.restart_service - end - - it "should call '/bin/systemctl restart service_name' if no restart command is specified" do - @current_resource.stub(:running).and_return(true) - @provider.should_receive(:shell_out_with_systems_locale!).with("/bin/systemctl restart #{@new_resource.service_name}").and_return(@shell_out_success) - @provider.restart_service - end - - describe "reload service" do - context "when a reload command is specified" do - it "should call the reload command" do - @current_resource.stub(:running).and_return(true) - @new_resource.stub(:reload_command).and_return("/sbin/rsyslog reloadyousillysally") - @provider.should_receive(:shell_out_with_systems_locale!).with("/sbin/rsyslog reloadyousillysally") - @provider.reload_service - end - end - - context "when a reload command is not specified" do - it "should call '/bin/systemctl reload service_name' if the service is running" do - @current_resource.stub(:running).and_return(true) - @provider.should_receive(:shell_out_with_systems_locale!).with("/bin/systemctl reload #{@new_resource.service_name}").and_return(@shell_out_success) - @provider.reload_service - end - - it "should start the service if the service is not running" do - @current_resource.stub(:running).and_return(false) - @provider.should_receive(:start_service).and_return(true) - @provider.reload_service - end - end - end - - it "should call the stop command if one is specified" do - @current_resource.stub(:running).and_return(true) - @new_resource.stub(:stop_command).and_return("/sbin/rsyslog stopyousillysally") - @provider.should_receive(:shell_out_with_systems_locale!).with("/sbin/rsyslog stopyousillysally") - @provider.stop_service - end - - it "should call '/bin/systemctl stop service_name' if no stop command is specified" do - @current_resource.stub(:running).and_return(true) - @provider.should_receive(:shell_out_with_systems_locale!).with("/bin/systemctl stop #{@new_resource.service_name}").and_return(@shell_out_success) - @provider.stop_service - end - - it "should not call '/bin/systemctl stop service_name' if it is already stopped" do - @current_resource.stub(:running).and_return(false) - @provider.should_not_receive(:shell_out_with_systems_locale!).with("/bin/systemctl stop #{@new_resource.service_name}") - @provider.stop_service - end - end - - describe "enable and disable service" do - before(:each) do - @current_resource = Chef::Resource::Service.new('rsyslog.service') - Chef::Resource::Service.stub(:new).and_return(@current_resource) - @provider.current_resource = @current_resource - end - - it "should call '/bin/systemctl enable service_name' to enable the service" do - @provider.should_receive(:shell_out!).with("/bin/systemctl enable #{@new_resource.service_name}").and_return(@shell_out_success) - @provider.enable_service - end - - it "should call '/bin/systemctl disable service_name' to disable the service" do - @provider.should_receive(:shell_out!).with("/bin/systemctl disable #{@new_resource.service_name}").and_return(@shell_out_success) - @provider.disable_service - end - end - - describe "is_active?" do - before(:each) do - @current_resource = Chef::Resource::Service.new('rsyslog.service') - Chef::Resource::Service.stub(:new).and_return(@current_resource) - end - - it "should return true if '/bin/systemctl is-active service_name' returns 0" do - @provider.should_receive(:shell_out).with('/bin/systemctl is-active rsyslog.service --quiet').and_return(@shell_out_success) - @provider.is_active?.should be_true - end - - it "should return false if '/bin/systemctl is-active service_name' returns anything except 0" do - @provider.should_receive(:shell_out).with('/bin/systemctl is-active rsyslog.service --quiet').and_return(@shell_out_failure) - @provider.is_active?.should be_false - end - end - - describe "is_enabled?" do - before(:each) do - @current_resource = Chef::Resource::Service.new('rsyslog.service') - Chef::Resource::Service.stub(:new).and_return(@current_resource) - end - - it "should return true if '/bin/systemctl is-enabled service_name' returns 0" do - @provider.should_receive(:shell_out).with('/bin/systemctl is-enabled rsyslog.service --quiet').and_return(@shell_out_success) - @provider.is_enabled?.should be_true - end - - it "should return false if '/bin/systemctl is-enabled service_name' returns anything except 0" do - @provider.should_receive(:shell_out).with('/bin/systemctl is-enabled rsyslog.service --quiet').and_return(@shell_out_failure) - @provider.is_enabled?.should be_false - end - end -end diff --git a/spec/unit/provider/service/upstart_service_spec.rb b/spec/unit/provider/service/upstart_service_spec.rb deleted file mode 100644 index 499a794ff4..0000000000 --- a/spec/unit/provider/service/upstart_service_spec.rb +++ /dev/null @@ -1,319 +0,0 @@ -# -# Author:: Bryan McLellan (btm@loftninjas.org) -# Copyright:: Copyright (c) 2010 Bryan McLellan -# 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::Service::Upstart do - before(:each) do - @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) - - @new_resource = Chef::Resource::Service.new("rsyslog") - @provider = Chef::Provider::Service::Upstart.new(@new_resource, @run_context) - end - - describe "when first created" do - before do - @platform = nil - 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' - #Chef::Platform.stub(:find_platform_and_version).and_return([ "ubuntu", "9.04" ]) - @provider = Chef::Provider::Service::Upstart.new(@new_resource, @run_context) - @provider.instance_variable_get(:@upstart_job_dir).should == "/etc/event.d" - @provider.instance_variable_get(:@upstart_conf_suffix).should == "" - 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' - @provider = Chef::Provider::Service::Upstart.new(@new_resource, @run_context) - @provider.instance_variable_get(:@upstart_job_dir).should == "/etc/init" - @provider.instance_variable_get(:@upstart_conf_suffix).should == ".conf" - end - - it "should return /etc/init as the upstart job directory by default" do - @node.automatic_attrs[:platform_version] = '9000' - @provider = Chef::Provider::Service::Upstart.new(@new_resource, @run_context) - @provider.instance_variable_get(:@upstart_job_dir).should == "/etc/init" - @provider.instance_variable_get(:@upstart_conf_suffix).should == ".conf" - end - end - - describe "load_current_resource" do - before(:each) do - @node.automatic_attrs[:command] = {:ps => "ps -ax"} - - @current_resource = Chef::Resource::Service.new("rsyslog") - Chef::Resource::Service.stub(:new).and_return(@current_resource) - - @status = double("Status", :exitstatus => 0) - @provider.stub(:popen4).and_return(@status) - @stdin = StringIO.new - @stdout = StringIO.new - @stderr = StringIO.new - @pid = double("PID") - - ::File.stub(:exists?).and_return(true) - ::File.stub(:open).and_return(true) - end - - it "should create a current resource with the name of the new resource" do - Chef::Resource::Service.should_receive(:new).and_return(@current_resource) - @provider.load_current_resource - end - - it "should set the current resources service name to the new resources service name" do - @current_resource.should_receive(:service_name).with(@new_resource.service_name) - @provider.load_current_resource - end - - it "should not change the service name when parameters are specified" do - @new_resource.parameters({ "OSD_ID" => "2" }) - @provider = Chef::Provider::Service::Upstart.new(@new_resource, @run_context) - @provider.current_resource = @current_resource - @new_resource.service_name.should == @current_resource.service_name - end - - it "should run '/sbin/status rsyslog'" do - @provider.should_receive(:popen4).with("/sbin/status rsyslog").and_return(@status) - @provider.load_current_resource - end - - describe "when the status command uses the new format" do - before do - end - - it "should set running to true if the status command returns 0" do - @stdout = StringIO.new("rsyslog start/running") - @provider.stub(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @provider.load_current_resource - @current_resource.running.should be_true - end - - it "should set running to false if the status command returns anything except 0" do - @stdout = StringIO.new("rsyslog stop/waiting") - @provider.stub(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @provider.load_current_resource - @current_resource.running.should be_false - 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") - @provider.stub(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @provider.load_current_resource - @current_resource.running.should be_true - end - - it "should set running to false if the status command returns anything except 0" do - @stdout = StringIO.new("rsyslog (stop) waiting") - @provider.stub(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @provider.load_current_resource - @current_resource.running.should be_false - end - end - - it "should set running to false if it catches a Chef::Exceptions::Exec" do - @provider.stub(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_raise(Chef::Exceptions::Exec) - @current_resource.should_receive(:running).with(false) - @provider.load_current_resource - end - - it "should set enabled to true when it finds 'starts on'" do - @lines = double("start on filesystem", :gets => "start on filesystem") - ::File.stub(:open).and_yield(@lines) - @current_resource.should_receive(:running).with(false) - @provider.load_current_resource - end - - it "should set enabled to false when it finds '#starts on'" do - @lines = double("start on filesystem", :gets => "#start on filesystem") - ::File.stub(:open).and_yield(@lines) - @current_resource.should_receive(:running).with(false) - @provider.load_current_resource - end - - it "should assume disable when no job configuration file is found" do - ::File.stub(:exists?).and_return(false) - @current_resource.should_receive(:running).with(false) - @provider.load_current_resource - end - - it "should track state when the upstart configuration file fails to load" do - File.should_receive(:exists?).and_return false - @provider.load_current_resource - @provider.instance_variable_get("@config_file_found").should == false - end - - describe "when a status command has been specified" do - before do - @new_resource.stub(:status_command).and_return("/bin/chefhasmonkeypants status") - end - - it "should run the services status command if one has been specified" do - @provider.stub(:shell_out!).with("/bin/chefhasmonkeypants status").and_return(0) - @current_resource.should_receive(:running).with(true) - @provider.load_current_resource - end - - it "should track state when the user-provided status command fails" do - @provider.stub(:shell_out!).and_raise(Errno::ENOENT) - @provider.load_current_resource - @provider.instance_variable_get("@command_success").should == false - end - - it "should set running to false if it catches a Chef::Exceptions::Exec when using a status command" do - @provider.stub(:shell_out!).and_raise(Errno::ENOENT) - @current_resource.should_receive(:running).with(false) - @provider.load_current_resource - end - end - - it "should track state when we fail to obtain service status via upstart_state" do - @provider.should_receive(:upstart_state).and_raise Chef::Exceptions::Exec - @provider.load_current_resource - @provider.instance_variable_get("@command_success").should == false - end - - it "should return the current resource" do - @provider.load_current_resource.should eql(@current_resource) - end - - end - - describe "enable and disable service" do - before(:each) do - @current_resource = Chef::Resource::Service.new('rsyslog') - Chef::Resource::Service.stub(:new).and_return(@current_resource) - @provider.current_resource = @current_resource - Chef::Util::FileEdit.stub(:new) - end - - it "should enable the service if it is not enabled" do - @file = Object.new - Chef::Util::FileEdit.stub(:new).and_return(@file) - @current_resource.stub(:enabled).and_return(false) - @file.should_receive(:search_file_replace) - @file.should_receive(:write_file) - @provider.enable_service() - end - - it "should disable the service if it is enabled" do - @file = Object.new - Chef::Util::FileEdit.stub(:new).and_return(@file) - @current_resource.stub(:enabled).and_return(true) - @file.should_receive(:search_file_replace) - @file.should_receive(:write_file) - @provider.disable_service() - end - - end - - describe "start and stop service" do - before(:each) do - @current_resource = Chef::Resource::Service.new('rsyslog') - - Chef::Resource::Service.stub(:new).and_return(@current_resource) - @provider.current_resource = @current_resource - end - - it "should call the start command if one is specified" do - @new_resource.stub(:start_command).and_return("/sbin/rsyslog startyousillysally") - @provider.should_receive(:shell_out_with_systems_locale!).with("/sbin/rsyslog startyousillysally") - @provider.start_service() - end - - it "should call '/sbin/start service_name' if no start command is specified" do - @provider.should_receive(:shell_out_with_systems_locale!).with("/sbin/start #{@new_resource.service_name}").and_return(0) - @provider.start_service() - end - - it "should not call '/sbin/start service_name' if it is already running" do - @current_resource.stub(:running).and_return(true) - @provider.should_not_receive(:shell_out_with_systems_locale!) - @provider.start_service() - end - - it "should pass parameters to the start command if they are provided" do - @new_resource = Chef::Resource::Service.new("rsyslog") - @new_resource.parameters({ "OSD_ID" => "2" }) - @provider = Chef::Provider::Service::Upstart.new(@new_resource, @run_context) - @provider.current_resource = @current_resource - @provider.should_receive(:shell_out_with_systems_locale!).with("/sbin/start rsyslog OSD_ID=2").and_return(0) - @provider.start_service() - end - - it "should call the restart command if one is specified" do - @current_resource.stub(:running).and_return(true) - @new_resource.stub(:restart_command).and_return("/sbin/rsyslog restartyousillysally") - @provider.should_receive(:shell_out_with_systems_locale!).with("/sbin/rsyslog restartyousillysally") - @provider.restart_service() - end - - it "should call '/sbin/restart service_name' if no restart command is specified" do - @current_resource.stub(:running).and_return(true) - @provider.should_receive(:shell_out_with_systems_locale!).with("/sbin/restart #{@new_resource.service_name}").and_return(0) - @provider.restart_service() - end - - it "should call '/sbin/start service_name' if restart_service is called for a stopped service" do - @current_resource.stub(:running).and_return(false) - @provider.should_receive(:shell_out_with_systems_locale!).with("/sbin/start #{@new_resource.service_name}").and_return(0) - @provider.restart_service() - end - - it "should call the reload command if one is specified" do - @current_resource.stub(:running).and_return(true) - @new_resource.stub(:reload_command).and_return("/sbin/rsyslog reloadyousillysally") - @provider.should_receive(:shell_out_with_systems_locale!).with("/sbin/rsyslog reloadyousillysally") - @provider.reload_service() - end - - it "should call '/sbin/reload service_name' if no reload command is specified" do - @current_resource.stub(:running).and_return(true) - @provider.should_receive(:shell_out_with_systems_locale!).with("/sbin/reload #{@new_resource.service_name}").and_return(0) - @provider.reload_service() - end - - it "should call the stop command if one is specified" do - @current_resource.stub(:running).and_return(true) - @new_resource.stub(:stop_command).and_return("/sbin/rsyslog stopyousillysally") - @provider.should_receive(:shell_out_with_systems_locale!).with("/sbin/rsyslog stopyousillysally") - @provider.stop_service() - end - - it "should call '/sbin/stop service_name' if no stop command is specified" do - @current_resource.stub(:running).and_return(true) - @provider.should_receive(:shell_out_with_systems_locale!).with("/sbin/stop #{@new_resource.service_name}").and_return(0) - @provider.stop_service() - end - - it "should not call '/sbin/stop service_name' if it is already stopped" do - @current_resource.stub(:running).and_return(false) - @provider.should_not_receive(:shell_out_with_systems_locale!).with("/sbin/stop #{@new_resource.service_name}") - @provider.stop_service() - end - end -end diff --git a/spec/unit/provider/service/windows_spec.rb b/spec/unit/provider/service/windows_spec.rb deleted file mode 100644 index 14bdb782cd..0000000000 --- a/spec/unit/provider/service/windows_spec.rb +++ /dev/null @@ -1,367 +0,0 @@ -# -# Author:: Nuo Yan <nuo@opscode.com> -# Author:: Seth Chisamore <schisamo@opscode.com> -# Copyright:: Copyright (c) 2010-2011 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::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 - Win32::Service = Class.new - Win32::Service::AUTO_START = 0x00000002 - Win32::Service::DEMAND_START = 0x00000003 - Win32::Service::DISABLED = 0x00000004 - Win32::Service.stub(:status).with(@new_resource.service_name).and_return( - double("StatusStruct", :current_state => "running")) - Win32::Service.stub(:config_info).with(@new_resource.service_name).and_return( - double("ConfigStruct", :start_type => "auto start")) - Win32::Service.stub(:exists?).and_return(true) - end - - it "should set the current resources service name to the new resources service name" do - @provider.load_current_resource - @provider.current_resource.service_name.should == 'chef' - end - - it "should return the current resource" do - @provider.load_current_resource.should equal(@provider.current_resource) - end - - it "should set the current resources status" do - @provider.load_current_resource - @provider.current_resource.running.should be_true - end - - it "should set the current resources start type" do - @provider.load_current_resource - @provider.current_resource.enabled.should be_true - end - - it "does not set the current resources start type if it is neither AUTO START or DISABLED" do - Win32::Service.stub(:config_info).with(@new_resource.service_name).and_return( - double("ConfigStruct", :start_type => "manual")) - @provider.load_current_resource - @provider.current_resource.enabled.should be_nil - end - - describe Chef::Provider::Service::Windows, "start_service" do - before(:each) do - Win32::Service.stub(: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" - @provider.should_receive(:shell_out!).with("#{@new_resource.start_command}").and_return("Starting custom service") - @provider.start_service - @new_resource.updated_by_last_action?.should be_true - end - - it "should use the built-in command if no start command is specified" do - Win32::Service.should_receive(:start).with(@new_resource.service_name) - @provider.start_service - @new_resource.updated_by_last_action?.should be_true - end - - it "should do nothing if the service does not exist" do - Win32::Service.stub(:exists?).with(@new_resource.service_name).and_return(false) - Win32::Service.should_not_receive(:start).with(@new_resource.service_name) - @provider.start_service - @new_resource.updated_by_last_action?.should be_false - end - - it "should do nothing if the service is running" do - Win32::Service.stub(:status).with(@new_resource.service_name).and_return( - double("StatusStruct", :current_state => "running")) - @provider.load_current_resource - Win32::Service.should_not_receive(:start).with(@new_resource.service_name) - @provider.start_service - @new_resource.updated_by_last_action?.should be_false - end - - it "should raise an error if the service is paused" do - Win32::Service.stub(:status).with(@new_resource.service_name).and_return( - double("StatusStruct", :current_state => "paused")) - @provider.load_current_resource - Win32::Service.should_not_receive(:start).with(@new_resource.service_name) - expect { @provider.start_service }.to raise_error( Chef::Exceptions::Service ) - @new_resource.updated_by_last_action?.should be_false - end - - it "should wait and continue if the service is in start_pending" do - Win32::Service.stub(: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 - Win32::Service.should_not_receive(:start).with(@new_resource.service_name) - @provider.start_service - @new_resource.updated_by_last_action?.should be_false - end - - it "should fail if the service is in stop_pending" do - Win32::Service.stub(:status).with(@new_resource.service_name).and_return( - double("StatusStruct", :current_state => "stop pending")) - @provider.load_current_resource - Win32::Service.should_not_receive(:start).with(@new_resource.service_name) - expect { @provider.start_service }.to raise_error( Chef::Exceptions::Service ) - @new_resource.updated_by_last_action?.should be_false - end - - end - - - describe Chef::Provider::Service::Windows, "stop_service" do - - before(:each) do - Win32::Service.stub(: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" - @provider.should_receive(:shell_out!).with("#{@new_resource.stop_command}").and_return("Stopping custom service") - @provider.stop_service - @new_resource.updated_by_last_action?.should be_true - end - - it "should use the built-in command if no stop command is specified" do - Win32::Service.should_receive(:stop).with(@new_resource.service_name) - @provider.stop_service - @new_resource.updated_by_last_action?.should be_true - end - - it "should do nothing if the service does not exist" do - Win32::Service.stub(:exists?).with(@new_resource.service_name).and_return(false) - Win32::Service.should_not_receive(:stop).with(@new_resource.service_name) - @provider.stop_service - @new_resource.updated_by_last_action?.should be_false - end - - it "should do nothing if the service is stopped" do - Win32::Service.stub(:status).with(@new_resource.service_name).and_return( - double("StatusStruct", :current_state => "stopped")) - @provider.load_current_resource - Win32::Service.should_not_receive(:stop).with(@new_resource.service_name) - @provider.stop_service - @new_resource.updated_by_last_action?.should be_false - end - - it "should raise an error if the service is paused" do - Win32::Service.stub(:status).with(@new_resource.service_name).and_return( - double("StatusStruct", :current_state => "paused")) - @provider.load_current_resource - Win32::Service.should_not_receive(:start).with(@new_resource.service_name) - expect { @provider.stop_service }.to raise_error( Chef::Exceptions::Service ) - @new_resource.updated_by_last_action?.should be_false - end - - it "should wait and continue if the service is in stop_pending" do - Win32::Service.stub(: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 - Win32::Service.should_not_receive(:stop).with(@new_resource.service_name) - @provider.stop_service - @new_resource.updated_by_last_action?.should be_false - end - - it "should fail if the service is in start_pending" do - Win32::Service.stub(:status).with(@new_resource.service_name).and_return( - double("StatusStruct", :current_state => "start pending")) - @provider.load_current_resource - Win32::Service.should_not_receive(:stop).with(@new_resource.service_name) - expect { @provider.stop_service }.to raise_error( Chef::Exceptions::Service ) - @new_resource.updated_by_last_action?.should be_false - end - - it "should pass custom timeout to the stop command if provided" do - Win32::Service.stub(:status).with(@new_resource.service_name).and_return( - double("StatusStruct", :current_state => "running")) - @new_resource.timeout 1 - Win32::Service.should_receive(:stop).with(@new_resource.service_name) - Timeout.timeout(2) do - expect { @provider.stop_service }.to raise_error(Timeout::Error) - end - @new_resource.updated_by_last_action?.should be_false - 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" - @provider.should_receive(:shell_out!).with("#{@new_resource.restart_command}") - @provider.restart_service - @new_resource.updated_by_last_action?.should be_true - end - - it "should stop then start the service if it is running" do - Win32::Service.stub(: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")) - Win32::Service.should_receive(:stop).with(@new_resource.service_name) - Win32::Service.should_receive(:start).with(@new_resource.service_name) - @provider.restart_service - @new_resource.updated_by_last_action?.should be_true - end - - it "should just start the service if it is stopped" do - Win32::Service.stub(:status).with(@new_resource.service_name).and_return( - double("StatusStruct", :current_state => "stopped"), - double("StatusStruct", :current_state => "stopped"), - double("StatusStruct", :current_state => "running")) - Win32::Service.should_receive(:start).with(@new_resource.service_name) - @provider.restart_service - @new_resource.updated_by_last_action?.should be_true - end - - it "should do nothing if the service does not exist" do - Win32::Service.stub(:exists?).with(@new_resource.service_name).and_return(false) - Win32::Service.should_not_receive(:stop).with(@new_resource.service_name) - Win32::Service.should_not_receive(:start).with(@new_resource.service_name) - @provider.restart_service - @new_resource.updated_by_last_action?.should be_false - end - - end - - describe Chef::Provider::Service::Windows, "enable_service" do - before(:each) do - Win32::Service.stub(:config_info).with(@new_resource.service_name).and_return( - double("ConfigStruct", :start_type => "disabled")) - end - - it "should enable service" do - Win32::Service.should_receive(:configure).with(:service_name => @new_resource.service_name, :start_type => Win32::Service::AUTO_START) - @provider.enable_service - @new_resource.updated_by_last_action?.should be_true - end - - it "should do nothing if the service does not exist" do - Win32::Service.stub(:exists?).with(@new_resource.service_name).and_return(false) - Win32::Service.should_not_receive(:configure) - @provider.enable_service - @new_resource.updated_by_last_action?.should be_false - end - end - - describe Chef::Provider::Service::Windows, "action_enable" do - it "does nothing if the service is enabled" do - Win32::Service.stub(:config_info).with(@new_resource.service_name).and_return( - double("ConfigStruct", :start_type => "auto start")) - @provider.should_not_receive(:enable_service) - @provider.action_enable - end - - it "enables the service if it is not set to automatic start" do - Win32::Service.stub(:config_info).with(@new_resource.service_name).and_return( - double("ConfigStruct", :start_type => "disabled")) - @provider.should_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 - Win32::Service.stub(:config_info).with(@new_resource.service_name).and_return( - double("ConfigStruct", :start_type => "disabled")) - @provider.should_not_receive(:disable_service) - @provider.action_disable - end - - it "disables the service if it is not set to disabled" do - Win32::Service.stub(:config_info).with(@new_resource.service_name).and_return( - double("ConfigStruct", :start_type => "auto start")) - @provider.should_receive(:disable_service) - @provider.action_disable - end - end - - describe Chef::Provider::Service::Windows, "disable_service" do - before(:each) do - Win32::Service.stub(:config_info).with(@new_resource.service_name).and_return( - double("ConfigStruct", :start_type => "auto start")) - end - - it "should disable service" do - Win32::Service.should_receive(:configure) - @provider.disable_service - @new_resource.updated_by_last_action?.should be_true - end - - it "should do nothing if the service does not exist" do - Win32::Service.stub(:exists?).with(@new_resource.service_name).and_return(false) - Win32::Service.should_not_receive(:configure) - @provider.disable_service - @new_resource.updated_by_last_action?.should be_false - end - end - - describe Chef::Provider::Service::Windows, "action_configure_startup" do - { :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) - @provider.stub(:current_start_type).and_return("fire") - @provider.should_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) - @provider.stub(:current_start_type).and_return(win32) - @provider.should_not_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 - Win32::Service.should_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 - Win32::Service.should_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 - Win32::Service.should_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) - end - end -end diff --git a/spec/unit/provider/service_spec.rb b/spec/unit/provider/service_spec.rb deleted file mode 100644 index 7ddc01ff0b..0000000000 --- a/spec/unit/provider/service_spec.rb +++ /dev/null @@ -1,169 +0,0 @@ -# -# Author:: AJ Christensen (<aj@hjksolutions.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' - -describe Chef::Provider::Service do - before do - @node = Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - @new_resource = Chef::Resource::Service.new("chef") - @current_resource = Chef::Resource::Service.new("chef") - - @provider = Chef::Provider::Service.new(@new_resource, @run_context) - @provider.current_resource = @current_resource - @provider.stub(:load_current_resource) - end - - describe "when enabling the service" do - it "should enable the service if disabled and set the resource as updated" do - @current_resource.enabled(false) - @provider.should_receive(:enable_service).and_return(true) - @provider.action_enable - @provider.set_updated_status - @provider.new_resource.should be_updated - end - - it "should not enable the service if already enabled" do - @current_resource.enabled(true) - @provider.should_not_receive(:enable_service) - @provider.action_enable - @provider.set_updated_status - @provider.new_resource.should_not be_updated - end - end - - - describe "when disabling the service" do - it "should disable the service if enabled and set the resource as updated" do - @current_resource.stub(:enabled).and_return(true) - @provider.should_receive(:disable_service).and_return(true) - @provider.run_action(:disable) - @provider.new_resource.should be_updated - end - - it "should not disable the service if already disabled" do - @current_resource.stub(:enabled).and_return(false) - @provider.should_not_receive(:disable_service) - @provider.run_action(:disable) - @provider.new_resource.should_not be_updated - end - end - - describe "action_start" do - it "should start the service if it isn't running and set the resource as updated" do - @current_resource.running(false) - @provider.should_receive(:start_service).with.and_return(true) - @provider.run_action(:start) - @provider.new_resource.should be_updated - end - - it "should not start the service if already running" do - @current_resource.running(true) - @provider.should_not_receive(:start_service) - @provider.run_action(:start) - @provider.new_resource.should_not be_updated - end - end - - describe "action_stop" do - it "should stop the service if it is running and set the resource as updated" do - @current_resource.stub(:running).and_return(true) - @provider.should_receive(:stop_service).and_return(true) - @provider.run_action(:stop) - @provider.new_resource.should be_updated - end - - it "should not stop the service if it's already stopped" do - @current_resource.stub(:running).and_return(false) - @provider.should_not_receive(:stop_service) - @provider.run_action(:stop) - @provider.new_resource.should_not be_updated - end - end - - describe "action_restart" do - before do - @current_resource.supports(:restart => true) - end - - it "should restart the service if it's supported and set the resource as updated" do - @provider.should_receive(:restart_service).and_return(true) - @provider.run_action(:restart) - @provider.new_resource.should be_updated - end - - it "should restart the service even if it isn't running and set the resource as updated" do - @current_resource.stub(:running).and_return(false) - @provider.should_receive(:restart_service).and_return(true) - @provider.run_action(:restart) - @provider.new_resource.should be_updated - end - end - - describe "action_reload" do - before do - @new_resource.supports(:reload => true) - end - - it "should raise an exception if reload isn't supported" do - @new_resource.supports(:reload => false) - @new_resource.stub(:reload_command).and_return(false) - lambda { @provider.run_action(:reload) }.should raise_error(Chef::Exceptions::UnsupportedAction) - end - - it "should reload the service if it is running and set the resource as updated" do - @current_resource.stub(:running).and_return(true) - @provider.should_receive(:reload_service).and_return(true) - @provider.run_action(:reload) - @provider.new_resource.should be_updated - end - - it "should not reload the service if it's stopped" do - @current_resource.stub(:running).and_return(false) - @provider.should_not_receive(:reload_service) - @provider.run_action(:stop) - @provider.new_resource.should_not be_updated - end - end - - it "delegates enable_service to subclasses" do - lambda { @provider.enable_service }.should raise_error(Chef::Exceptions::UnsupportedAction) - end - - it "delegates disable_service to subclasses" do - lambda { @provider.disable_service }.should raise_error(Chef::Exceptions::UnsupportedAction) - end - - it "delegates start_service to subclasses" do - lambda { @provider.start_service }.should raise_error(Chef::Exceptions::UnsupportedAction) - end - - it "delegates stop_service to subclasses" do - lambda { @provider.stop_service }.should raise_error(Chef::Exceptions::UnsupportedAction) - end - - it "delegates restart_service to subclasses" do - lambda { @provider.restart_service }.should raise_error(Chef::Exceptions::UnsupportedAction) - end - - it "delegates reload_service to subclasses" do - lambda { @provider.reload_service }.should raise_error(Chef::Exceptions::UnsupportedAction) - end -end diff --git a/spec/unit/provider/subversion_spec.rb b/spec/unit/provider/subversion_spec.rb deleted file mode 100644 index 5d9d1cec1e..0000000000 --- a/spec/unit/provider/subversion_spec.rb +++ /dev/null @@ -1,280 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@kallistec.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' - -describe Chef::Provider::Subversion do - - before do - @resource = Chef::Resource::Subversion.new("my app") - @resource.repository "http://svn.example.org/trunk/" - @resource.destination "/my/deploy/dir" - @resource.revision "12345" - @resource.svn_arguments(false) - @resource.svn_info_args(false) - @node = Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - @provider = Chef::Provider::Subversion.new(@resource, @run_context) - end - - it "converts resource attributes to options for run_command and popen4" do - @provider.run_options.should == {} - @resource.user 'deployninja' - @provider.run_options.should == {:user => "deployninja"} - end - - context "determining the revision of the currently deployed code" do - - before do - @stdout = double("stdout") - @stderr = double("stderr") - @exitstatus = double("exitstatus") - end - - it "sets the revision to nil if there isn't any deployed code yet" do - ::File.should_receive(:exist?).with("/my/deploy/dir/.svn").and_return(false) - @provider.find_current_revision.should be_nil - end - - it "determines the current revision if there's a checkout with svn data available" do - example_svn_info = "Path: .\n" + - "URL: http://svn.example.org/trunk/myapp\n" + - "Repository Root: http://svn.example.org\n" + - "Repository UUID: d62ff500-7bbc-012c-85f1-0026b0e37c24\n" + - "Revision: 11739\nNode Kind: directory\n" + - "Schedule: normal\n" + - "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" - ::File.should_receive(:exist?).at_least(1).times.with("/my/deploy/dir/.svn").and_return(true) - ::File.should_receive(:directory?).with("/my/deploy/dir").and_return(true) - ::Dir.should_receive(:chdir).with("/my/deploy/dir").and_yield - @stdout.stub(:string).and_return(example_svn_info) - @stderr.stub(:string).and_return("") - @exitstatus.stub(:exitstatus).and_return(0) - expected_command = ["svn info", {:cwd=>"/my/deploy/dir"}] - @provider.should_receive(:popen4).with(*expected_command). - and_yield("no-pid", "no-stdin", @stdout,@stderr). - and_return(@exitstatus) - @provider.find_current_revision.should 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" - ::File.should_receive(:exist?).with("/my/deploy/dir/.svn").and_return(true) - ::File.should_receive(:directory?).with("/my/deploy/dir").and_return(true) - ::Dir.should_receive(:chdir).with("/my/deploy/dir").and_yield - @stdout.stub(:string).and_return(example_svn_info) - @stderr.stub(:string).and_return("") - @exitstatus.stub(:exitstatus).and_return(1) - @provider.should_receive(:popen4).and_yield("no-pid", "no-stdin", @stdout,@stderr). - and_return(@exitstatus) - @provider.find_current_revision.should be_nil - end - - it "finds the current revision when loading the current resource state" do - # note: the test is kinda janky, but it provides regression coverage for CHEF-2092 - @resource.instance_variable_set(:@action, :sync) - @provider.should_receive(:find_current_revision).and_return("12345") - @provider.load_current_resource - @provider.current_resource.revision.should == "12345" - end - end - - it "creates the current_resource object and sets its revision to the current deployment's revision as long as we're not exporting" do - @provider.stub(:find_current_revision).and_return("11410") - @provider.new_resource.instance_variable_set :@action, [:checkout] - @provider.load_current_resource - @provider.current_resource.name.should eql(@resource.name) - @provider.current_resource.revision.should eql("11410") - end - - context "resolving revisions to an integer" do - - before do - @stdout = double("stdout") - @stderr = double("stderr") - @resource.svn_info_args "--no-auth-cache" - end - - it "returns the revision number as is if it's already an integer" do - @provider.revision_int.should eql("12345") - end - - it "queries the server and resolves the revision if it's not an integer (i.e. 'HEAD')" do - example_svn_info = "Path: .\n" + - "URL: http://svn.example.org/trunk/myapp\n" + - "Repository Root: http://svn.example.org\n" + - "Repository UUID: d62ff500-7bbc-012c-85f1-0026b0e37c24\n" + - "Revision: 11739\nNode Kind: directory\n" + - "Schedule: normal\n" + - "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") - exitstatus.stub(:exitstatus).and_return(0) - @resource.revision "HEAD" - @stdout.stub(:string).and_return(example_svn_info) - @stderr.stub(:string).and_return("") - expected_command = ["svn info http://svn.example.org/trunk/ --no-auth-cache -rHEAD", {:cwd=>Dir.tmpdir}] - @provider.should_receive(:popen4).with(*expected_command). - and_yield("no-pid","no-stdin",@stdout,@stderr). - and_return(exitstatus) - @provider.revision_int.should 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") - exitstatus.stub(:exitstatus).and_return(0) - @resource.revision "HEAD" - @stdout.stub(:string).and_return(example_svn_info) - @stderr.stub(:string).and_return("") - @provider.should_receive(:popen4).and_yield("no-pid","no-stdin",@stdout,@stderr). - and_return(exitstatus) - lambda {@provider.revision_int}.should raise_error(RuntimeError, "Could not parse `svn info` data: some random text from an error message") - - end - - it "responds to :revision_slug as an alias for revision_sha" do - @provider.should respond_to(:revision_slug) - end - - end - - it "generates a checkout command with default options" do - @provider.checkout_command.should eql("svn checkout -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir") - end - - it "generates a checkout command with authentication" do - @resource.svn_username "deployNinja" - @resource.svn_password "vanish!" - @provider.checkout_command.should eql("svn checkout -q --username deployNinja --password vanish! " + - "-r12345 http://svn.example.org/trunk/ /my/deploy/dir") - end - - it "generates a checkout command with arbitrary options" do - @resource.svn_arguments "--no-auth-cache" - @provider.checkout_command.should 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 - @provider.sync_command.should eql("svn update -q -r12345 /my/deploy/dir") - end - - it "generates an export command with default options" do - @provider.export_command.should eql("svn export --force -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir") - end - - it "doesn't try to find the current revision when loading the resource if running an export" do - @provider.new_resource.instance_variable_set :@action, [:export] - @provider.should_not_receive(:find_current_revision) - @provider.load_current_resource - end - - it "doesn't try to find the current revision when loading the resource if running a force export" do - @provider.new_resource.instance_variable_set :@action, [:force_export] - @provider.should_not_receive(:find_current_revision) - @provider.load_current_resource - end - - it "runs an export with the --force option" do - ::File.stub(:directory?).with("/my/deploy").and_return(true) - expected_cmd = "svn export --force -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir" - @provider.should_receive(:shell_out!).with(command: expected_cmd) - @provider.run_action(:force_export) - @resource.should be_updated - end - - it "runs the checkout command for action_checkout" do - ::File.stub(:directory?).with("/my/deploy").and_return(true) - expected_cmd = "svn checkout -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir" - @provider.should_receive(:shell_out!).with(command: expected_cmd) - @provider.run_action(:checkout) - @resource.should be_updated - end - - it "raises an error if the svn checkout command would fail because the enclosing directory doesn't exist" do - lambda {@provider.run_action(:sync)}.should raise_error(Chef::Exceptions::MissingParentDirectory) - end - - it "should not checkout if the destination exists or is a non empty directory" do - ::File.stub(:exist?).with("/my/deploy/dir/.svn").and_return(false) - ::File.stub(:exist?).with("/my/deploy/dir").and_return(true) - ::File.stub(:directory?).with("/my/deploy").and_return(true) - ::Dir.stub(:entries).with("/my/deploy/dir").and_return(['.','..','foo','bar']) - @provider.should_not_receive(:checkout_command) - @provider.run_action(:checkout) - @resource.should_not be_updated - end - - it "runs commands with the user and group specified in the resource" do - ::File.stub(:directory?).with("/my/deploy").and_return(true) - @resource.user "whois" - @resource.group "thisis" - expected_cmd = "svn checkout -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir" - @provider.should_receive(:shell_out!).with(command: expected_cmd, user: "whois", group: "thisis") - @provider.run_action(:checkout) - @resource.should be_updated - end - - it "does a checkout for action_sync if there's no deploy dir" do - ::File.stub(:directory?).with("/my/deploy").and_return(true) - ::File.should_receive(:exist?).with("/my/deploy/dir/.svn").twice.and_return(false) - @provider.should_receive(:action_checkout) - @provider.run_action(:sync) - end - - it "does a checkout for action_sync if the deploy dir exists but is empty" do - ::File.stub(:directory?).with("/my/deploy").and_return(true) - ::File.should_receive(:exist?).with("/my/deploy/dir/.svn").twice.and_return(false) - @provider.should_receive(:action_checkout) - @provider.run_action(:sync) - end - - it "runs the sync_command on action_sync if the deploy dir exists and isn't empty" do - ::File.stub(:directory?).with("/my/deploy").and_return(true) - ::File.should_receive(:exist?).with("/my/deploy/dir/.svn").and_return(true) - @provider.stub(:find_current_revision).and_return("11410") - @provider.stub(:current_revision_matches_target_revision?).and_return(false) - expected_cmd = "svn update -q -r12345 /my/deploy/dir" - @provider.should_receive(:shell_out!).with(command: expected_cmd) - @provider.run_action(:sync) - @resource.should be_updated - end - - it "does not fetch any updates if the remote revision matches the current revision" do - ::File.stub(:directory?).with("/my/deploy").and_return(true) - ::File.should_receive(:exist?).with("/my/deploy/dir/.svn").and_return(true) - @provider.stub(:find_current_revision).and_return('12345') - @provider.stub(:current_revision_matches_target_revision?).and_return(true) - @provider.run_action(:sync) - @resource.should_not be_updated - end - - it "runs the export_command on action_export" do - ::File.stub(:directory?).with("/my/deploy").and_return(true) - expected_cmd = "svn export --force -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir" - @provider.should_receive(:shell_out!).with(command: expected_cmd) - @provider.run_action(:export) - @resource.should be_updated - end - -end diff --git a/spec/unit/provider/template/content_spec.rb b/spec/unit/provider/template/content_spec.rb deleted file mode 100644 index b419e70519..0000000000 --- a/spec/unit/provider/template/content_spec.rb +++ /dev/null @@ -1,78 +0,0 @@ -# -# Author:: Lamont Granquist (<lamont@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::Template::Content do - - let(:new_resource) do - double("Chef::Resource::Template (new)", - :cookbook_name => 'openldap', - :source => 'openldap_stuff.conf.erb', - :local => false, - :cookbook => nil, - :variables => {}, - :inline_helper_blocks => {}, - :inline_helper_modules => [], - :helper_modules => []) - end - - let(:rendered_file_location) { Dir.tmpdir + '/openldap_stuff.conf' } - - let(:run_context) do - cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks")) - Chef::Cookbook::FileVendor.fetch_from_disk(cookbook_repo) - cl = Chef::CookbookLoader.new(cookbook_repo) - cl.load_cookbooks - cookbook_collection = Chef::CookbookCollection.new(cl) - node = Chef::Node.new - double("Chef::Resource::RunContext", :node => node, :cookbook_collection => cookbook_collection) - end - - let(:content) do - current_resource = double("Chef::Resource::Template (current)") - Chef::Provider::Template::Content.new(new_resource, current_resource, run_context) - end - - after do - FileUtils.rm(rendered_file_location) if ::File.exist?(rendered_file_location) - end - - it "finds the template file in the cookbook cache if it isn't local" do - content.template_location.should == CHEF_SPEC_DATA + '/cookbooks/openldap/templates/default/openldap_stuff.conf.erb' - end - - it "finds the template file locally if it is local" do - new_resource.stub(:local).and_return(true) - new_resource.stub(:source).and_return('/tmp/its_on_disk.erb') - content.template_location.should == '/tmp/its_on_disk.erb' - end - - it "should use the cookbook name if defined in the template resource" do - new_resource.stub(:cookbook_name).and_return('apache2') - new_resource.stub(:cookbook).and_return('openldap') - new_resource.stub(:source).and_return("test.erb") - content.template_location.should == CHEF_SPEC_DATA + '/cookbooks/openldap/templates/default/test.erb' - end - - it "creates the template with the rendered content" do - run_context.node.normal[:slappiness] = "a warm gun" - IO.read(content.tempfile.path).should == "slappiness is a warm gun" - end - -end diff --git a/spec/unit/provider/template_spec.rb b/spec/unit/provider/template_spec.rb deleted file mode 100644 index 514bdc12ff..0000000000 --- a/spec/unit/provider/template_spec.rb +++ /dev/null @@ -1,90 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: Lamont Granquist (<lamont@opscode.com>) -# Copyright:: Copyright (c) 2008-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 '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(:enclosing_directory) { - canonicalize_path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates"))) - } - let(:resource_path) { - canonicalize_path(File.expand_path(File.join(enclosing_directory, "seattle.txt"))) - } - - # Subject - - let(:provider) do - provider = described_class.new(resource, run_context) - provider.stub(:content).and_return(content) - provider - end - - let(:resource) do - resource = Chef::Resource::Template.new("seattle", @run_context) - resource.path(resource_path) - resource - end - - let(:content) do - content = double('Chef::Provider::File::Content::Template', :template_location => "/foo/bar/baz") - File.stub(:exists?).with("/foo/bar/baz").and_return(true) - content - end - - it_behaves_like Chef::Provider::File - - 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(:enclosing_directory) { - canonicalize_path(File.expand_path(File.join(CHEF_SPEC_DATA, "templates"))) - } - let(:resource_path) { - canonicalize_path(File.expand_path(File.join(enclosing_directory, "seattle.txt"))) - } - - # Subject - - let(:provider) do - provider = described_class.new(resource, run_context) - provider.stub(:content).and_return(content) - provider - end - - it "stops executing when the local template source can't be found" do - setup_normal_file - content.stub(:template_location).and_return("/baz/bar/foo") - File.stub(:exists?).with("/baz/bar/foo").and_return(false) - lambda { provider.run_action(:create) }.should raise_error Chef::Mixin::WhyRun::ResourceRequirements::Assertion::AssertionFailure - end - - end - - it_behaves_like "a file provider with source field" -end diff --git a/spec/unit/provider/user/dscl_spec.rb b/spec/unit/provider/user/dscl_spec.rb deleted file mode 100644 index c17aefb00d..0000000000 --- a/spec/unit/provider/user/dscl_spec.rb +++ /dev/null @@ -1,879 +0,0 @@ -# -# Author:: Dreamcat4 (<dreamcat4@gmail.com>) -# Copyright:: Copyright (c) 2009 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. -# - -ShellCmdResult = Struct.new(:stdout, :stderr, :exitstatus) - -require 'spec_helper' -require 'ostruct' -require 'mixlib/shellout' - -describe Chef::Provider::User::Dscl do - before do - Chef::Platform.stub(:windows?) { false } - end - let(:node) { - node = Chef::Node.new - node.stub(:[]).with(:platform_version).and_return(mac_version) - node.stub(:[]).with(:platform).and_return("mac_os_x") - node - } - - let(:events) { - Chef::EventDispatch::Dispatcher.new - } - - let(:run_context) { - Chef::RunContext.new(node, {}, events) - } - - let(:new_resource) { - r = Chef::Resource::User.new("toor") - r.password(password) - r.salt(salt) - r.iterations(iterations) - r - } - - let(:provider) { - Chef::Provider::User::Dscl.new(new_resource, run_context) - } - - let(:mac_version) { - "10.9.1" - } - - let(:password) { nil } - let(:salt) { nil } - let(:iterations) { nil } - - let(:salted_sha512_password) { - "0f543f021c63255e64e121a3585601b8ecfedf6d2\ -705ddac69e682a33db5dbcdb9b56a2520bc8fff63a\ -2ba6b7984c0737ff0b7949455071581f7affcd536d\ -402b6cdb097" - } - - let(:salted_sha512_pbkdf2_password) { - "c734b6e4787c3727bb35e29fdd92b97c\ -1de12df509577a045728255ec7c6c5f5\ -c18efa05ed02b682ffa7ebc05119900e\ -b1d4880833aa7a190afc13e2bf0936b8\ -20123e8c98f0f9bcac2a629d9163caac\ -9464a8c234f3919082400b4f939bb77b\ -c5adbbac718b7eb99463a7b679571e0f\ -1c9fef2ef08d0b9e9c2bcf644eed2ffc" - } - - let(:salted_sha512_pbkdf2_salt) { - "2d942d8364a9ccf2b8e5cb7ed1ff58f78\ -e29dbfee7f9db58859144d061fd0058" - } - - let(:salted_sha512_pbkdf2_iterations) { - 25000 - } - - let(:vagrant_sha_512) { - "6f75d7190441facc34291ebbea1fc756b242d4f\ -e9bcff141bccb84f1979e27e539539aa31f9f7dcc92c0cea959\ -ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30" - } - - let(:vagrant_sha_512_pbkdf2) { - "12601a90db17cbf\ -8ba4808e6382fb0d3b9d8a6c1a190477bf680ab21afb\ -6065467136e55cc208a6f74156e3daf20fb13369ef4b\ -7bafa047d80359fb46a48a4adccd548ebb33851b093\ -47cca84341a7f93a27147343f89fb843fb46c0017d2\ -64afa4976baacf941b915bd1ec1ca24c30b3e759e02\ -403e02f59fe7ff5938a7636c" - } - - let(:vagrant_sha_512_pbkdf2_salt) { - "ee954be472fdc60ddf89484781433993625f006af6ec810c08f49a7e413946a1" - } - - let(:vagrant_sha_512_pbkdf2_iterations) { - 34482 - } - - 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) - provider.should_receive(:shell_out).with("dscl . -cmd /Path args").and_return(shell_return) - provider.run_dscl("cmd /Path args").should == 'stdout' - end - - it "returns an empty string from delete commands" do - shell_return = ShellCmdResult.new('out', 'err', 23) - provider.should_receive(:shell_out).with("dscl . -delete /Path args").and_return(shell_return) - provider.run_dscl("delete /Path args").should == "" - end - - it "should raise an exception for any other command" do - shell_return = ShellCmdResult.new('out', 'err', 23) - provider.should_receive(:shell_out).with('dscl . -cmd /Path arguments').and_return(shell_return) - lambda { provider.run_dscl("cmd /Path arguments") }.should 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) - provider.should_receive(:shell_out).with('dscl . -cmd /Path args').and_return(shell_return) - lambda { provider.run_dscl("cmd /Path args") }.should 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) - provider.should_receive(:shell_out).with('dscl . -cmd /Path args').and_return(shell_return) - lambda { provider.run_dscl("cmd /Path args") }.should raise_error(Chef::Exceptions::DsclCommandFailed) - end - end - - describe "get_free_uid" do - before do - provider.should_receive(:run_dscl).with("list /Users uid").and_return("\nwheel 200\nstaff 201\nbrahms 500\nchopin 501\n") - end - - describe "when resource is configured as system" do - before do - new_resource.system(true) - end - - it "should return the first unused uid number on or above 500" do - provider.get_free_uid.should eq(202) - end - end - - it "should return the first unused uid number on or above 200" do - provider.get_free_uid.should eq(502) - end - - it "should raise an exception when the search limit is exhausted" do - search_limit = 1 - lambda { provider.get_free_uid(search_limit) }.should raise_error(RuntimeError) - end - end - - describe "uid_used?" do - it "should return false if not given any valid uid number" do - provider.uid_used?(nil).should be_false - end - - describe "when called with a user id" do - before do - provider.should_receive(:run_dscl).with("list /Users uid").and_return("\naj 500\n") - end - - it "should return true for a used uid number" do - provider.uid_used?(500).should be_true - end - - it "should return false for an unused uid number" do - provider.uid_used?(501).should be_false - end - end - end - - describe "when determining the uid to set" do - it "raises RequestedUIDUnavailable if the requested uid is already in use" do - provider.stub(:uid_used?).and_return(true) - provider.should_receive(:get_free_uid).and_return(501) - lambda { provider.dscl_set_uid }.should raise_error(Chef::Exceptions::RequestedUIDUnavailable) - end - - it "finds a valid, unused uid when none is specified" do - provider.should_receive(:run_dscl).with("list /Users uid").and_return('') - provider.should_receive(:run_dscl).with("create /Users/toor UniqueID 501") - provider.should_receive(:get_free_uid).and_return(501) - provider.dscl_set_uid - new_resource.uid.should eq(501) - end - - it "sets the uid specified in the resource" do - new_resource.uid(1000) - provider.should_receive(:run_dscl).with("create /Users/toor UniqueID 1000").and_return(true) - provider.should_receive(:run_dscl).with("list /Users uid").and_return('') - provider.dscl_set_uid - end - end - - describe "when modifying the home directory" do - let(:current_resource) { - new_resource.dup - } - - before do - new_resource.supports({ :manage_home => true }) - new_resource.home('/Users/toor') - - provider.current_resource = current_resource - end - - it "deletes the home directory when resource#home is nil" do - new_resource.instance_variable_set(:@home, nil) - provider.should_receive(:run_dscl).with("delete /Users/toor NFSHomeDirectory").and_return(true) - provider.dscl_set_home - end - - - it "raises InvalidHomeDirectory when the resource's home directory doesn't look right" do - new_resource.home('epic-fail') - lambda { provider.dscl_set_home }.should 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_resource.home(current_home) - new_resource.gid(23) - ::File.stub(:exists?).with('/old/home/toor').and_return(true) - ::File.stub(:exists?).with('/Users/toor').and_return(true) - - FileUtils.should_receive(:mkdir_p).with('/Users/toor').and_return(true) - FileUtils.should_receive(:rmdir).with(current_home) - ::Dir.should_receive(:glob).with("#{CHEF_SPEC_DATA}/old_home_dir/*",::File::FNM_DOTMATCH).and_return(current_home_files) - FileUtils.should_receive(:mv).with(current_home_files, "/Users/toor", :force => true) - FileUtils.should_receive(:chown_R).with('toor','23','/Users/toor') - - provider.should_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 - ::File.stub(:exists?).and_return(false,false,false) - lambda { provider.dscl_set_home }.should raise_error(Chef::Exceptions::User) - end - - it "should run ditto to copy any missing files from skel to the new home dir" do - ::File.should_receive(:exists?).with("/System/Library/User\ Template/English.lproj").and_return(true) - FileUtils.should_receive(:chown_R).with('toor', '', '/Users/toor') - provider.should_receive(:shell_out!).with("ditto '/System/Library/User Template/English.lproj' '/Users/toor'") - provider.ditto_home - end - - it "creates the user's NFSHomeDirectory and home directory" do - provider.should_receive(:run_dscl).with("create /Users/toor NFSHomeDirectory '/Users/toor'").and_return(true) - provider.should_receive(:ditto_home) - provider.dscl_set_home - end - end - - describe "resource_requirements" do - let(:dscl_exists) { true } - let(:plutil_exists) { true } - - before do - ::File.stub(:exists?).with("/usr/bin/dscl").and_return(dscl_exists) - ::File.stub(:exists?).with("/usr/bin/plutil").and_return(plutil_exists) - end - - def run_requirements - provider.define_resource_requirements - provider.action = :create - provider.process_resource_requirements - end - - describe "when dscl doesn't exist" do - let(:dscl_exists) { false } - - it "should raise an error" do - lambda { run_requirements }.should raise_error - end - end - - describe "when plutil doesn't exist" do - let(:plutil_exists) { false } - - it "should raise an error" do - lambda { run_requirements }.should raise_error - end - end - - describe "when on Mac 10.6" do - let(:mac_version) { - "10.6.5" - } - - it "should raise an error" do - lambda { run_requirements }.should raise_error - end - end - - describe "when on Mac 10.7" do - let(:mac_version) { - "10.7.5" - } - - describe "when password is SALTED-SHA512" do - let(:password) { salted_sha512_password } - - it "should not raise an error" do - lambda { run_requirements }.should_not raise_error - end - end - - describe "when password is SALTED-SHA512-PBKDF2" do - let(:password) { salted_sha512_pbkdf2_password } - - it "should raise an error" do - lambda { run_requirements }.should raise_error - end - end - end - - [ "10.9", "10.10"].each do |version| - describe "when on Mac #{version}" do - let(:mac_version) { - "#{version}.2" - } - - describe "when password is SALTED-SHA512" do - let(:password) { salted_sha512_password } - - it "should raise an error" do - lambda { run_requirements }.should raise_error - end - end - - describe "when password is SALTED-SHA512-PBKDF2" do - let(:password) { salted_sha512_pbkdf2_password } - - describe "when salt and iteration is not set" do - it "should raise an error" do - lambda { run_requirements }.should raise_error - end - end - - describe "when salt and iteration is set" do - let(:salt) { salted_sha512_pbkdf2_salt } - let(:iterations) { salted_sha512_pbkdf2_iterations } - - it "should not raise an error" do - lambda { run_requirements }.should_not raise_error - end - end - end - end - end - end - - describe "load_current_resource" do - # set this to any of the user plist files under spec/data - let(:user_plist_file) { nil } - - before do - provider.should_receive(:shell_out).with("dscacheutil '-flushcache'") - provider.should_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) - else - ShellCmdResult.new(File.read(File.join(CHEF_SPEC_DATA, "mac_users/#{user_plist_file}.plist.xml")), "", 0) - end - end - - if !user_plist_file.nil? - provider.should_receive(:convert_binary_plist_to_xml).and_return(File.read(File.join(CHEF_SPEC_DATA, "mac_users/#{user_plist_file}.shadow.xml"))) - end - end - - describe "when user is not there" do - it "shouldn't raise an error" do - lambda { provider.load_current_resource }.should_not raise_error - end - - it "should set @user_exists" do - provider.load_current_resource - provider.instance_variable_get(:@user_exists).should be_false - end - - it "should set username" do - provider.load_current_resource - provider.current_resource.username.should eq("toor") - end - end - - describe "when user is there" do - let(:password) { "something" } # Load password during load_current_resource - - describe "on 10.7" do - let(:mac_version) { - "10.7.5" - } - - let(:user_plist_file) { "10.7" } - - it "collects the user data correctly" do - provider.load_current_resource - provider.current_resource.comment.should eq("vagrant") - provider.current_resource.uid.should eq("11112222-3333-4444-AAAA-BBBBCCCCDDDD") - provider.current_resource.gid.should eq("80") - provider.current_resource.home.should eq("/Users/vagrant") - provider.current_resource.shell.should eq("/bin/bash") - provider.current_resource.password.should eq(vagrant_sha_512) - end - - describe "when a plain password is set that is same" do - let(:password) { "vagrant" } - - it "diverged_password? should report false" do - provider.load_current_resource - provider.diverged_password?.should be_false - end - end - - describe "when a plain password is set that is different" do - let(:password) { "not_vagrant" } - - it "diverged_password? should report true" do - provider.load_current_resource - provider.diverged_password?.should be_true - end - end - - describe "when iterations change" do - let(:password) { vagrant_sha_512 } - let(:iterations) { 12345 } - - it "diverged_password? should report false" do - provider.load_current_resource - provider.diverged_password?.should be_false - end - end - - describe "when shadow hash changes" do - let(:password) { salted_sha512_password } - - it "diverged_password? should report true" do - provider.load_current_resource - provider.diverged_password?.should be_true - end - end - - describe "when salt change" do - let(:password) { vagrant_sha_512 } - let(:salt) { "SOMETHINGRANDOM" } - - it "diverged_password? should report false" do - provider.load_current_resource - provider.diverged_password?.should be_false - end - end - end - - describe "on 10.8" do - let(:mac_version) { - "10.8.3" - } - - let(:user_plist_file) { "10.8" } - - it "collects the user data correctly" do - provider.load_current_resource - provider.current_resource.comment.should eq("vagrant") - provider.current_resource.uid.should eq("11112222-3333-4444-AAAA-BBBBCCCCDDDD") - provider.current_resource.gid.should eq("80") - provider.current_resource.home.should eq("/Users/vagrant") - provider.current_resource.shell.should eq("/bin/bash") - provider.current_resource.password.should eq("ea4c2d265d801ba0ec0dfccd\ -253dfc1de91cbe0806b4acc1ed7fe22aebcf6beb5344d0f442e590\ -ffa04d679075da3afb119e41b72b5eaf08ee4aa54693722646d5\ -19ee04843deb8a3e977428d33f625e83887913e5c13b70035961\ -5e00ad7bc3e7a0c98afc3e19d1360272454f8d33a9214d2fbe8b\ -e68d1f9821b26689312366") - provider.current_resource.salt.should eq("f994ef2f73b7c5594ebd1553300976b20733ce0e24d659783d87f3d81cbbb6a9") - provider.current_resource.iterations.should eq(39840) - end - end - - describe "on 10.7 upgraded to 10.8" do - # In this scenario user password is still in 10.7 format - let(:mac_version) { - "10.8.3" - } - - let(:user_plist_file) { "10.7-8" } - - it "collects the user data correctly" do - provider.load_current_resource - provider.current_resource.comment.should eq("vagrant") - provider.current_resource.uid.should eq("11112222-3333-4444-AAAA-BBBBCCCCDDDD") - provider.current_resource.gid.should eq("80") - provider.current_resource.home.should eq("/Users/vagrant") - provider.current_resource.shell.should eq("/bin/bash") - provider.current_resource.password.should eq("6f75d7190441facc34291ebbea1fc756b242d4f\ -e9bcff141bccb84f1979e27e539539aa31f9f7dcc92c0cea959\ -ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30") - end - - describe "when a plain text password is set" do - it "reports password needs to be updated" do - provider.load_current_resource - provider.diverged_password?.should be_true - end - end - - describe "when a salted-sha512-pbkdf2 shadow is set" do - let(:password) { salted_sha512_pbkdf2_password } - let(:salt) { salted_sha512_pbkdf2_salt } - let(:iterations) { salted_sha512_pbkdf2_iterations } - - it "reports password needs to be updated" do - provider.load_current_resource - provider.diverged_password?.should be_true - end - end - end - - describe "on 10.9" do - let(:mac_version) { - "10.9.1" - } - - let(:user_plist_file) { "10.9" } - - it "collects the user data correctly" do - provider.load_current_resource - provider.current_resource.comment.should eq("vagrant") - provider.current_resource.uid.should eq("11112222-3333-4444-AAAA-BBBBCCCCDDDD") - provider.current_resource.gid.should eq("80") - provider.current_resource.home.should eq("/Users/vagrant") - provider.current_resource.shell.should eq("/bin/bash") - provider.current_resource.password.should eq(vagrant_sha_512_pbkdf2) - provider.current_resource.salt.should eq(vagrant_sha_512_pbkdf2_salt) - provider.current_resource.iterations.should eq(vagrant_sha_512_pbkdf2_iterations) - end - - describe "when a plain password is set that is same" do - let(:password) { "vagrant" } - - it "diverged_password? should report false" do - provider.load_current_resource - provider.diverged_password?.should be_false - end - end - - describe "when a plain password is set that is different" do - let(:password) { "not_vagrant" } - - it "diverged_password? should report true" do - provider.load_current_resource - provider.diverged_password?.should be_true - end - end - - describe "when iterations change" do - let(:password) { vagrant_sha_512_pbkdf2 } - let(:salt) { vagrant_sha_512_pbkdf2_salt } - let(:iterations) { 12345 } - - it "diverged_password? should report true" do - provider.load_current_resource - provider.diverged_password?.should be_true - end - end - - describe "when shadow hash changes" do - let(:password) { salted_sha512_pbkdf2_password } - let(:salt) { vagrant_sha_512_pbkdf2_salt } - let(:iterations) { vagrant_sha_512_pbkdf2_iterations } - - it "diverged_password? should report true" do - provider.load_current_resource - provider.diverged_password?.should be_true - end - end - - describe "when salt change" do - let(:password) { vagrant_sha_512_pbkdf2 } - let(:salt) { salted_sha512_pbkdf2_salt } - let(:iterations) { vagrant_sha_512_pbkdf2_iterations } - - it "diverged_password? should report true" do - provider.load_current_resource - provider.diverged_password?.should be_true - end - end - end - end - end - - describe "salted_sha512_pbkdf2?" do - it "should return true when the string is a salted_sha512_pbkdf2 hash" do - provider.salted_sha512_pbkdf2?(salted_sha512_pbkdf2_password).should be_true - end - - it "should return false otherwise" do - provider.salted_sha512_pbkdf2?(salted_sha512_password).should be_false - provider.salted_sha512_pbkdf2?("any other string").should be_false - end - end - - describe "salted_sha512?" do - it "should return true when the string is a salted_sha512_pbkdf2 hash" do - provider.salted_sha512_pbkdf2?(salted_sha512_pbkdf2_password).should be_true - end - - it "should return false otherwise" do - provider.salted_sha512?(salted_sha512_pbkdf2_password).should be_false - provider.salted_sha512?("any other string").should be_false - end - end - - describe "prepare_password_shadow_info" do - describe "when on Mac 10.7" do - let(:mac_version) { - "10.7.1" - } - - describe "when the password is plain text" do - let(:password) { "vagrant" } - - it "password_shadow_info should have salted-sha-512 format" do - shadow_info = provider.prepare_password_shadow_info - shadow_info.should have_key("SALTED-SHA512") - info = shadow_info["SALTED-SHA512"].string.unpack('H*').first - provider.salted_sha512?(info).should be_true - end - end - - describe "when the password is salted-sha-512" do - let(:password) { vagrant_sha_512 } - - it "password_shadow_info should have salted-sha-512 format" do - shadow_info = provider.prepare_password_shadow_info - shadow_info.should have_key("SALTED-SHA512") - info = shadow_info["SALTED-SHA512"].string.unpack('H*').first - provider.salted_sha512?(info).should be_true - info.should eq(vagrant_sha_512) - end - end - end - - ["10.8", "10.9", "10.10"].each do |version| - describe "when on Mac #{version}" do - let(:mac_version) { - "#{version}.1" - } - - describe "when the password is plain text" do - let(:password) { "vagrant" } - - it "password_shadow_info should have salted-sha-512 format" do - shadow_info = provider.prepare_password_shadow_info - shadow_info.should have_key("SALTED-SHA512-PBKDF2") - shadow_info["SALTED-SHA512-PBKDF2"].should have_key("entropy") - shadow_info["SALTED-SHA512-PBKDF2"].should have_key("salt") - shadow_info["SALTED-SHA512-PBKDF2"].should have_key("iterations") - info = shadow_info["SALTED-SHA512-PBKDF2"]["entropy"].string.unpack('H*').first - provider.salted_sha512_pbkdf2?(info).should be_true - end - end - - describe "when the password is salted-sha-512" do - let(:password) { vagrant_sha_512_pbkdf2 } - let(:iterations) { vagrant_sha_512_pbkdf2_iterations } - let(:salt) { vagrant_sha_512_pbkdf2_salt } - - it "password_shadow_info should have salted-sha-512 format" do - shadow_info = provider.prepare_password_shadow_info - shadow_info.should have_key("SALTED-SHA512-PBKDF2") - shadow_info["SALTED-SHA512-PBKDF2"].should have_key("entropy") - shadow_info["SALTED-SHA512-PBKDF2"].should have_key("salt") - shadow_info["SALTED-SHA512-PBKDF2"].should have_key("iterations") - info = shadow_info["SALTED-SHA512-PBKDF2"]["entropy"].string.unpack('H*').first - provider.salted_sha512_pbkdf2?(info).should be_true - info.should eq(vagrant_sha_512_pbkdf2) - end - end - end - end - end - - describe "set_password" do - before do - new_resource.password("something") - end - - it "should sleep and flush the dscl cache before saving the password" do - provider.should_receive(:prepare_password_shadow_info).and_return({ }) - mock_shellout = double("Mock::Shellout") - mock_shellout.stub(:run_command) - Mixlib::ShellOut.should_receive(:new).and_return(mock_shellout) - provider.should_receive(:read_user_info) - provider.should_receive(:dscl_set) - provider.should_receive(:sleep).with(3) - provider.should_receive(:save_user_info) - provider.set_password - end - end - - describe "when the user does not yet exist and chef is creating it" do - context "with a numeric gid" do - before do - new_resource.comment "#mockssuck" - new_resource.gid 1001 - end - - it "creates the user, comment field, sets uid, gid, configures the home directory, sets the shell, and sets the password" do - provider.should_receive :dscl_create_user - provider.should_receive :dscl_create_comment - provider.should_receive :dscl_set_uid - provider.should_receive :dscl_set_gid - provider.should_receive :dscl_set_home - provider.should_receive :dscl_set_shell - provider.should_receive :set_password - provider.create_user - end - - it "creates the user and sets the comment field" do - provider.should_receive(:run_dscl).with("create /Users/toor").and_return(true) - provider.dscl_create_user - end - - it "sets the comment field" do - provider.should_receive(:run_dscl).with("create /Users/toor RealName '#mockssuck'").and_return(true) - provider.dscl_create_comment - end - - it "should run run_dscl with create /Users/user PrimaryGroupID to set the users primary group" do - provider.should_receive(:run_dscl).with("create /Users/toor PrimaryGroupID '1001'").and_return(true) - provider.dscl_set_gid - end - - it "should run run_dscl with create /Users/user UserShell to set the users login shell" do - provider.should_receive(:run_dscl).with("create /Users/toor UserShell '/usr/bin/false'").and_return(true) - provider.dscl_set_shell - end - end - - context "with a non-numeric gid" do - before do - new_resource.comment "#mockssuck" - new_resource.gid "newgroup" - end - - it "should map the group name to a numeric ID when the group exists" do - provider.should_receive(:run_dscl).with("read /Groups/newgroup PrimaryGroupID").ordered.and_return("PrimaryGroupID: 1001\n") - provider.should_receive(:run_dscl).with("create /Users/toor PrimaryGroupID '1001'").ordered.and_return(true) - provider.dscl_set_gid - 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) - provider.should_receive(:shell_out).with('dscl . -read /Groups/newgroup PrimaryGroupID').and_return(shell_return) - lambda { provider.dscl_set_gid }.should raise_error(Chef::Exceptions::GroupIDNotFound) - end - end - end - - describe "when the user exists and chef is managing it" do - before do - current_resource = new_resource.dup - provider.current_resource = current_resource - - # These are all different from current_resource - new_resource.username "mud" - new_resource.uid 2342 - new_resource.gid 2342 - 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 - provider.should_receive :dscl_create_user - provider.should_receive :dscl_create_comment - provider.should_receive :dscl_set_uid - provider.should_receive :dscl_set_gid - provider.should_receive :dscl_set_home - provider.should_receive :dscl_set_shell - provider.should_receive :set_password - provider.create_user - end - end - - describe "when changing the gid" do - before do - current_resource = new_resource.dup - provider.current_resource = current_resource - - # This is different from current_resource - new_resource.gid 2342 - end - - it "sets the gid" do - provider.should_receive :dscl_set_gid - provider.manage_user - end - end - - describe "when the user exists" do - before do - provider.should_receive(:shell_out).with("dscacheutil '-flushcache'") - provider.should_receive(:shell_out).with("plutil -convert xml1 -o - /var/db/dslocal/nodes/Default/users/toor.plist") do - ShellCmdResult.new(File.read(File.join(CHEF_SPEC_DATA, "mac_users/10.9.plist.xml")), "", 0) - end - provider.load_current_resource - end - - describe "when Chef is removing the user" do - it "removes the user from the groups and deletes home directory when the resource is configured to manage home" do - new_resource.supports({ :manage_home => true }) - provider.should_receive(:run_dscl).with("list /Groups").and_return("my_group\nyour_group\nreal_group\n") - provider.should_receive(:run_dscl).with("read /Groups/my_group").and_raise(Chef::Exceptions::DsclCommandFailed) # Empty group - provider.should_receive(:run_dscl).with("read /Groups/your_group").and_return("GroupMembership: not_you") - provider.should_receive(:run_dscl).with("read /Groups/real_group").and_return("GroupMembership: toor") - provider.should_receive(:run_dscl).with("delete /Groups/real_group GroupMembership 'toor'") - provider.should_receive(:run_dscl).with("delete /Users/toor") - FileUtils.should_receive(:rm_rf).with("/Users/vagrant") - provider.remove_user - end - end - - describe "when user is not locked" do - it "determines the user as not locked" do - provider.should_not be_locked - end - end - - describe "when user is locked" do - before do - auth_authority = provider.instance_variable_get(:@authentication_authority) - provider.instance_variable_set(:@authentication_authority, auth_authority + ";DisabledUser;") - end - - it "determines the user as not locked" do - provider.should be_locked - end - - it "can unlock the user" do - provider.should_receive(:run_dscl).with("create /Users/toor AuthenticationAuthority ';ShadowHash;HASHLIST:<SALTED-SHA512-PBKDF2>'") - provider.unlock_user - end - end - end - - describe "when locking the user" do - it "should run run_dscl with append /Users/user AuthenticationAuthority ;DisabledUser; to lock the user account" do - provider.should_receive(:run_dscl).with("append /Users/toor AuthenticationAuthority ';DisabledUser;'") - provider.lock_user - end - end - -end diff --git a/spec/unit/provider/user/pw_spec.rb b/spec/unit/provider/user/pw_spec.rb deleted file mode 100644 index a577a57de9..0000000000 --- a/spec/unit/provider/user/pw_spec.rb +++ /dev/null @@ -1,252 +0,0 @@ -# -# Author:: Stephen Haynes (<sh@nomitor.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' - -describe Chef::Provider::User::Pw 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("adam") - @new_resource.comment "Adam Jacob" - @new_resource.uid 1000 - @new_resource.gid 1000 - @new_resource.home "/home/adam" - @new_resource.shell "/usr/bin/zsh" - @new_resource.password "abracadabra" - - @new_resource.supports :manage_home => true - - @current_resource = Chef::Resource::User.new("adam") - @current_resource.comment "Adam Jacob" - @current_resource.uid 1000 - @current_resource.gid 1000 - @current_resource.home "/home/adam" - @current_resource.shell "/usr/bin/zsh" - @current_resource.password "abracadabra" - - @provider = Chef::Provider::User::Pw.new(@new_resource, @run_context) - @provider.current_resource = @current_resource - end - - describe "setting options to the pw command" do - field_list = { - '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 - @current_resource.should_receive(attribute) - @new_resource.should_receive(attribute) - @provider.set_options - end - - it "should set the option for #{attribute} if the new resources #{attribute} is not null" do - @new_resource.stub(attribute).and_return("hola") - @provider.set_options.should eql(" #{@new_resource.username} #{option} '#{@new_resource.send(attribute)}' -m") - end - - it "should set the option for #{attribute} if the new resources #{attribute} is not null, without homedir management" do - @new_resource.stub(:supports).and_return({:manage_home => false}) - @new_resource.stub(attribute).and_return("hola") - @provider.set_options.should eql(" #{@new_resource.username} #{option} '#{@new_resource.send(attribute)}'") - end - end - - it "should combine all the possible options" do - match_string = " adam" - field_list.sort{ |a,b| a[0] <=> b[0] }.each do |attribute, option| - @new_resource.stub(attribute).and_return("hola") - match_string << " #{option} 'hola'" - end - match_string << " -m" - @provider.set_options.should eql(match_string) - end - end - - describe "create_user" do - before(:each) do - @provider.stub(:run_command).and_return(true) - @provider.stub(:modify_password).and_return(true) - end - - it "should run pw useradd with the return of set_options" do - @provider.should_receive(:run_command).with({ :command => "pw useradd adam -m" }).and_return(true) - @provider.create_user - end - - it "should modify the password" do - @provider.should_receive(:modify_password).and_return(true) - @provider.create_user - end - end - - describe "manage_user" do - before(:each) do - @provider.stub(:run_command).and_return(true) - @provider.stub(:modify_password).and_return(true) - end - - it "should run pw usermod with the return of set_options" do - @provider.should_receive(:run_command).with({ :command => "pw usermod adam -m" }).and_return(true) - @provider.manage_user - end - - it "should modify the password" do - @provider.should_receive(:modify_password).and_return(true) - @provider.create_user - end - end - - describe "remove_user" do - it "should run pw userdel with the new resources user name" do - @new_resource.supports :manage_home => false - @provider.should_receive(:run_command).with({ :command => "pw userdel #{@new_resource.username}" }).and_return(true) - @provider.remove_user - end - - it "should run pw userdel with the new resources user name and -r if manage_home is true" do - @provider.should_receive(:run_command).with({ :command => "pw userdel #{@new_resource.username} -r"}).and_return(true) - @provider.remove_user - end - end - - describe "determining if the user is locked" do - it "should return true if user is locked" do - @current_resource.stub(:password).and_return("*LOCKED*abracadabra") - @provider.check_lock.should eql(true) - end - - it "should return false if user is not locked" do - @current_resource.stub(:password).and_return("abracadabra") - @provider.check_lock.should eql(false) - end - end - - describe "when locking the user" do - it "should run pw lock with the new resources username" do - @provider.should_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 - @provider.should_receive(:run_command).with({ :command => "pw unlock #{@new_resource.username}"}) - @provider.unlock_user - end - end - - describe "when modifying the password" do - before(:each) do - @status = double("Status", :exitstatus => 0) - @provider.stub(:popen4).and_return(@status) - @pid, @stdin, @stdout, @stderr = nil, nil, nil, nil - end - - describe "and the new password has not been specified" do - before(:each) do - @new_resource.stub(:password).and_return(nil) - end - - it "logs an appropriate message" do - Chef::Log.should_receive(:debug).with("user[adam] no change needed to password") - @provider.modify_password - end - end - - describe "and the new password has been specified" do - before(:each) do - @new_resource.stub(:password).and_return("abracadabra") - end - - it "should check for differences in password between the new and current resources" do - @current_resource.should_receive(:password) - @new_resource.should_receive(:password) - @provider.modify_password - end - end - - describe "and the passwords are identical" do - before(:each) do - @new_resource.stub(:password).and_return("abracadabra") - @current_resource.stub(:password).and_return("abracadabra") - end - - it "logs an appropriate message" do - Chef::Log.should_receive(:debug).with("user[adam] no change needed to password") - @provider.modify_password - end - end - - describe "and the passwords are different" do - before(:each) do - @new_resource.stub(:password).and_return("abracadabra") - @current_resource.stub(:password).and_return("sesame") - end - - it "should log an appropriate message" do - Chef::Log.should_receive(:debug).with("user[adam] updating password") - @provider.modify_password - end - - it "should run pw usermod with the username and the option -H 0" do - @provider.should_receive(:popen4).with("pw usermod adam -H 0", :waitlast => true).and_return(@status) - @provider.modify_password - end - - it "should send the new password to the stdin of pw usermod" do - @stdin = StringIO.new - @provider.stub(:popen4).and_yield(@pid, @stdin, @stdout, @stderr).and_return(@status) - @provider.modify_password - @stdin.string.should == "abracadabra\n" - end - - it "should raise an exception if pw usermod fails" do - @status.should_receive(:exitstatus).and_return(1) - lambda { @provider.modify_password }.should raise_error(Chef::Exceptions::User) - end - - it "should not raise an exception if pw usermod succeeds" do - @status.should_receive(:exitstatus).and_return(0) - lambda { @provider.modify_password }.should_not raise_error - end - end - end - - describe "when loading the current state" do - before do - @provider.new_resource = Chef::Resource::User.new("adam") - end - - it "should raise an error if the required binary /usr/sbin/pw doesn't exist" do - File.should_receive(:exists?).with("/usr/sbin/pw").and_return(false) - lambda { @provider.load_current_resource }.should raise_error(Chef::Exceptions::User) - end - - it "shouldn't raise an error if /usr/sbin/pw exists" do - File.stub(:exists?).and_return(true) - lambda { @provider.load_current_resource }.should_not raise_error - end - end -end diff --git a/spec/unit/provider/user/solaris_spec.rb b/spec/unit/provider/user/solaris_spec.rb deleted file mode 100644 index d8bd0f9e75..0000000000 --- a/spec/unit/provider/user/solaris_spec.rb +++ /dev/null @@ -1,80 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: Daniel DeLeo (<dan@opscode.com>) -# Copyright:: Copyright (c) 2008, 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. -# - -require 'spec_helper' - -describe Chef::Provider::User::Solaris do - - subject(:provider) do - p = described_class.new(@new_resource, @run_context) - p.current_resource = @current_resource - - # Prevent the useradd-based provider tests from trying to write /etc/shadow - p.stub(:write_shadow_file) - 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 - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - - @new_resource = Chef::Resource::User.new("adam", @run_context) - @current_resource = Chef::Resource::User.new("adam", @run_context) - - @new_resource.password "hocus-pocus" - - # Let these tests run #write_shadow_file - provider.unstub(:write_shadow_file) - end - - it "should use its own shadow file writer to set the password" do - provider.should_receive(:write_shadow_file) - provider.stub(:shell_out!).and_return(true) - provider.manage_user - end - - it "should write out a modified version of the password file" do - password_file = Tempfile.new("shadow") - password_file.puts "adam:existingpassword:15441::::::" - password_file.close - provider.password_file = password_file.path - provider.stub(:shell_out!).and_return(true) - # may not be able to write to /etc for tests... - temp_file = Tempfile.new("shadow") - Tempfile.stub(:new).with("shadow", "/etc").and_return(temp_file) - @new_resource.password "verysecurepassword" - provider.manage_user - ::File.open(password_file.path, "r").read.should =~ /adam:verysecurepassword:/ - password_file.unlink - end - end - -end diff --git a/spec/unit/provider/user/useradd_spec.rb b/spec/unit/provider/user/useradd_spec.rb deleted file mode 100644 index a65da3f9e1..0000000000 --- a/spec/unit/provider/user/useradd_spec.rb +++ /dev/null @@ -1,51 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: Daniel DeLeo (<dan@opscode.com>) -# Copyright:: Copyright (c) 2008, 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. -# - -require 'spec_helper' -require 'chef/provider/user/useradd' - -describe Chef::Provider::User::Useradd do - - subject(:provider) do - p = described_class.new(@new_resource, @run_context) - p.current_resource = @current_resource - p - end - - supported_useradd_options = { - 'comment' => "-c", - 'gid' => "-g", - 'uid' => "-u", - 'shell' => "-s", - 'password' => "-p" - } - - include_examples "a useradd-based user provider", supported_useradd_options - - describe "manage_user" do - # CHEF-5247: Chef::Provider::User::Solaris subclasses Chef::Provider::User::Useradd, but does not use usermod to change passwords. - # Thus, a call to Solaris#manage_user calls Solaris#manage_password and Useradd#manage_user, but the latter should be a no-op. - it "should not run the command if universal_options is an empty array" do - provider.stub(:universal_options).and_return([]) - expect(provider).not_to receive(:shell_out!) - provider.manage_user - end - end -end diff --git a/spec/unit/provider/user/windows_spec.rb b/spec/unit/provider/user/windows_spec.rb deleted file mode 100644 index 45a1c61c41..0000000000 --- a/spec/unit/provider/user/windows_spec.rb +++ /dev/null @@ -1,185 +0,0 @@ -# -# Author:: Doug MacEachern (<dougm@vmware.com>) -# Copyright:: Copyright (c) 2010 VMware, 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 Chef - class Util - class Windows - class NetUser - end - end - end -end - -describe Chef::Provider::User::Windows do - before(:each) do - @node = Chef::Node.new - @new_resource = Chef::Resource::User.new("monkey") - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - @current_resource = Chef::Resource::User.new("monkey") - - @net_user = double("Chef::Util::Windows::NetUser") - Chef::Util::Windows::NetUser.stub(:new).and_return(@net_user) - - @provider = Chef::Provider::User::Windows.new(@new_resource, @run_context) - @provider.current_resource = @current_resource - end - - it "creates a net_user object with the provided username" do - @new_resource.username "not-monkey" - expect(Chef::Util::Windows::NetUser).to receive(:new).with("not-monkey") - @provider = Chef::Provider::User::Windows.new(@new_resource, @run_context) - end - - describe "when comparing the user's current attributes to the desired attributes" do - before do - @new_resource.comment "Adam Jacob" - @new_resource.uid 1000 - @new_resource.gid 1000 - @new_resource.home "/home/adam" - @new_resource.shell "/usr/bin/zsh" - @new_resource.password "abracadabra" - - @provider.current_resource = @new_resource.clone - end - - describe "and the attributes match" do - it "doesn't set the comment field to be updated" do - @provider.set_options.should_not have_key(:full_name) - end - - it "doesn't set the home directory to be updated" do - @provider.set_options.should_not have_key(:home_dir) - end - - it "doesn't set the group id to be updated" do - @provider.set_options.should_not have_key(:primary_group_id) - end - - it "doesn't set the user id to be updated" do - @provider.set_options.should_not have_key(:user_id) - end - - it "doesn't set the shell to be updated" do - @provider.set_options.should_not have_key(:script_path) - end - - it "doesn't set the password to be updated" do - @provider.set_options.should_not have_key(:password) - end - - end - - describe "and the attributes do not match" do - before do - @current_resource = Chef::Resource::User.new("adam") - @current_resource.comment "Adam Jacob-foo" - @current_resource.uid 1111 - @current_resource.gid 1111 - @current_resource.home "/home/adam-foo" - @current_resource.shell "/usr/bin/tcsh" - @current_resource.password "foobarbaz" - @provider.current_resource = @current_resource - end - - it "marks the full_name field to be updated" do - @provider.set_options[:full_name].should == "Adam Jacob" - end - - it "marks the home_dir attribute to be updated" do - @provider.set_options[:home_dir].should == '/home/adam' - end - - it "marks the primary_group_id attribute to be updated" do - @provider.set_options[:primary_group_id].should == 1000 - end - - it "marks the user_id attribute to be updated" do - @provider.set_options[:user_id].should == 1000 - end - - it "marks the script_path attribute to be updated" do - @provider.set_options[:script_path].should == '/usr/bin/zsh' - end - - it "marks the password attribute to be updated" do - @provider.set_options[:password].should == 'abracadabra' - end - end - end - - describe "when creating the user" do - it "should call @net_user.add with the return of set_options" do - @provider.stub(:set_options).and_return(:name=> "monkey") - @net_user.should_receive(:add).with(:name=> "monkey") - @provider.create_user - end - end - - describe "manage_user" do - before(:each) do - @provider.stub(:set_options).and_return(:name=> "monkey") - end - - it "should call @net_user.update with the return of set_options" do - @net_user.should_receive(:update).with(:name=> "monkey") - @provider.manage_user - end - end - - describe "when removing the user" do - it "should call @net_user.delete" do - @net_user.should_receive(:delete) - @provider.remove_user - end - end - - describe "when checking if the user is locked" do - before(:each) do - @current_resource.password "abracadabra" - end - - it "should return true if user is locked" do - @net_user.stub(:check_enabled).and_return(true) - @provider.check_lock.should eql(true) - end - - it "should return false if user is not locked" do - @net_user.stub(:check_enabled).and_return(false) - @provider.check_lock.should eql(false) - end - end - - describe "locking the user" do - it "should call @net_user.disable_account" do - @net_user.stub(:check_enabled).and_return(true) - @net_user.should_receive(:disable_account) - @provider.lock_user - end - end - - describe "unlocking the user" do - it "should call @net_user.enable_account" do - @net_user.stub(:check_enabled).and_return(false) - @net_user.should_receive(:enable_account) - @provider.unlock_user - end - end -end diff --git a/spec/unit/provider/user_spec.rb b/spec/unit/provider/user_spec.rb deleted file mode 100644 index 153db6f283..0000000000 --- a/spec/unit/provider/user_spec.rb +++ /dev/null @@ -1,466 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -EtcPwnamIsh = Struct.new(:name, :passwd, :uid, :gid, :gecos, :dir, :shell, :change, :uclass, :expire) -EtcGrnamIsh = Struct.new(:name, :passwd, :gid, :mem) - -describe Chef::Provider::User 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("adam") - @new_resource.comment "Adam Jacob" - @new_resource.uid 1000 - @new_resource.gid 1000 - @new_resource.home "/home/adam" - @new_resource.shell "/usr/bin/zsh" - - @current_resource = Chef::Resource::User.new("adam") - @current_resource.comment "Adam Jacob" - @current_resource.uid 1000 - @current_resource.gid 1000 - @current_resource.home "/home/adam" - @current_resource.shell "/usr/bin/zsh" - - @provider = Chef::Provider::User.new(@new_resource, @run_context) - @provider.current_resource = @current_resource - end - - describe "when first created" do - it "assume the user exists by default" do - @provider.user_exists.should eql(true) - end - - it "does not know the locked state" do - @provider.locked.should eql(nil) - end - end - - describe "executing load_current_resource" do - before(:each) do - @node = Chef::Node.new - #@new_resource = double("Chef::Resource::User", - # :null_object => true, - # :username => "adam", - # :comment => "Adam Jacob", - # :uid => 1000, - # :gid => 1000, - # :home => "/home/adam", - # :shell => "/usr/bin/zsh", - # :password => nil, - # :updated => nil - #) - Chef::Resource::User.stub(:new).and_return(@current_resource) - @pw_user = EtcPwnamIsh.new - @pw_user.name = "adam" - @pw_user.gid = 1000 - @pw_user.uid = 1000 - @pw_user.gecos = "Adam Jacob" - @pw_user.dir = "/home/adam" - @pw_user.shell = "/usr/bin/zsh" - @pw_user.passwd = "*" - Etc.stub(:getpwnam).and_return(@pw_user) - end - - it "should create a current resource with the same name as the new resource" do - @provider.load_current_resource - @provider.current_resource.name.should == 'adam' - end - - it "should set the username of the current resource to the username of the new resource" do - @provider.load_current_resource - @current_resource.username.should == @new_resource.username - end - - it "should change the encoding of gecos to the encoding of the new resource", :ruby_gte_19_only do - @pw_user.gecos.force_encoding('ASCII-8BIT') - @provider.load_current_resource - @provider.current_resource.comment.encoding.should == @new_resource.comment.encoding - end - - it "should look up the user in /etc/passwd with getpwnam" do - Etc.should_receive(:getpwnam).with(@new_resource.username).and_return(@pw_user) - @provider.load_current_resource - end - - it "should set user_exists to false if the user is not found with getpwnam" do - Etc.should_receive(:getpwnam).and_raise(ArgumentError) - @provider.load_current_resource - @provider.user_exists.should eql(false) - end - - # The mapping between the Chef::Resource::User and Getpwnam struct - user_attrib_map = { - :uid => :uid, - :gid => :gid, - :comment => :gecos, - :home => :dir, - :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 - @current_resource.should_receive(user_attrib).with(@pw_user.send(getpwnam_attrib)) - @provider.load_current_resource - end - end - - it "should attempt to convert the group gid if one has been supplied" do - @provider.should_receive(:convert_group_name) - @provider.load_current_resource - end - - it "shouldn't try and convert the group gid if none has been supplied" do - @new_resource.stub(:gid).and_return(nil) - @provider.should_not_receive(:convert_group_name) - @provider.load_current_resource - end - - it "should return the current resource" do - @provider.load_current_resource.should eql(@current_resource) - end - - 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" - true - else - false - end - end - - before (:each) do - user = @pw_user.dup - user.name = "root" - user.passwd = "x" - @new_resource.password "some new password" - Etc.stub(:getpwnam).and_return(user) - end - - 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 - - context "and we are root", :requires_root => true do - it "should pass assertions when ruby-shadow can be loaded" do - @provider.action = 'create' - original_method = @provider.method(:require) - @provider.should_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, - :sp_warn => 7, :sp_inact => -1, :sp_expire => -1, :sp_flag => -1) - Shadow::Passwd.should_receive(:getspnam).with("adam").and_return(passwd_info) - @provider.load_current_resource - @provider.define_resource_requirements - @provider.process_resource_requirements - end - end - end - end - - it "should fail assertions when ruby-shadow cannot be loaded" do - @provider.should_receive(:require).with("shadow") { raise LoadError } - @provider.load_current_resource - @provider.define_resource_requirements - lambda {@provider.process_resource_requirements}.should raise_error Chef::Exceptions::MissingLibrary - end - - end - end - - 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"] - } - } - - %w{uid gid comment home shell password}.each do |attribute| - it "should return true if #{attribute} doesn't match" do - @new_resource.send(attribute, mapping[attribute][0]) - @current_resource.send(attribute, mapping[attribute][1]) - @provider.compare_user.should eql(true) - end - end - - %w{uid gid}.each do |attribute| - it "should return false if string #{attribute} matches fixnum" do - @new_resource.send(attribute, "100") - @current_resource.send(attribute, 100) - @provider.compare_user.should eql(false) - end - end - - it "should return false if the objects are identical" do - @provider.compare_user.should eql(false) - end - end - - describe "action_create" do - before(:each) do - @provider.stub(:load_current_resource) - # @current_resource = double("Chef::Resource::User", - # :null_object => true, - # :username => "adam", - # :comment => "Adam Jacob", - # :uid => 1000, - # :gid => 1000, - # :home => "/home/adam", - # :shell => "/usr/bin/zsh", - # :password => nil, - # :updated => nil - # ) - # @provider = Chef::Provider::User.new(@node, @new_resource) - # @provider.current_resource = @current_resource - # @provider.user_exists = false - # @provider.stub(:create_user).and_return(true) - # @provider.stub(:manage_user).and_return(true) - end - - it "should call create_user if the user does not exist" do - @provider.user_exists = false - @provider.should_receive(:create_user).and_return(true) - @provider.action_create - @provider.set_updated_status - @new_resource.should be_updated - end - - it "should call manage_user if the user exists and has mismatched attributes" do - @provider.user_exists = true - @provider.stub(:compare_user).and_return(true) - @provider.should_receive(:manage_user).and_return(true) - @provider.action_create - end - - it "should set the new_resources updated flag when it creates the user if we call manage_user" do - @provider.user_exists = true - @provider.stub(:compare_user).and_return(true) - @provider.stub(:manage_user).and_return(true) - @provider.action_create - @provider.set_updated_status - @new_resource.should be_updated - end - end - - describe "action_remove" do - before(:each) do - @provider.stub(:load_current_resource) - end - - it "should not call remove_user if the user does not exist" do - @provider.user_exists = false - @provider.should_not_receive(:remove_user) - @provider.action_remove - end - - it "should call remove_user if the user exists" do - @provider.user_exists = true - @provider.should_receive(:remove_user) - @provider.action_remove - end - - it "should set the new_resources updated flag to true if the user is removed" do - @provider.user_exists = true - @provider.should_receive(:remove_user) - @provider.action_remove - @provider.set_updated_status - @new_resource.should be_updated - end - end - - describe "action_manage" do - before(:each) do - @provider.stub(:load_current_resource) - # @node = Chef::Node.new - # @new_resource = double("Chef::Resource::User", - # :null_object => true - # ) - # @current_resource = double("Chef::Resource::User", - # :null_object => true - # ) - # @provider = Chef::Provider::User.new(@node, @new_resource) - # @provider.current_resource = @current_resource - # @provider.user_exists = true - # @provider.stub(:manage_user).and_return(true) - end - - it "should run manage_user if the user exists and has mismatched attributes" do - @provider.should_receive(:compare_user).and_return(true) - @provider.should_receive(:manage_user).and_return(true) - @provider.action_manage - end - - it "should set the new resources updated flag to true if manage_user is called" do - @provider.stub(:compare_user).and_return(true) - @provider.stub(:manage_user).and_return(true) - @provider.action_manage - @provider.set_updated_status - @new_resource.should be_updated - end - - it "should not run manage_user if the user does not exist" do - @provider.user_exists = false - @provider.should_not_receive(:manage_user) - @provider.action_manage - end - - it "should not run manage_user if the user exists but has no differing attributes" do - @provider.should_receive(:compare_user).and_return(false) - @provider.should_not_receive(:manage_user) - @provider.action_manage - end - end - - describe "action_modify" do - before(:each) do - @provider.stub(:load_current_resource) - # @node = Chef::Node.new - # @new_resource = double("Chef::Resource::User", - # :null_object => true - # ) - # @current_resource = double("Chef::Resource::User", - # :null_object => true - # ) - # @provider = Chef::Provider::User.new(@node, @new_resource) - # @provider.current_resource = @current_resource - # @provider.user_exists = true - # @provider.stub(:manage_user).and_return(true) - end - - it "should run manage_user if the user exists and has mismatched attributes" do - @provider.should_receive(:compare_user).and_return(true) - @provider.should_receive(:manage_user).and_return(true) - @provider.action_modify - end - - it "should set the new resources updated flag to true if manage_user is called" do - @provider.stub(:compare_user).and_return(true) - @provider.stub(:manage_user).and_return(true) - @provider.action_modify - @provider.set_updated_status - @new_resource.should be_updated - end - - it "should not run manage_user if the user exists but has no differing attributes" do - @provider.should_receive(:compare_user).and_return(false) - @provider.should_not_receive(:manage_user) - @provider.action_modify - end - - it "should raise a Chef::Exceptions::User if the user doesn't exist" do - @provider.user_exists = false - lambda { @provider.action = :modify; @provider.run_action }.should raise_error(Chef::Exceptions::User) - end - end - - - describe "action_lock" do - before(:each) do - @provider.stub(:load_current_resource) - end - it "should lock the user if it exists and is unlocked" do - @provider.stub(:check_lock).and_return(false) - @provider.should_receive(:lock_user).and_return(true) - @provider.action_lock - end - - it "should set the new resources updated flag to true if lock_user is called" do - @provider.stub(:check_lock).and_return(false) - @provider.should_receive(:lock_user) - @provider.action_lock - @provider.set_updated_status - @new_resource.should be_updated - end - - it "should raise a Chef::Exceptions::User if we try and lock a user that does not exist" do - @provider.user_exists = false - @provider.action = :lock - - lambda { @provider.run_action }.should raise_error(Chef::Exceptions::User) - end - end - - describe "action_unlock" do - before(:each) do - @provider.stub(:load_current_resource) - # @node = Chef::Node.new - # @new_resource = double("Chef::Resource::User", - # :null_object => true - # ) - # @current_resource = double("Chef::Resource::User", - # :null_object => true - # ) - # @provider = Chef::Provider::User.new(@node, @new_resource) - # @provider.current_resource = @current_resource - # @provider.user_exists = true - # @provider.stub(:check_lock).and_return(true) - # @provider.stub(:unlock_user).and_return(true) - end - - it "should unlock the user if it exists and is locked" do - @provider.stub(:check_lock).and_return(true) - @provider.should_receive(:unlock_user).and_return(true) - @provider.action_unlock - @provider.set_updated_status - @new_resource.should be_updated - end - - it "should raise a Chef::Exceptions::User if we try and unlock a user that does not exist" do - @provider.user_exists = false - @provider.action = :unlock - lambda { @provider.run_action }.should raise_error(Chef::Exceptions::User) - end - end - - describe "convert_group_name" do - before do - @new_resource.gid('999') - @group = EtcGrnamIsh.new('wheel', '*', 999, []) - end - - it "should lookup the group name locally" do - Etc.should_receive(:getgrnam).with("999").and_return(@group) - @provider.convert_group_name.should == 999 - end - - it "should raise an error if we can't translate the group name during resource assertions" do - Etc.should_receive(:getgrnam).and_raise(ArgumentError) - @provider.define_resource_requirements - @provider.convert_group_name - lambda { @provider.process_resource_requirements }.should raise_error(Chef::Exceptions::User) - end - - it "should set the new resources gid to the integerized version if available" do - Etc.should_receive(:getgrnam).with("999").and_return(@group) - @provider.convert_group_name - @new_resource.gid.should == 999 - end - end -end diff --git a/spec/unit/provider/whyrun_safe_ruby_block_spec.rb b/spec/unit/provider/whyrun_safe_ruby_block_spec.rb deleted file mode 100644 index d5209248b3..0000000000 --- a/spec/unit/provider/whyrun_safe_ruby_block_spec.rb +++ /dev/null @@ -1,47 +0,0 @@ -# -# Author:: Phil Dibowitz (<phild@fb.com>) -# Copyright:: Copyright (c) 2013 Facebook -# 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::WhyrunSafeRubyBlock, "initialize" do - before(:each) do - $evil_global_evil_laugh = :wahwah - @node = Chef::Node.new - @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} - @provider = Chef::Provider::WhyrunSafeRubyBlock.new(@new_resource, @run_context) - end - - it "should call the block and flag the resource as updated" do - @provider.run_action(:run) - $evil_global_evil_laugh.should == :mwahahaha - @new_resource.should be_updated - end - - it "should call the block and flat the resource as updated - even in whyrun" do - Chef::Config[:why_run] = true - @provider.run_action(:run) - $evil_global_evil_laugh.should == :mwahahaha - @new_resource.should be_updated - Chef::Config[:why_run] = false - end - -end - diff --git a/spec/unit/provider_spec.rb b/spec/unit/provider_spec.rb deleted file mode 100644 index 9b89fc1888..0000000000 --- a/spec/unit/provider_spec.rb +++ /dev/null @@ -1,181 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - - -class NoWhyrunDemonstrator < Chef::Provider - attr_reader :system_state_altered - def whyrun_supported? - false - end - def load_current_resource - - end - def action_foo - @system_state_altered = true - end -end - -class ConvergeActionDemonstrator < Chef::Provider - attr_reader :system_state_altered - - def whyrun_supported? - true - end - - def load_current_resource - end - - def action_foo - converge_by("running a state changing action") do - @system_state_altered = true - end - end -end - -describe Chef::Provider do - before(:each) do - @cookbook_collection = Chef::CookbookCollection.new([]) - @node = Chef::Node.new - @node.name "latte" - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events) - @resource = Chef::Resource.new("funk", @run_context) - @resource.cookbook_name = "a_delicious_pie" - @provider = Chef::Provider.new(@resource, @run_context) - end - - it "should mixin shell_out" do - expect(@provider.respond_to?(:shell_out)).to be true - end - - it "should mixin shell_out!" do - expect(@provider.respond_to?(:shell_out!)).to be true - end - - it "should mixin shell_out_with_systems_locale" do - expect(@provider.respond_to?(:shell_out_with_systems_locale)).to be true - end - - it "should store the resource passed to new as new_resource" do - @provider.new_resource.should eql(@resource) - end - - it "should store the node passed to new as node" do - @provider.node.should eql(@node) - end - - it "should have nil for current_resource by default" do - @provider.current_resource.should eql(nil) - end - - it "should not support whyrun by default" do - @provider.send(:whyrun_supported?).should eql(false) - end - - it "should return true for action_nothing" do - @provider.action_nothing.should eql(true) - end - - 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} - @provider.send(:recipe_eval, &snitch) - temporary_collection.should be_an_instance_of(Chef::ResourceCollection) - @provider.run_context.instance_variable_get(:@resource_collection).should == "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. :/ - Chef::RunContext.stub(:new).and_raise("not supposed to happen") - snitch = Proc.new {temporary_collection = @run_context.resource_collection} - @provider.send(:recipe_eval, &snitch) - end - - context "when no converge actions are queued" do - before do - @provider.stub(:whyrun_supported?).and_return(true) - @provider.stub(:load_current_resource) - end - - it "does not mark the new resource as updated" do - @resource.should_not be_updated - @resource.should_not be_updated_by_last_action - end - end - - context "when converge actions have been added to the queue" do - describe "and provider supports whyrun mode" do - before do - @provider = ConvergeActionDemonstrator.new(@resource, @run_context) - end - - it "should tell us that it does support whyrun" do - @provider.should be_whyrun_supported - end - - it "queues up converge actions" do - @provider.action_foo - @provider.send(:converge_actions).should have(1).actions - end - - it "executes pending converge actions to converge the system" do - @provider.run_action(:foo) - @provider.instance_variable_get(:@system_state_altered).should be_true - end - - it "marks the resource as updated" do - @provider.run_action(:foo) - @resource.should be_updated - @resource.should be_updated_by_last_action - end - end - - describe "and provider does not support whyrun mode" do - before do - Chef::Config[:why_run] = true - @provider = NoWhyrunDemonstrator.new(@resource, @run_context) - end - - after do - Chef::Config[:why_run] = false - end - - it "should tell us that it doesn't support whyrun" do - @provider.should_not be_whyrun_supported - end - - it "should automatically generate a converge_by block on the provider's behalf" do - @provider.run_action(:foo) - @provider.send(:converge_actions).should have(0).actions - @provider.system_state_altered.should be_false - end - - it "should automatically execute the generated converge_by block" do - @provider.run_action(:foo) - @provider.system_state_altered.should be_false - @resource.should_not be_updated - @resource.should_not be_updated_by_last_action - end - end - end - -end diff --git a/spec/unit/pure_application_spec.rb b/spec/unit/pure_application_spec.rb deleted file mode 100644 index 5d879a7b85..0000000000 --- a/spec/unit/pure_application_spec.rb +++ /dev/null @@ -1,32 +0,0 @@ -# -# Author:: Serdar Sutay (<serdar@getchef.com>) -# Copyright:: Copyright (c) 2014 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. - -# This spec file intentionally doesn't include spec_helper.rb to -# be able to test only Chef::Application. -# Regression test for CHEF-5169 - -require 'chef/application' - -describe "Chef::Application" do - let(:app) { Chef::Application.new } - - describe "load_config_file" do - it "calls ConfigFetcher successfully without NameError" do - expect { app.load_config_file }.not_to raise_error - end - end -end diff --git a/spec/unit/recipe_spec.rb b/spec/unit/recipe_spec.rb deleted file mode 100644 index c795ba3788..0000000000 --- a/spec/unit/recipe_spec.rb +++ /dev/null @@ -1,464 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: Christopher Walters (<cw@opscode.com>) -# Author:: Tim Hinderliter (<tim@opscode.com>) -# Author:: Seth Chisamore (<schisamo@opscode.com>) -# Copyright:: Copyright (c) 2008-2011 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::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 - 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 - end - - let(:run_context) do - Chef::RunContext.new(node, cookbook_collection, events) - end - - let(:recipe) do - Chef::Recipe.new("hjk", "test", run_context) - end - - describe "method_missing" do - describe "resources" do - it "should load a two word (zen_master) resource" do - lambda do - recipe.zen_master "monkey" do - peace true - end - end.should_not raise_error - end - - it "should load a one word (cat) resource" do - lambda do - recipe.cat "loulou" do - pretty_kitty true - end - end.should_not raise_error - end - - it "should load a four word (one_two_three_four) resource" do - lambda do - recipe.one_two_three_four "numbers" do - i_can_count true - end - end.should_not raise_error - end - - it "should throw an error if you access a resource that we can't find" do - lambda { recipe.not_home("not_home_resource") }.should raise_error(NameError) - end - - it "should require a name argument" do - lambda { - recipe.cat - }.should raise_error(ArgumentError, "You must supply a name when declaring a cat resource") - end - - it "should allow regular errors (not NameErrors) to pass unchanged" do - lambda { - recipe.cat("felix") { raise ArgumentError, "You Suck" } - }.should raise_error(ArgumentError) - end - - it "should add our zen_master to the collection" do - recipe.zen_master "monkey" do - peace true - end - run_context.resource_collection.lookup("zen_master[monkey]").name.should eql("monkey") - end - - it "should add our zen masters to the collection in the order they appear" do - %w{monkey dog cat}.each do |name| - recipe.zen_master name do - peace true - end - end - - run_context.resource_collection.map{|r| r.name}.should eql(["monkey", "dog", "cat"]) - end - - it "should return the new resource after creating it" do - res = recipe.zen_master "makoto" do - peace true - end - res.resource_name.should eql(:zen_master) - res.name.should eql("makoto") - end - - describe "should locate platform mapped resources" do - - it "locate resource for particular platform" do - Object.const_set('ShaunTheSheep', Class.new(Chef::Resource){ provides :laughter, :on_platforms => ["television"] }) - node.automatic[:platform] = "television" - node.automatic[:platform_version] = "123" - res = recipe.laughter "timmy" - res.name.should eql("timmy") - res.kind_of?(ShaunTheSheep) - end - - it "locate a resource for all platforms" do - Object.const_set("YourMom", Class.new(Chef::Resource){ provides :love_and_caring }) - res = recipe.love_and_caring "mommy" - res.name.should eql("mommy") - res.kind_of?(YourMom) - end - - end - end - - describe "creating resources via build_resource" do - let(:zm_resource) do - recipe.build_resource(:zen_master, "klopp") do - something "bvb" - end - end - - it "applies attributes from the block to the resource" do - zm_resource.something.should == "bvb" - end - - it "sets contextual attributes on the resource" do - zm_resource.recipe_name.should == "test" - zm_resource.cookbook_name.should == "hjk" - zm_resource.source_line.should include(__FILE__) - end - - it "does not add the resource to the resource collection" do - zm_resource # force let binding evaluation - expect { run_context.resource_collection.resources(:zen_master => "klopp") }.to raise_error(Chef::Exceptions::ResourceNotFound) - end - - end - - describe "creating resources via declare_resource" do - let(:zm_resource) do - recipe.declare_resource(:zen_master, "klopp") do - something "bvb" - end - end - - it "applies attributes from the block to the resource" do - zm_resource.something.should == "bvb" - end - - it "sets contextual attributes on the resource" do - zm_resource.recipe_name.should == "test" - zm_resource.cookbook_name.should == "hjk" - zm_resource.source_line.should include(__FILE__) - end - - it "adds the resource to the resource collection" do - zm_resource # force let binding evaluation - run_context.resource_collection.resources(:zen_master => "klopp").should == zm_resource - end - end - - describe "creating a resource with short name" do - # zen_follower resource has this: - # provides :follower, :on_platforms => ["zen"] - before do - node.stub(:[]) do |key| - case key - when :platform - :zen - when :platform_version - "1.0.0" - else - nil - end - end - end - - let(:resource_follower) do - recipe.declare_resource(:follower, "srst") do - master "none" - end - end - - it "defines the resource using the declaration name with short name" do - resource_follower - run_context.resource_collection.lookup("follower[srst]").should_not be_nil - end - end - - describe "creating a resource with a long name" do - let(:resource_zn_follower) do - recipe.declare_resource(:zen_follower, "srst") do - master "none" - end - end - - - it "defines the resource using the declaration name with long name" do - resource_zn_follower - run_context.resource_collection.lookup("zen_follower[srst]").should_not be_nil - end - end - - describe "when attempting to create a resource of an invalid type" do - - it "gives a sane error message when using method_missing" do - lambda do - recipe.no_such_resource("foo") - end.should 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 - lambda do - recipe.instance_eval do - # Giving an argument will change this from NameError to NoMethodError - no_such_resource - end - end.should 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 - expect { recipe.build_resource(:no_such_resource, "foo") }.to raise_error(Chef::Exceptions::NoSuchResourceType) - end - - it "gives a sane error message when using declare_resource" do - expect { recipe.declare_resource(:no_such_resource, "bar") }.to raise_error(Chef::Exceptions::NoSuchResourceType) - end - - end - - describe "when creating a resource that contains an error in the attributes block" do - - it "does not obfuscate the error source" do - lambda do - recipe.zen_master("klopp") do - this_method_doesnt_exist - end - end.should raise_error(NoMethodError, "undefined method `this_method_doesnt_exist' for Chef::Resource::ZenMaster") - - end - - end - - describe "resource cloning" do - - let(:second_recipe) do - Chef::Recipe.new("second_cb", "second_recipe", run_context) - end - - let(:original_resource) do - recipe.zen_master("klopp") do - something "bvb09" - action :score - end - end - - let(:duplicated_resource) do - original_resource - second_recipe.zen_master("klopp") do - # attrs should be cloned - end - end - - it "copies attributes from the first resource" do - duplicated_resource.something.should == "bvb09" - end - - it "does not copy the action from the first resource" do - original_resource.action.should == [:score] - duplicated_resource.action.should == :nothing - end - - it "does not copy the source location of the first resource" do - # sanity check source location: - original_resource.source_line.should include(__FILE__) - duplicated_resource.source_line.should include(__FILE__) - # actual test: - original_resource.source_line.should_not == duplicated_resource.source_line - end - - it "sets the cookbook name on the cloned resource to that resource's cookbook" do - duplicated_resource.cookbook_name.should == "second_cb" - end - - it "sets the recipe name on the cloned resource to that resoure's recipe" do - duplicated_resource.recipe_name.should == "second_recipe" - end - - end - - describe "resource definitions" do - it "should execute defined resources" do - crow_define = Chef::ResourceDefinition.new - crow_define.define :crow, :peace => false, :something => true do - zen_master "lao tzu" do - peace params[:peace] - something params[:something] - end - end - run_context.definitions[:crow] = crow_define - recipe.crow "mine" do - peace true - end - run_context.resource_collection.resources(:zen_master => "lao tzu").name.should eql("lao tzu") - run_context.resource_collection.resources(:zen_master => "lao tzu").something.should eql(true) - end - - it "should set the node on defined resources" do - crow_define = Chef::ResourceDefinition.new - crow_define.define :crow, :peace => false, :something => true do - zen_master "lao tzu" do - peace params[:peace] - something params[:something] - end - end - run_context.definitions[:crow] = crow_define - node.normal[:foo] = false - recipe.crow "mine" do - something node[:foo] - end - recipe.resources(:zen_master => "lao tzu").something.should eql(false) - end - end - - end - - describe "instance_eval" do - it "should handle an instance_eval properly" do - code = <<-CODE - zen_master "gnome" do - peace = true - end - CODE - lambda { recipe.instance_eval(code) }.should_not raise_error - recipe.resources(:zen_master => "gnome").name.should eql("gnome") - end - end - - describe "from_file" do - it "should load a resource from a ruby file" do - recipe.from_file(File.join(CHEF_SPEC_DATA, "recipes", "test.rb")) - res = recipe.resources(:file => "/etc/nsswitch.conf") - res.name.should eql("/etc/nsswitch.conf") - res.action.should eql([:create]) - res.owner.should eql("root") - res.group.should eql("root") - res.mode.should eql(0644) - end - - it "should raise an exception if the file cannot be found or read" do - lambda { recipe.from_file("/tmp/monkeydiving") }.should raise_error(IOError) - end - end - - describe "include_recipe" do - it "should evaluate another recipe with include_recipe" do - node.should_receive(:loaded_recipe).with(:openldap, "gigantor") - run_context.stub(:unreachable_cookbook?).with(:openldap).and_return(false) - run_context.include_recipe "openldap::gigantor" - res = run_context.resource_collection.resources(:cat => "blanket") - res.name.should eql("blanket") - res.pretty_kitty.should eql(false) - end - - it "should load the default recipe for a cookbook if include_recipe is called without a ::" do - node.should_receive(:loaded_recipe).with(:openldap, "default") - run_context.stub(:unreachable_cookbook?).with(:openldap).and_return(false) - run_context.include_recipe "openldap" - res = run_context.resource_collection.resources(:cat => "blanket") - res.name.should eql("blanket") - res.pretty_kitty.should eql(true) - end - - it "should store that it has seen a recipe in the run_context" do - node.should_receive(:loaded_recipe).with(:openldap, "default") - run_context.stub(:unreachable_cookbook?).with(:openldap).and_return(false) - run_context.include_recipe "openldap" - run_context.loaded_recipe?("openldap").should be_true - end - - it "should not include the same recipe twice" do - node.should_receive(:loaded_recipe).with(:openldap, "default").exactly(:once) - run_context.stub(:unreachable_cookbook?).with(:openldap).and_return(false) - cookbook_collection[:openldap].should_receive(:load_recipe).with("default", run_context) - recipe.include_recipe "openldap" - cookbook_collection[:openldap].should_not_receive(:load_recipe).with("default", run_context) - recipe.include_recipe "openldap" - end - end - - describe "tags" do - it "should set tags via tag" do - recipe.tag "foo" - node[:tags].should include("foo") - end - - it "should set multiple tags via tag" do - recipe.tag "foo", "bar" - node[:tags].should include("foo") - node[:tags].should include("bar") - end - - it "should not set the same tag twice via tag" do - recipe.tag "foo" - recipe.tag "foo" - node[:tags].should eql([ "foo" ]) - end - - it "should return the current list of tags from tag with no arguments" do - recipe.tag "foo" - recipe.tag.should eql([ "foo" ]) - end - - it "should return true from tagged? if node is tagged" do - recipe.tag "foo" - recipe.tagged?("foo").should be(true) - end - - it "should return false from tagged? if node is not tagged" do - recipe.tagged?("foo").should be(false) - end - - it "should return false from tagged? if node is not tagged" do - recipe.tagged?("foo").should be(false) - end - - it "should remove a tag from the tag list via untag" do - recipe.tag "foo" - recipe.untag "foo" - node[:tags].should eql([]) - end - - it "should remove multiple tags from the tag list via untag" do - recipe.tag "foo", "bar" - recipe.untag "bar", "foo" - node[:tags].should eql([]) - end - end -end diff --git a/spec/unit/registry_helper_spec.rb b/spec/unit/registry_helper_spec.rb deleted file mode 100644 index 444a82dc7c..0000000000 --- a/spec/unit/registry_helper_spec.rb +++ /dev/null @@ -1,376 +0,0 @@ -# -# Author:: Prajakta Purohit (prajakta@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 - Chef::Win32::Registry.any_instance.stub(: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 - @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) - @registry.should_receive(:key_exists!).with(key_path).and_return(true) - @hive_mock.should_receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock) - @reg_mock.should_receive(:map) - @registry.get_values(key_path) - end - - it "throws an exception if key does not exist" do - @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) - @registry.should_receive(:key_exists!).with(key_path).and_raise(Chef::Exceptions::Win32RegKeyMissing) - lambda{@registry.get_values(key_path)}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) - end - end - - describe "set_value" do - it "does nothing if key and hive and value exist" do - @registry.should_receive(:key_exists!).with(key_path).and_return(true) - @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) - @registry.should_receive(:value_exists?).with(key_path, value1).and_return(true) - @registry.should_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 - @registry.should_receive(:key_exists!).with(key_path).and_return(true) - @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) - @registry.should_receive(:value_exists?).with(key_path, value1).and_return(true) - @registry.should_receive(:data_exists?).with(key_path, value1).and_return(false) - @hive_mock.should_receive(:open).with(key, Win32::Registry::KEY_SET_VALUE | ::Win32::Registry::KEY_QUERY_VALUE | @registry.registry_system_architecture).and_yield(@reg_mock) - @registry.should_receive(:get_type_from_name).with(:string).and_return(1) - @reg_mock.should_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 - @registry.should_receive(:key_exists!).with(key_path).and_return(true) - @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) - @registry.should_receive(:value_exists?).with(key_path, value1).and_return(false) - @hive_mock.should_receive(:open).with(key, ::Win32::Registry::KEY_SET_VALUE | ::Win32::Registry::KEY_QUERY_VALUE | @registry.registry_system_architecture).and_yield(@reg_mock) - @registry.should_receive(:get_type_from_name).with(:string).and_return(1) - @reg_mock.should_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 - @registry.should_receive(:key_exists!).with(key_path).and_raise(Chef::Exceptions::Win32RegKeyMissing) - lambda {@registry.set_value(key_path, value1)}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) - end - end - - describe "delete_value" do - it "deletes value if value exists" do - @registry.should_receive(:value_exists?).with(key_path, value1).and_return(true) - @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) - @hive_mock.should_receive(:open).with(key, ::Win32::Registry::KEY_SET_VALUE | @registry.registry_system_architecture).and_yield(@reg_mock) - @reg_mock.should_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 - @registry.should_receive(:value_exists?).with(key_path, value1).and_return(true) - @registry.should_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 - @registry.should_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 - @registry.should_receive(:keys_missing?).with(key_path).and_return(true) - @registry.should_receive(:create_missing).with(key_path) - @registry.should_receive(:key_exists?).with(key_path).and_return(false) - @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) - @hive_mock.should_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 - @registry.should_receive(:keys_missing?).with(key_path).and_return(true) - lambda{@registry.create_key(key_path, false)}.should raise_error(Chef::Exceptions::Win32RegNoRecursive) - end - - it "does nothing if the key exists" do - @registry.should_receive(:keys_missing?).with(key_path).and_return(true) - @registry.should_receive(:create_missing).with(key_path) - @registry.should_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 - @registry.should_receive(:keys_missing?).with(key_path).and_return(false) - @registry.should_receive(:key_exists?).with(key_path).and_return(false) - @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) - @hive_mock.should_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 - @registry.should_receive(:keys_missing?).with(key_path).and_return(false) - @registry.should_receive(:key_exists?).with(key_path).and_return(false) - @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) - @hive_mock.should_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 - @registry.should_receive(:key_exists?).with(key_path).and_return(true) - @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) - @registry.should_receive(:has_subkeys?).with(key_path).and_return(true) - @registry.should_receive(:get_subkeys).with(key_path).and_return([sub_key]) - @registry.should_receive(:key_exists?).with(key_path+"\\"+sub_key).and_return(true) - @registry.should_receive(:get_hive_and_key).with(key_path+"\\"+sub_key).and_return([@hive_mock, key+"\\"+sub_key]) - @registry.should_receive(:has_subkeys?).with(key_path+"\\"+sub_key).and_return(false) - @registry.should_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 - @registry.should_receive(:key_exists?).with(key_path).and_return(true) - @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) - @registry.should_receive(:has_subkeys?).with(key_path).and_return(true) - lambda{@registry.delete_key(key_path, false)}.should raise_error(Chef::Exceptions::Win32RegNoRecursive) - end - - it "deletes key if the key exists and has no subkeys" do - @registry.should_receive(:key_exists?).with(key_path).and_return(true) - @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) - @registry.should_receive(:has_subkeys?).with(key_path).and_return(false) - @registry.should_receive(:delete_key_ex) - @registry.delete_key(key_path, true) - end - end - - describe "key_exists?" do - it "returns true if key_exists" do - @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) - @hive_mock.should_receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock) - @registry.key_exists?(key_path).should == true - end - - it "returns false if key does not exist" do - @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) - @hive_mock.should_receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_raise(::Win32::Registry::Error) - @registry.key_exists?(key_path).should == false - end - end - - describe "key_exists!" do - it "throws an exception if the key_parent does not exist" do - @registry.should_receive(:key_exists?).with(key_path).and_return(false) - lambda{@registry.key_exists!(key_path)}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) - end - end - - describe "hive_exists?" do - it "returns true if the hive exists" do - @registry.should_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 - @registry.should_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 - @registry.should_receive(:key_exists!).with(key_path).and_return(true) - @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) - @hive_mock.should_receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock) - @reg_mock.should_receive(:each_key).and_yield(key) - @registry.has_subkeys?(key_path) == true - end - - it "returns false if the key does not have subkeys" do - @registry.should_receive(:key_exists!).with(key_path).and_return(true) - @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) - @hive_mock.should_receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock) - @reg_mock.should_receive(:each_key).and_return(no_args()) - @registry.has_subkeys?(key_path).should == false - end - - it "throws an exception if the key does not exist" do - @registry.should_receive(:key_exists!).with(key_path).and_raise(Chef::Exceptions::Win32RegKeyMissing) - lambda {@registry.set_value(key_path, value1)}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) - end - end - - describe "get_subkeys" do - it "returns the subkeys if they exist" do - @registry.should_receive(:key_exists!).with(key_path).and_return(true) - @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) - @hive_mock.should_receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock) - @reg_mock.should_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 - @registry.should_receive(:key_exists!).with(key_path).and_raise(Chef::Exceptions::Win32RegKeyMissing) - lambda {@registry.value_exists?(key_path, value1)}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) - end - - it "returns true if the value exists" do - @registry.should_receive(:key_exists!).with(key_path).and_return(true) - @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) - @hive_mock.should_receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock) - @reg_mock.should_receive(:any?).and_yield("one") - @registry.value_exists?(key_path, value1) == true - end - - it "returns false if the value does not exist" do - @registry.should_receive(:key_exists!).with(key_path).and_return(true) - @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) - @hive_mock.should_receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock) - @reg_mock.should_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 - @registry.should_receive(:key_exists!).with(key_path).and_raise(Chef::Exceptions::Win32RegKeyMissing) - lambda {@registry.data_exists?(key_path, value1)}.should raise_error(Chef::Exceptions::Win32RegKeyMissing) - end - - it "returns true if the data exists" do - @registry.should_receive(:key_exists!).with(key_path).and_return(true) - @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) - @registry.should_receive(:get_type_from_name).with(:string).and_return(1) - @reg_mock.should_receive(:each).with(no_args()).and_yield("one", 1, "1") - @hive_mock.should_receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock) - @registry.data_exists?(key_path, value1).should == true - end - - it "returns false if the data does not exist" do - @registry.should_receive(:key_exists!).with(key_path).and_return(true) - @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) - @hive_mock.should_receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock) - @registry.should_receive(:get_type_from_name).with(:string).and_return(1) - @reg_mock.should_receive(:each).with(no_args()).and_yield("one", 1, "2") - @registry.data_exists?(key_path, value1).should == false - end - end - - describe "value_exists!" do - it "does nothing if the value exists" do - @registry.should_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 - @registry.should_receive(:value_exists?).with(key_path, value1).and_return(false) - lambda{@registry.value_exists!(key_path, value1)}.should raise_error(Chef::Exceptions::Win32RegValueMissing) - end - end - - describe "data_exists!" do - it "does nothing if the data exists" do - @registry.should_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 - @registry.should_receive(:data_exists?).with(key_path, value1).and_return(false) - lambda{@registry.data_exists!(key_path, value1)}.should raise_error(Chef::Exceptions::Win32RegDataMissing) - end - end - - describe "type_matches?" do - it "returns true if type matches" do - @registry.should_receive(:value_exists!).with(key_path, value1).and_return(true) - @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) - @hive_mock.should_receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock) - @registry.should_receive(:get_type_from_name).with(:string).and_return(1) - @reg_mock.should_receive(:each).and_yield("one", 1) - @registry.type_matches?(key_path, value1).should == true - end - - it "returns false if type does not match" do - @registry.should_receive(:value_exists!).with(key_path, value1).and_return(true) - @registry.should_receive(:get_hive_and_key).with(key_path).and_return([@hive_mock, key]) - @hive_mock.should_receive(:open).with(key, ::Win32::Registry::KEY_READ | @registry.registry_system_architecture).and_yield(@reg_mock) - @reg_mock.should_receive(:each).and_yield("two", 2) - @registry.type_matches?(key_path, value1).should == false - end - - it "throws an exception if value does not exist" do - @registry.should_receive(:value_exists?).with(key_path, value1).and_return(false) - lambda{@registry.type_matches?(key_path, value1)}.should raise_error(Chef::Exceptions::Win32RegValueMissing) - end - end - - describe "type_matches!" do - it "does nothing if the type_matches" do - @registry.should_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 - @registry.should_receive(:type_matches?).with(key_path, value1).and_return(false) - lambda{@registry.type_matches!(key_path, value1)}.should raise_error(Chef::Exceptions::Win32RegTypesMismatch) - end - end - - describe "keys_missing?" do - it "returns true if the keys are missing" do - @registry.should_receive(:key_exists?).with(missing_key_path).and_return(false) - @registry.keys_missing?(key_path).should == true - end - - it "returns false if no keys in the path are missing" do - @registry.should_receive(:key_exists?).with(missing_key_path).and_return(true) - @registry.keys_missing?(key_path).should == false - end - end -end diff --git a/spec/unit/resource/apt_package_spec.rb b/spec/unit/resource/apt_package_spec.rb deleted file mode 100644 index 58b007c327..0000000000 --- a/spec/unit/resource/apt_package_spec.rb +++ /dev/null @@ -1,43 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef::Resource::AptPackage, "initialize" do - - before(:each) do - @resource = Chef::Resource::AptPackage.new("foo") - end - - it "should return a Chef::Resource::AptPackage" do - @resource.should be_a_kind_of(Chef::Resource::AptPackage) - end - - it "should set the resource_name to :apt_package" do - @resource.resource_name.should eql(:apt_package) - end - - it "should set the provider to Chef::Provider::Package::Apt" do - @resource.provider.should eql(Chef::Provider::Package::Apt) - end - - it "should support default_release" do - @resource.default_release("lenny-backports") - @resource.default_release.should eql("lenny-backports") - end -end diff --git a/spec/unit/resource/bash_spec.rb b/spec/unit/resource/bash_spec.rb deleted file mode 100644 index d729db6977..0000000000 --- a/spec/unit/resource/bash_spec.rb +++ /dev/null @@ -1,40 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef::Resource::Bash do - - before(:each) do - @resource = Chef::Resource::Bash.new("fakey_fakerton") - end - - it "should create a new Chef::Resource::Bash" do - @resource.should be_a_kind_of(Chef::Resource) - @resource.should be_a_kind_of(Chef::Resource::Bash) - end - - it "should have a resource name of :bash" do - @resource.resource_name.should eql(:bash) - end - - it "should have an interpreter of bash" do - @resource.interpreter.should eql("bash") - end - -end diff --git a/spec/unit/resource/batch_spec.rb b/spec/unit/resource/batch_spec.rb deleted file mode 100644 index b74c7d24a7..0000000000 --- a/spec/unit/resource/batch_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -# -# Author:: Adam Edwards (<adamed@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::Batch 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::Batch.new("batch_unit_test", run_context) - - end - - it "should create a new Chef::Resource::Batch" do - @resource.should be_a_kind_of(Chef::Resource::Batch) - end - - context "windows script" do - let(:resource_instance) { @resource } - let(:resource_instance_name ) { @resource.command } - let(:resource_name) { :batch } - let(:interpreter_file_name) { 'cmd.exe' } - - it_should_behave_like "a Windows script resource" - end - -end diff --git a/spec/unit/resource/breakpoint_spec.rb b/spec/unit/resource/breakpoint_spec.rb deleted file mode 100644 index 412211a038..0000000000 --- a/spec/unit/resource/breakpoint_spec.rb +++ /dev/null @@ -1,43 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@kallistec.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' - -describe Chef::Resource::Breakpoint do - - before do - @breakpoint = Chef::Resource::Breakpoint.new - end - - it "allows the action :break" do - @breakpoint.allowed_actions.should include(:break) - end - - it "defaults to the break action" do - @breakpoint.action.should == "break" - end - - it "names itself after the line number of the file where it's created" do - @breakpoint.name.should match(/breakpoint_spec\.rb\:[\d]{2}\:in \`new\'$/) - end - - it "uses the breakpoint provider" do - @breakpoint.provider.should == Chef::Provider::Breakpoint - end - -end diff --git a/spec/unit/resource/chef_gem_spec.rb b/spec/unit/resource/chef_gem_spec.rb deleted file mode 100644 index dda65f8741..0000000000 --- a/spec/unit/resource/chef_gem_spec.rb +++ /dev/null @@ -1,54 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: Bryan McLellan <btm@loftninjas.org> -# Copyright:: Copyright (c) 2008, 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::Resource::ChefGem, "initialize" do - - before(:each) do - @resource = Chef::Resource::ChefGem.new("foo") - end - - it "should return a Chef::Resource::ChefGem" do - @resource.should be_a_kind_of(Chef::Resource::ChefGem) - end - - it "should set the resource_name to :chef_gem" do - @resource.resource_name.should eql(:chef_gem) - end - - it "should set the provider to Chef::Provider::Package::Rubygems" do - @resource.provider.should eql(Chef::Provider::Package::Rubygems) - end -end - -describe Chef::Resource::ChefGem, "gem_binary" do - before(:each) do - expect(RbConfig::CONFIG).to receive(:[]).with('bindir').and_return("/opt/chef/embedded/bin") - @resource = Chef::Resource::ChefGem.new("foo") - end - - it "should raise an exception when gem_binary is set" do - lambda { @resource.gem_binary("/lol/cats/gem") }.should 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") - end -end diff --git a/spec/unit/resource/conditional_action_not_nothing_spec.rb b/spec/unit/resource/conditional_action_not_nothing_spec.rb deleted file mode 100644 index 49bc0ad57d..0000000000 --- a/spec/unit/resource/conditional_action_not_nothing_spec.rb +++ /dev/null @@ -1,45 +0,0 @@ -# -# Author:: Xabier de Zuazo (<xabier@onddo.com>) -# Copyright:: Copyright (c) 2013 Onddo Labs, SL. -# 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::ConditionalActionNotNothing do - - describe "after running a :nothing action" do - before do - @action = :nothing - @conditional = Chef::Resource::ConditionalActionNotNothing.new(@action) - end - - it "indicates that resource convergence should not continue" do - @conditional.continue?.should be_false - end - end - - describe "after running an action different to :nothing" do - before do - @action = :something - @conditional = Chef::Resource::ConditionalActionNotNothing.new(@action) - end - - it "indicates that resource convergence should continue" do - @conditional.continue?.should be_true - end - end - -end diff --git a/spec/unit/resource/conditional_spec.rb b/spec/unit/resource/conditional_spec.rb deleted file mode 100644 index 1fc2518013..0000000000 --- a/spec/unit/resource/conditional_spec.rb +++ /dev/null @@ -1,167 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@opscode.com>) -# Copyright:: Copyright (c) 2011 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 'ostruct' - -describe Chef::Resource::Conditional do - before do - Mixlib::ShellOut.any_instance.stub(:run_command).and_return(nil) - @status = OpenStruct.new(:success? => true) - Mixlib::ShellOut.any_instance.stub(:status).and_return(@status) - @parent_resource = Chef::Resource.new(nil, Chef::Node.new) - 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/) - end - - it "does not evaluate a guard interpreter on initialization of the conditional" do - expect_any_instance_of(Chef::Resource::Conditional).not_to receive(:configure) - expect(Chef::GuardInterpreter::DefaultGuardInterpreter).not_to receive(:new) - expect(Chef::GuardInterpreter::ResourceGuardInterpreter).not_to receive(:new) - Chef::Resource::Conditional.only_if(@parent_resource, "true") - end - - describe "configure" do - it "raises an exception when a guard_interpreter is specified and a block is given" do - @parent_resource.guard_interpreter :canadian_mounties - conditional = Chef::Resource::Conditional.send(:new, :always, @parent_resource, nil, {}) { True } - expect { conditional.configure }.to raise_error(ArgumentError, /does not support blocks/) - end - end - - describe "when created as an `only_if`" do - describe "after running a successful command" do - before do - @conditional = Chef::Resource::Conditional.only_if(@parent_resource, "true") - end - - it "indicates that resource convergence should continue" do - @conditional.continue?.should be_true - end - end - - describe "after running a negative/false command" do - before do - @status.send("success?=", false) - @conditional = Chef::Resource::Conditional.only_if(@parent_resource, "false") - end - - it "indicates that resource convergence should not continue" do - @conditional.continue?.should be_false - end - end - - describe 'after running a command which timed out' do - before do - @conditional = Chef::Resource::Conditional.only_if(@parent_resource, "false") - Chef::GuardInterpreter::DefaultGuardInterpreter.any_instance.stub(:shell_out).and_raise(Chef::Exceptions::CommandTimeout) - end - - it 'indicates that resource convergence should not continue' do - @conditional.continue?.should be_false - end - - it 'should log a warning' do - Chef::Log.should_receive(:warn).with("Command 'false' timed out") - @conditional.continue? - end - end - - describe "after running a block that returns a truthy value" do - before do - @conditional = Chef::Resource::Conditional.only_if(@parent_resource) { Object.new } - end - - it "indicates that resource convergence should continue" do - @conditional.continue?.should be_true - end - end - - describe "after running a block that returns a falsey value" do - before do - @conditional = Chef::Resource::Conditional.only_if(@parent_resource) { nil } - end - - it "indicates that resource convergence should not continue" do - @conditional.continue?.should be_false - end - end - end - - describe "when created as a `not_if`" do - describe "after running a successful/true command" do - before do - @conditional = Chef::Resource::Conditional.not_if(@parent_resource, "true") - end - - it "indicates that resource convergence should not continue" do - @conditional.continue?.should be_false - end - end - - describe "after running a failed/false command" do - before do - @status.send("success?=", false) - @conditional = Chef::Resource::Conditional.not_if(@parent_resource, "false") - end - - it "indicates that resource convergence should continue" do - @conditional.continue?.should be_true - end - end - - describe 'after running a command which timed out' do - before do - @conditional = Chef::Resource::Conditional.not_if(@parent_resource, "false") - Chef::GuardInterpreter::DefaultGuardInterpreter.any_instance.stub(:shell_out).and_raise(Chef::Exceptions::CommandTimeout) - end - - it 'indicates that resource convergence should continue' do - @conditional.continue?.should be_true - end - - it 'should log a warning' do - Chef::Log.should_receive(:warn).with("Command 'false' timed out") - @conditional.continue? - end - end - - describe "after running a block that returns a truthy value" do - before do - @conditional = Chef::Resource::Conditional.not_if(@parent_resource) { Object.new } - end - - it "indicates that resource convergence should not continue" do - @conditional.continue?.should be_false - end - end - - describe "after running a block that returns a falsey value" do - before do - @conditional = Chef::Resource::Conditional.not_if(@parent_resource) { nil } - end - - it "indicates that resource convergence should continue" do - @conditional.continue?.should be_true - end - end - end - -end diff --git a/spec/unit/resource/cookbook_file_spec.rb b/spec/unit/resource/cookbook_file_spec.rb deleted file mode 100644 index 6c55c8035a..0000000000 --- a/spec/unit/resource/cookbook_file_spec.rb +++ /dev/null @@ -1,89 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@opscode.com>) -# Author:: Tyler Cloke (<tyler@opscode.com>) -# Copyright:: Copyright (c) 2010 Opscode, Inc. -#p 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::CookbookFile do - before do - @cookbook_file = Chef::Resource::CookbookFile.new('sourcecode_tarball.tgz') - end - - it "uses the name parameter for the source parameter" do - @cookbook_file.name.should == 'sourcecode_tarball.tgz' - end - - it "has a source parameter" do - @cookbook_file.name('config_file.conf') - @cookbook_file.name.should == 'config_file.conf' - end - - it "defaults to a nil cookbook parameter (current cookbook will be used)" do - @cookbook_file.cookbook.should be_nil - end - - it "has a cookbook parameter" do - @cookbook_file.cookbook("munin") - @cookbook_file.cookbook.should == 'munin' - end - - it "sets the provider to Chef::Provider::CookbookFile" do - @cookbook_file.provider.should == Chef::Provider::CookbookFile - end - - 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 - @cookbook_file.checksum("1" * 64) - end - - - it "describes the state" do - state = @cookbook_file.state - if Chef::Platform.windows? - puts state - state[:rights].should == [{:permissions => :read, :principals => "Everyone"}] - state[:deny_rights].should == [{:permissions => :full_control, :principals => "Clumsy_Sam"}] - else - state[:group].should == "wheel" - state[:mode].should == "0664" - state[:owner].should == "root" - end - state[:checksum].should == "1" * 64 - end - - it "returns the path as its identity" do - if Chef::Platform.windows? - @cookbook_file.identity.should == "C:/temp/origin/file.txt" - else - @cookbook_file.identity.should == "/tmp/origin/file.txt" - end - end - end -end diff --git a/spec/unit/resource/cron_spec.rb b/spec/unit/resource/cron_spec.rb deleted file mode 100644 index cf821e3d32..0000000000 --- a/spec/unit/resource/cron_spec.rb +++ /dev/null @@ -1,186 +0,0 @@ -# -# Author:: Bryan McLellan (btm@loftninjas.org) -# Author:: Tyler Cloke (<tyler@opscode.com>) -# Copyright:: Copyright (c) 2009 Bryan McLellan -# 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::Cron do - - before(:each) do - @resource = Chef::Resource::Cron.new("cronify") - end - - it "should create a new Chef::Resource::Cron" do - @resource.should be_a_kind_of(Chef::Resource) - @resource.should be_a_kind_of(Chef::Resource::Cron) - end - - it "should have a name" do - @resource.name.should eql("cronify") - end - - it "should have a default action of 'create'" do - @resource.action.should eql(:create) - end - - it "should accept create or delete for action" do - lambda { @resource.action :create }.should_not raise_error - lambda { @resource.action :delete }.should_not raise_error - lambda { @resource.action :lolcat }.should raise_error(ArgumentError) - end - - it "should allow you to set a command" do - @resource.command "/bin/true" - @resource.command.should eql("/bin/true") - end - - it "should allow you to set a user" do - @resource.user "daemon" - @resource.user.should eql("daemon") - end - - it "should allow you to specify the minute" do - @resource.minute "30" - @resource.minute.should eql("30") - end - - it "should allow you to specify the hour" do - @resource.hour "6" - @resource.hour.should eql("6") - end - - it "should allow you to specify the day" do - @resource.day "10" - @resource.day.should eql("10") - end - - it "should allow you to specify the month" do - @resource.month "10" - @resource.month.should eql("10") - end - - it "should allow you to specify the weekday" do - @resource.weekday "2" - @resource.weekday.should eql("2") - end - - it "should allow you to specify the mailto variable" do - @resource.mailto "test@example.com" - @resource.mailto.should eql("test@example.com") - end - - it "should allow you to specify the path" do - @resource.path "/usr/bin:/usr/sbin" - @resource.path.should eql("/usr/bin:/usr/sbin") - end - - it "should allow you to specify the home directory" do - @resource.home "/root" - @resource.home.should eql("/root") - end - - it "should allow you to specify the shell to run the command with" do - @resource.shell "/bin/zsh" - @resource.shell.should eql("/bin/zsh") - end - - it "should allow you to specify environment variables hash" do - env = {"TEST" => "LOL"} - @resource.environment env - @resource.environment.should eql(env) - end - - it "should allow * for all time and date values" do - [ "minute", "hour", "day", "month", "weekday" ].each do |x| - @resource.send(x, "*").should eql("*") - end - end - - it "should allow ranges for all time and date values" do - [ "minute", "hour", "day", "month", "weekday" ].each do |x| - @resource.send(x, "1-2,5").should eql("1-2,5") - end - end - - it "should have a default value of * for all time and date values" do - [ "minute", "hour", "day", "month", "weekday" ].each do |x| - @resource.send(x).should eql("*") - end - end - - it "should have a default value of root for the user" do - @resource.user.should eql("root") - end - - it "should reject any minute over 59" do - lambda { @resource.minute "60" }.should raise_error(RangeError) - end - - it "should reject any hour over 23" do - lambda { @resource.hour "24" }.should raise_error(RangeError) - end - - it "should reject any day over 31" do - lambda { @resource.day "32" }.should raise_error(RangeError) - end - - it "should reject any month over 12" do - lambda { @resource.month "13" }.should raise_error(RangeError) - end - - describe "weekday" do - it "should reject any weekday over 7" do - lambda { @resource.weekday "8" }.should raise_error(RangeError) - end - it "should reject any symbols which don't represent day of week" do - lambda { @resource.weekday :foo }.should raise_error(RangeError) - end - end - - it "should convert integer schedule values to a string" do - [ "minute", "hour", "day", "month", "weekday" ].each do |x| - @resource.send(x, 5).should eql("5") - end - end - - describe "when it has a time (minute, hour, day, month, weeekend) and user" do - before do - @resource.command("tackle") - @resource.minute("1") - @resource.hour("2") - @resource.day("3") - @resource.month("4") - @resource.weekday("5") - @resource.user("root") - end - - it "describes the state" do - state = @resource.state - state[:minute].should == "1" - state[:hour].should == "2" - state[:day].should == "3" - state[:month].should == "4" - state[:weekday].should == "5" - state[:user].should == "root" - end - - it "returns the command as its identity" do - @resource.identity.should == "tackle" - end - end -end diff --git a/spec/unit/resource/csh_spec.rb b/spec/unit/resource/csh_spec.rb deleted file mode 100644 index e1534a8f5f..0000000000 --- a/spec/unit/resource/csh_spec.rb +++ /dev/null @@ -1,40 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef::Resource::Csh do - - before(:each) do - @resource = Chef::Resource::Csh.new("fakey_fakerton") - end - - it "should create a new Chef::Resource::Csh" do - @resource.should be_a_kind_of(Chef::Resource) - @resource.should be_a_kind_of(Chef::Resource::Csh) - end - - it "should have a resource name of :csh" do - @resource.resource_name.should eql(:csh) - end - - it "should have an interpreter of csh" do - @resource.interpreter.should eql("csh") - end - -end diff --git a/spec/unit/resource/deploy_revision_spec.rb b/spec/unit/resource/deploy_revision_spec.rb deleted file mode 100644 index 1f509992aa..0000000000 --- a/spec/unit/resource/deploy_revision_spec.rb +++ /dev/null @@ -1,47 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@kallistec.com>) -# Copyright:: Copyright (c) 2009 Daniel DeLeo -# 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::DeployRevision do - - it "defaults to the revision deploy provider" do - @resource = Chef::Resource::DeployRevision.new("deploy _this_!") - @resource.provider.should == Chef::Provider::Deploy::Revision - end - - it "has a name of deploy_revision" do - @resource = Chef::Resource::DeployRevision.new("deploy _this_!") - @resource.resource_name.should == :deploy_revision - end - -end - -describe Chef::Resource::DeployBranch do - - it "defaults to the revision deploy provider" do - @resource = Chef::Resource::DeployBranch.new("deploy _this_!") - @resource.provider.should == Chef::Provider::Deploy::Revision - end - - it "has a name of deploy_branch" do - @resource = Chef::Resource::DeployBranch.new("deploy _this_!") - @resource.resource_name.should == :deploy_branch - end - -end diff --git a/spec/unit/resource/deploy_spec.rb b/spec/unit/resource/deploy_spec.rb deleted file mode 100644 index 7cc25ed41c..0000000000 --- a/spec/unit/resource/deploy_spec.rb +++ /dev/null @@ -1,273 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@kallistec.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' - -describe Chef::Resource::Deploy do - - class << self - def resource_has_a_string_attribute(attr_name) - it "has a String attribute for #{attr_name.to_s}" do - @resource.send(attr_name, "this is a string") - @resource.send(attr_name).should eql("this is a string") - lambda {@resource.send(attr_name, 8675309)}.should 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 - @resource.send(attr_name).should eql(opts[:defaults_to]) - @resource.send(attr_name, !opts[:defaults_to]) - @resource.send(attr_name).should eql( !opts[:defaults_to] ) - end - end - - def resource_has_a_callback_attribute(attr_name) - it "has a Callback attribute #{attr_name}" do - callback_block = lambda { :noop } - lambda {@resource.send(attr_name, &callback_block)}.should_not raise_error - @resource.send(attr_name).should == callback_block - callback_file = "path/to/callback.rb" - lambda {@resource.send(attr_name, callback_file)}.should_not raise_error - @resource.send(attr_name).should == callback_file - lambda {@resource.send(attr_name, :this_is_fail)}.should raise_error(ArgumentError) - end - end - end - - before do - @resource = Chef::Resource::Deploy.new("/my/deploy/dir") - end - - resource_has_a_string_attribute(:repo) - resource_has_a_string_attribute(:deploy_to) - resource_has_a_string_attribute(:role) - resource_has_a_string_attribute(:restart_command) - resource_has_a_string_attribute(:migration_command) - resource_has_a_string_attribute(:user) - resource_has_a_string_attribute(:group) - resource_has_a_string_attribute(:repository_cache) - resource_has_a_string_attribute(:copy_exclude) - resource_has_a_string_attribute(:revision) - resource_has_a_string_attribute(:remote) - resource_has_a_string_attribute(:git_ssh_wrapper) - resource_has_a_string_attribute(:svn_username) - resource_has_a_string_attribute(:svn_password) - 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) - - it "uses the first argument as the deploy directory" do - @resource.deploy_to.should eql("/my/deploy/dir") - end - - # For git, any revision, branch, tag, whatever is resolved to a SHA1 ref. - # For svn, the branch is included in the repo URL. - # Therefore, revision and branch ARE NOT SEPARATE THINGS - it "aliases #revision as #branch" do - @resource.branch "stable" - @resource.revision.should eql("stable") - end - - it "takes the SCM resource to use as a constant, and defaults to git" do - @resource.scm_provider.should eql(Chef::Provider::Git) - @resource.scm_provider Chef::Provider::Subversion - @resource.scm_provider.should eql(Chef::Provider::Subversion) - end - - it "allows scm providers to be set via symbol" do - @resource.scm_provider.should == Chef::Provider::Git - @resource.scm_provider :subversion - @resource.scm_provider.should == Chef::Provider::Subversion - end - - it "allows scm providers to be set via string" do - @resource.scm_provider.should == Chef::Provider::Git - @resource.scm_provider "subversion" - @resource.scm_provider.should == Chef::Provider::Subversion - end - - it "has a boolean attribute for svn_force_export defaulting to false" do - @resource.svn_force_export.should be_false - @resource.svn_force_export true - @resource.svn_force_export.should be_true - lambda {@resource.svn_force_export(10053)}.should raise_error(ArgumentError) - end - - it "takes arbitrary environment variables in a hash" do - @resource.environment "RAILS_ENV" => "production" - @resource.environment.should == {"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" - @resource.environment.should == {"RAILS_ENV"=>"production", "RACK_ENV"=>"production","MERB_ENV"=>"production"} - end - - it "sets destination to $deploy_to/shared/$repository_cache" do - @resource.destination.should eql("/my/deploy/dir/shared/cached-copy") - end - - it "sets shared_path to $deploy_to/shared" do - @resource.shared_path.should eql("/my/deploy/dir/shared") - end - - it "sets current_path to $deploy_to/current" do - @resource.current_path.should eql("/my/deploy/dir/current") - end - - it "gets the current_path correct even if the shared_path is set (regression test)" do - @resource.shared_path - @resource.current_path.should eql("/my/deploy/dir/current") - end - - it "gives #depth as 5 if shallow clone is true, nil otherwise" do - @resource.depth.should be_nil - @resource.shallow_clone true - @resource.depth.should eql("5") - end - - it "aliases repo as repository" do - @resource.repository "git@github.com/opcode/cookbooks.git" - @resource.repo.should eql("git@github.com/opcode/cookbooks.git") - end - - it "aliases git_ssh_wrapper as ssh_wrapper" do - @resource.ssh_wrapper "git_my_repo.sh" - @resource.git_ssh_wrapper.should eql("git_my_repo.sh") - end - - it "has an Array attribute purge_before_symlink, default: log, tmp/pids, public/system" do - @resource.purge_before_symlink.should == %w{ log tmp/pids public/system } - @resource.purge_before_symlink %w{foo bar baz} - @resource.purge_before_symlink.should == %w{foo bar baz} - end - - it "has an Array attribute create_dirs_before_symlink, default: tmp, public, config" do - @resource.create_dirs_before_symlink.should == %w{tmp public config} - @resource.create_dirs_before_symlink %w{foo bar baz} - @resource.create_dirs_before_symlink.should == %w{foo bar baz} - 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"} - @resource.symlinks.should == default - @resource.symlinks "foo" => "bar/baz" - @resource.symlinks.should == {"foo" => "bar/baz"} - end - - it 'has a Hash attribute symlink_before_migrate, default "config/database.yml" => "config/database.yml"' do - @resource.symlink_before_migrate.should == {"config/database.yml" => "config/database.yml"} - @resource.symlink_before_migrate "wtf?" => "wtf is going on" - @resource.symlink_before_migrate.should == {"wtf?" => "wtf is going on"} - end - - resource_has_a_callback_attribute :before_migrate - resource_has_a_callback_attribute :before_symlink - resource_has_a_callback_attribute :before_restart - resource_has_a_callback_attribute :after_restart - - it "aliases restart_command as restart" do - @resource.restart "foobaz" - @resource.restart_command.should == "foobaz" - end - - it "takes a block for the restart parameter" do - restart_like_this = lambda {p :noop} - @resource.restart(&restart_like_this) - @resource.restart.should == restart_like_this - end - - it "defaults to using the Deploy::Timestamped provider" do - @resource.provider.should == Chef::Provider::Deploy::Timestamped - end - - it "allows providers to be set with a full class name" do - @resource.provider Chef::Provider::Deploy::Timestamped - @resource.provider.should == Chef::Provider::Deploy::Timestamped - end - - it "allows deploy providers to be set via symbol" do - @resource.provider :revision - @resource.provider.should == Chef::Provider::Deploy::Revision - end - - it "allows deploy providers to be set via string" do - @resource.provider "revision" - @resource.provider.should == Chef::Provider::Deploy::Revision - end - - it "defaults keep_releases to 5" do - @resource.keep_releases.should == 5 - end - - it "allows keep_releases to be set via integer" do - @resource.keep_releases 10 - @resource.keep_releases.should == 10 - end - - it "enforces a minimum keep_releases of 1" do - @resource.keep_releases 0 - @resource.keep_releases.should == 1 - end - - describe "when it has a timeout attribute" do - let(:ten_seconds) { 10 } - before { @resource.timeout(ten_seconds) } - it "stores this timeout" do - @resource.timeout.should == ten_seconds - end - end - - describe "when it has no timeout attribute" do - it "should have no default timeout" do - @resource.timeout.should be_nil - end - end - - describe "when it has meta application root, revision, user, group, - scm provider, repository cache, environment, simlinks and migrate" do - before do - @resource.repository("http://uri.org") - @resource.deploy_to("/") - @resource.revision("1.2.3") - @resource.user("root") - @resource.group("pokemon") - @resource.scm_provider(Chef::Provider::Git) - @resource.repository_cache("cached-copy") - @resource.environment({"SUDO" => "TRUE"}) - @resource.symlinks({"system" => "public/system"}) - @resource.migrate(false) - - end - - it "describes its state" do - state = @resource.state - state[:deploy_to].should == "/" - state[:revision].should == "1.2.3" - end - - it "returns the repository URI as its identity" do - @resource.identity.should == "http://uri.org" - end - end - -end diff --git a/spec/unit/resource/directory_spec.rb b/spec/unit/resource/directory_spec.rb deleted file mode 100644 index a42383c49e..0000000000 --- a/spec/unit/resource/directory_spec.rb +++ /dev/null @@ -1,82 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: Tyler Cloke (<tyler@opscode.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' - -describe Chef::Resource::Directory do - - before(:each) do - @resource = Chef::Resource::Directory.new("fakey_fakerton") - end - - it "should create a new Chef::Resource::Directory" do - @resource.should be_a_kind_of(Chef::Resource) - @resource.should be_a_kind_of(Chef::Resource::Directory) - end - - it "should have a name" do - @resource.name.should eql("fakey_fakerton") - end - - it "should have a default action of 'create'" do - @resource.action.should eql(:create) - end - - it "should accept create or delete for action" do - lambda { @resource.action :create }.should_not raise_error - lambda { @resource.action :delete }.should_not raise_error - lambda { @resource.action :blues }.should raise_error(ArgumentError) - end - - it "should use the object name as the path by default" do - @resource.path.should eql("fakey_fakerton") - end - - it "should accept a string as the path" do - lambda { @resource.path "/tmp" }.should_not raise_error - @resource.path.should eql("/tmp") - lambda { @resource.path Hash.new }.should raise_error(ArgumentError) - end - - it "should allow you to have specify whether the action is recursive with true/false" do - lambda { @resource.recursive true }.should_not raise_error - lambda { @resource.recursive false }.should_not raise_error - lambda { @resource.recursive "monkey" }.should raise_error(ArgumentError) - end - - describe "when it has group, mode, and owner" do - before do - @resource.path("/tmp/foo/bar/") - @resource.group("wheel") - @resource.mode("0664") - @resource.owner("root") - end - - it "describes its state" do - state = @resource.state - state[:group].should == "wheel" - state[:mode].should == "0664" - state[:owner].should == "root" - end - - it "returns the directory path as its identity" do - @resource.identity.should == "/tmp/foo/bar/" - end - end -end diff --git a/spec/unit/resource/dpkg_package_spec.rb b/spec/unit/resource/dpkg_package_spec.rb deleted file mode 100644 index 9ef498a577..0000000000 --- a/spec/unit/resource/dpkg_package_spec.rb +++ /dev/null @@ -1,38 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef::Resource::DpkgPackage, "initialize" do - - before(:each) do - @resource = Chef::Resource::DpkgPackage.new("foo") - end - - it "should return a Chef::Resource::DpkgPackage" do - @resource.should be_a_kind_of(Chef::Resource::DpkgPackage) - end - - it "should set the resource_name to :dpkg_package" do - @resource.resource_name.should eql(:dpkg_package) - end - - it "should set the provider to Chef::Provider::Package::Dpkg" do - @resource.provider.should eql(Chef::Provider::Package::Dpkg) - end -end diff --git a/spec/unit/resource/dsc_script_spec.rb b/spec/unit/resource/dsc_script_spec.rb deleted file mode 100644 index eb9d19e553..0000000000 --- a/spec/unit/resource/dsc_script_spec.rb +++ /dev/null @@ -1,98 +0,0 @@ -# -# Author:: Adam Edwards (<adamed@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' - -describe Chef::Resource::DscScript do - let(:dsc_test_resource_name) { 'DSCTest' } - - context 'when Powershell supports Dsc' do - let(:dsc_test_run_context) { - node = Chef::Node.new - 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) - } - 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' } - - it "has a default action of `:run`" do - 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) - end - - it "allows the code attribute to be set" do - dsc_test_resource.code(configuration_code) - expect(dsc_test_resource.code).to eq(configuration_code) - end - - it "allows the command attribute to be set" do - dsc_test_resource.command(configuration_path) - expect(dsc_test_resource.command).to eq(configuration_path) - end - - it "allows the configuration_name attribute to be set" do - dsc_test_resource.configuration_name(configuration_name) - expect(dsc_test_resource.configuration_name).to eq(configuration_name) - end - - it "allows the configuration_data attribute to be set" do - dsc_test_resource.configuration_data(configuration_data) - expect(dsc_test_resource.configuration_data).to eq(configuration_data) - end - - it "allows the configuration_data_script attribute to be set" do - dsc_test_resource.configuration_data_script(configuration_data_script) - expect(dsc_test_resource.configuration_data_script).to eq(configuration_data_script) - end - - it "raises an ArgumentError exception if an attempt is made to set the code attribute when the command attribute is already set" do - dsc_test_resource.command(configuration_path) - expect { dsc_test_resource.code(configuration_code) }.to raise_error(ArgumentError) - end - - it "raises an ArgumentError exception if an attempt is made to set the command attribute when the code attribute is already set" do - dsc_test_resource.code(configuration_code) - expect { dsc_test_resource.command(configuration_path) }.to raise_error(ArgumentError) - end - - it "raises an ArgumentError exception if an attempt is made to set the configuration_name attribute when the code attribute is already set" do - dsc_test_resource.code(configuration_code) - expect { dsc_test_resource.configuration_name(configuration_name) }.to raise_error(ArgumentError) - end - - it "raises an ArgumentError exception if an attempt is made to set the configuration_data attribute when the configuration_data_script attribute is already set" do - dsc_test_resource.configuration_data_script(configuration_data_script) - expect { dsc_test_resource.configuration_data(configuration_data) }.to raise_error(ArgumentError) - end - - it "raises an ArgumentError exception if an attempt is made to set the configuration_data_script attribute when the configuration_data attribute is already set" do - dsc_test_resource.configuration_data(configuration_data) - expect { dsc_test_resource.configuration_data_script(configuration_data_script) }.to raise_error(ArgumentError) - end - end -end diff --git a/spec/unit/resource/easy_install_package_spec.rb b/spec/unit/resource/easy_install_package_spec.rb deleted file mode 100644 index 9682c8177b..0000000000 --- a/spec/unit/resource/easy_install_package_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -# -# Author:: Joe Williams (<joe@joetify.com>) -# Copyright:: Copyright (c) 2009 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 'spec_helper' - -describe Chef::Resource::EasyInstallPackage, "initialize" do - - before(:each) do - @resource = Chef::Resource::EasyInstallPackage.new("foo") - end - - it "should create a new Chef::Resource::EasyInstallPackage" do - @resource.should be_a_kind_of(Chef::Resource) - @resource.should be_a_kind_of(Chef::Resource::EasyInstallPackage) - end - - it "should return a Chef::Resource::EasyInstallPackage" do - @resource.should be_a_kind_of(Chef::Resource::EasyInstallPackage) - end - - it "should set the resource_name to :easy_install_package" do - @resource.resource_name.should eql(:easy_install_package) - end - - it "should set the provider to Chef::Provider::Package::EasyInstall" do - @resource.provider.should eql(Chef::Provider::Package::EasyInstall) - end - - it "should allow you to set the easy_install_binary attribute" do - @resource.easy_install_binary "/opt/local/bin/easy_install" - @resource.easy_install_binary.should eql("/opt/local/bin/easy_install") - end -end diff --git a/spec/unit/resource/env_spec.rb b/spec/unit/resource/env_spec.rb deleted file mode 100644 index a1f599400b..0000000000 --- a/spec/unit/resource/env_spec.rb +++ /dev/null @@ -1,85 +0,0 @@ -# -# Author:: Doug MacEachern (<dougm@vmware.com>) -# Author:: Tyler Cloke (<tyler@opscode.com>) -# Copyright:: Copyright (c) 2010 VMware, 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::Env do - - before(:each) do - @resource = Chef::Resource::Env.new("FOO") - end - - it "should create a new Chef::Resource::Env" do - @resource.should be_a_kind_of(Chef::Resource) - @resource.should be_a_kind_of(Chef::Resource::Env) - end - - it "should have a name" do - @resource.name.should eql("FOO") - end - - it "should have a default action of 'create'" do - @resource.action.should 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 - if bad_value - lambda { @resource.action action }.should raise_error(ArgumentError) - else - lambda { @resource.action action }.should_not raise_error - end - end - end - - it "should use the object name as the key_name by default" do - @resource.key_name.should eql("FOO") - end - - it "should accept a string as the env value via 'value'" do - lambda { @resource.value "bar" }.should_not raise_error - end - - it "should not accept a Hash for the env value via 'to'" do - lambda { @resource.value Hash.new }.should raise_error(ArgumentError) - end - - it "should allow you to set an env value via 'to'" do - @resource.value "bar" - @resource.value.should eql("bar") - end - - describe "when it has key name and value" do - before do - @resource.key_name("charmander") - @resource.value("level7") - @resource.delim("hi") - end - - it "describes its state" do - state = @resource.state - state[:value].should == "level7" - end - - it "returns the key name as its identity" do - @resource.identity.should == "charmander" - end - end - -end diff --git a/spec/unit/resource/erl_call_spec.rb b/spec/unit/resource/erl_call_spec.rb deleted file mode 100644 index 3efbdca9a0..0000000000 --- a/spec/unit/resource/erl_call_spec.rb +++ /dev/null @@ -1,81 +0,0 @@ -# -# Author:: Joe Williams (<joe@joetify.com>) -# Author:: Tyler Cloke (<tyler@opscode.com>) -# Copyright:: Copyright (c) 2009 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 'spec_helper' - -describe Chef::Resource::ErlCall do - - before(:each) do - @resource = Chef::Resource::ErlCall.new("fakey_fakerton") - end - - it "should create a new Chef::Resource::ErlCall" do - @resource.should be_a_kind_of(Chef::Resource) - @resource.should be_a_kind_of(Chef::Resource::ErlCall) - end - - it "should have a resource name of :erl_call" do - @resource.resource_name.should eql(:erl_call) - end - - it "should have a default action of run" do - @resource.action.should eql("run") - end - - it "should accept run as an action" do - lambda { @resource.action :run }.should_not raise_error - end - - it "should allow you to set the code attribute" do - @resource.code "q()." - @resource.code.should eql("q().") - end - - it "should allow you to set the cookie attribute" do - @resource.cookie "nomnomnom" - @resource.cookie.should eql("nomnomnom") - end - - it "should allow you to set the distributed attribute" do - @resource.distributed true - @resource.distributed.should eql(true) - end - - it "should allow you to set the name_type attribute" do - @resource.name_type "sname" - @resource.name_type.should eql("sname") - end - - it "should allow you to set the node_name attribute" do - @resource.node_name "chef@erlang" - @resource.node_name.should eql("chef@erlang") - end - - describe "when it has cookie and node_name" do - before do - @resource.code("erl-call:function()") - @resource.cookie("cookie") - @resource.node_name("raster") - end - - it "returns the code as its identity" do - @resource.identity.should == "erl-call:function()" - end - end -end diff --git a/spec/unit/resource/execute_spec.rb b/spec/unit/resource/execute_spec.rb deleted file mode 100644 index 8c8dcfb6ca..0000000000 --- a/spec/unit/resource/execute_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: Tyler Cloke (<tyler@opscode.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' - -describe Chef::Resource::Execute do - let(:resource_instance_name) { "some command" } - let(:execute_resource) { Chef::Resource::Execute.new(resource_instance_name) } - it_behaves_like "an execute resource" -end diff --git a/spec/unit/resource/file_spec.rb b/spec/unit/resource/file_spec.rb deleted file mode 100644 index 9c6365f6d3..0000000000 --- a/spec/unit/resource/file_spec.rb +++ /dev/null @@ -1,116 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef::Resource::File do - - before(:each) do - @resource = Chef::Resource::File.new("fakey_fakerton") - end - - it "should have a name" do - @resource.name.should eql("fakey_fakerton") - end - - it "should have a default action of 'create'" do - @resource.action.should eql("create") - end - - it "should have a default content of nil" do - @resource.content.should be_nil - end - - it "should be set to back up 5 files by default" do - @resource.backup.should eql(5) - end - - it "should only accept strings for content" do - lambda { @resource.content 5 }.should raise_error(ArgumentError) - lambda { @resource.content :foo }.should raise_error(ArgumentError) - lambda { @resource.content "hello" => "there" }.should raise_error(ArgumentError) - lambda { @resource.content "hi" }.should_not raise_error - end - - it "should only accept false or a number for backup" do - lambda { @resource.backup true }.should raise_error(ArgumentError) - lambda { @resource.backup false }.should_not raise_error - lambda { @resource.backup 10 }.should_not raise_error - lambda { @resource.backup "blues" }.should raise_error(ArgumentError) - end - - it "should accept a sha256 for checksum" do - lambda { @resource.checksum "0fd012fdc96e96f8f7cf2046522a54aed0ce470224513e45da6bc1a17a4924aa" }.should_not raise_error - lambda { @resource.checksum "monkey!" }.should raise_error(ArgumentError) - end - - it "should accept create, delete or touch for action" do - lambda { @resource.action :create }.should_not raise_error - lambda { @resource.action :delete }.should_not raise_error - lambda { @resource.action :touch }.should_not raise_error - lambda { @resource.action :blues }.should raise_error(ArgumentError) - end - - it "should use the object name as the path by default" do - @resource.path.should eql("fakey_fakerton") - end - - it "should accept a string as the path" do - lambda { @resource.path "/tmp" }.should_not raise_error - @resource.path.should eql("/tmp") - lambda { @resource.path Hash.new }.should raise_error(ArgumentError) - end - - describe "when it has a path, owner, group, mode, and checksum" do - before do - @resource.path("/tmp/foo.txt") - @resource.owner("root") - @resource.group("wheel") - @resource.mode("0644") - @resource.checksum("1" * 64) - end - - context "on unix", :unix_only do - it "describes its state" do - state = @resource.state - state[:owner].should == "root" - state[:group].should == "wheel" - state[:mode].should == "0644" - state[:checksum].should == "1" * 64 - end - end - - it "returns the file path as its identity" do - @resource.identity.should == "/tmp/foo.txt" - end - - end - - describe "when access controls are set on windows", :windows_only => true do - before do - @resource.rights :read, "Everyone" - @resource.rights :full_control, "DOMAIN\User" - end - it "describes its state including windows ACL attributes" do - state = @resource.state - state[:rights].should == [ {:permissions => :read, :principals => "Everyone"}, - {:permissions => :full_control, :principals => "DOMAIN\User"} ] - end - end - -end diff --git a/spec/unit/resource/freebsd_package_spec.rb b/spec/unit/resource/freebsd_package_spec.rb deleted file mode 100644 index ae12abac6e..0000000000 --- a/spec/unit/resource/freebsd_package_spec.rb +++ /dev/null @@ -1,91 +0,0 @@ -# -# Authors:: AJ Christensen (<aj@opscode.com>) -# Richard Manyanza (<liseki@nyikacraftsmen.com>) -# Copyright:: Copyright (c) 2008 Opscode, Inc. -# Copyright:: Copyright (c) 2014 Richard Manyanza. -# 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 'ostruct' - -describe Chef::Resource::FreebsdPackage do - before(:each) do - @node = Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - @resource = Chef::Resource::FreebsdPackage.new("foo", @run_context) - end - - - describe "Initialization" do - it "should return a Chef::Resource::FreebsdPackage" do - @resource.should be_a_kind_of(Chef::Resource::FreebsdPackage) - end - - it "should set the resource_name to :freebsd_package" do - @resource.resource_name.should eql(:freebsd_package) - end - - it "should not set the provider" do - @resource.provider.should be_nil - 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.after_created - @resource.provider.should == Chef::Provider::Package::Freebsd::Port - end - end - - describe "if __Freebsd_version is greater than or equal to 1000017" do - it "should be Freebsd::Pkgng" do - [1000017, 1000018, 1000500, 1001001, 1100000].each do |__freebsd_version| - @node.normal[:os_version] = __freebsd_version - @resource.after_created - @resource.provider.should == Chef::Provider::Package::Freebsd::Pkgng - end - end - end - - describe "if pkgng enabled" do - it "should be Freebsd::Pkgng" do - pkg_enabled = OpenStruct.new(:stdout => "yes\n") - @resource.stub(:shell_out!).with("make -V WITH_PKGNG", :env => nil).and_return(pkg_enabled) - @resource.after_created - @resource.provider.should == Chef::Provider::Package::Freebsd::Pkgng - end - end - - describe "if __Freebsd_version is less than 1000017 and pkgng not enabled" do - it "should be Freebsd::Pkg" do - pkg_enabled = OpenStruct.new(:stdout => "\n") - @resource.stub(:shell_out!).with("make -V WITH_PKGNG", :env => nil).and_return(pkg_enabled) - - [1000016, 1000000, 901503, 902506, 802511].each do |__freebsd_version| - @node[:os_version] == __freebsd_version - @node.normal[:os_version] = __freebsd_version - @resource.after_created - @resource.provider.should == Chef::Provider::Package::Freebsd::Pkg - end - end - end - end -end - diff --git a/spec/unit/resource/gem_package_spec.rb b/spec/unit/resource/gem_package_spec.rb deleted file mode 100644 index 98703455de..0000000000 --- a/spec/unit/resource/gem_package_spec.rb +++ /dev/null @@ -1,49 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef::Resource::GemPackage, "initialize" do - - before(:each) do - @resource = Chef::Resource::GemPackage.new("foo") - end - - it "should return a Chef::Resource::GemPackage" do - @resource.should be_a_kind_of(Chef::Resource::GemPackage) - end - - it "should set the resource_name to :gem_package" do - @resource.resource_name.should eql(:gem_package) - end - - it "should set the provider to Chef::Provider::Package::Rubygems" do - @resource.provider.should eql(Chef::Provider::Package::Rubygems) - end -end - -describe Chef::Resource::GemPackage, "gem_binary" do - before(:each) do - @resource = Chef::Resource::GemPackage.new("foo") - end - - it "should set the gem_binary variable to whatever is passed in" do - @resource.gem_binary("/opt/local/bin/gem") - @resource.gem_binary.should eql("/opt/local/bin/gem") - end -end diff --git a/spec/unit/resource/git_spec.rb b/spec/unit/resource/git_spec.rb deleted file mode 100644 index 95a30c28a4..0000000000 --- a/spec/unit/resource/git_spec.rb +++ /dev/null @@ -1,46 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@kallistec.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' - -describe Chef::Resource::Git do - - before(:each) do - @git = Chef::Resource::Git.new("my awesome webapp") - end - - it "is a kind of Scm Resource" do - @git.should be_a_kind_of(Chef::Resource::Scm) - @git.should be_an_instance_of(Chef::Resource::Git) - end - - it "uses the git provider" do - @git.provider.should eql(Chef::Provider::Git) - end - - it "uses aliases revision as branch" do - @git.branch "HEAD" - @git.revision.should eql("HEAD") - end - - it "aliases revision as reference" do - @git.reference "v1.0 tag" - @git.revision.should eql("v1.0 tag") - end - -end diff --git a/spec/unit/resource/group_spec.rb b/spec/unit/resource/group_spec.rb deleted file mode 100644 index 0c3cf4f67f..0000000000 --- a/spec/unit/resource/group_spec.rb +++ /dev/null @@ -1,157 +0,0 @@ -# -# Author:: AJ Christensen (<aj@opscode.com>) -# Author:: Tyler Cloke (<tyler@opscode.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' - -describe Chef::Resource::Group, "initialize" do - before(:each) do - @resource = Chef::Resource::Group.new("admin") - end - - it "should create a new Chef::Resource::Group" do - @resource.should be_a_kind_of(Chef::Resource) - @resource.should be_a_kind_of(Chef::Resource::Group) - end - - it "should set the resource_name to :group" do - @resource.resource_name.should eql(:group) - end - - it "should set the group_name equal to the argument to initialize" do - @resource.group_name.should eql("admin") - end - - it "should default gid to nil" do - @resource.gid.should eql(nil) - end - - it "should default members to an empty array" do - @resource.members.should eql([]) - end - - it "should alias users to members, also an empty array" do - @resource.users.should eql([]) - end - - it "should set action to :create" do - @resource.action.should eql(:create) - end - - %w{create remove modify manage}.each do |action| - it "should allow action #{action}" do - @resource.allowed_actions.detect { |a| a == action.to_sym }.should eql(action.to_sym) - end - end - - it "should accept domain groups (@ or \ separator) on non-windows" do - lambda { @resource.group_name "domain\@group" }.should_not raise_error - @resource.group_name.should == "domain\@group" - lambda { @resource.group_name "domain\\group" }.should_not raise_error - @resource.group_name.should == "domain\\group" - lambda { @resource.group_name "domain\\group^name" }.should_not raise_error - @resource.group_name.should == "domain\\group^name" - end -end - -describe Chef::Resource::Group, "group_name" do - before(:each) do - @resource = Chef::Resource::Group.new("admin") - end - - it "should allow a string" do - @resource.group_name "pirates" - @resource.group_name.should eql("pirates") - end - - it "should not allow a hash" do - lambda { @resource.send(:group_name, { :aj => "is freakin awesome" }) }.should raise_error(ArgumentError) - end -end - -describe Chef::Resource::Group, "gid" do - before(:each) do - @resource = Chef::Resource::Group.new("admin") - end - - it "should allow an integer" do - @resource.gid 100 - @resource.gid.should eql(100) - end - - it "should not allow a hash" do - lambda { @resource.send(:gid, { :aj => "is freakin awesome" }) }.should raise_error(ArgumentError) - end -end - -describe Chef::Resource::Group, "members" do - before(:each) do - @resource = Chef::Resource::Group.new("admin") - end - - [ :users, :members].each do |method| - it "(#{method}) should allow and convert a string" do - @resource.send(method, "aj") - @resource.send(method).should eql(["aj"]) - end - - it "(#{method}) should allow an array" do - @resource.send(method, [ "aj", "adam" ]) - @resource.send(method).should eql( ["aj", "adam"] ) - end - - it "(#{method}) should not allow a hash" do - lambda { @resource.send(method, { :aj => "is freakin awesome" }) }.should raise_error(ArgumentError) - end - end -end - -describe Chef::Resource::Group, "append" do - before(:each) do - @resource = Chef::Resource::Group.new("admin") - end - - it "should default to false" do - @resource.append.should eql(false) - end - - it "should allow a boolean" do - @resource.append true - @resource.append.should eql(true) - end - - it "should not allow a hash" do - lambda { @resource.send(:gid, { :aj => "is freakin awesome" }) }.should raise_error(ArgumentError) - end - - describe "when it has members" do - before do - @resource.group_name("pokemon") - @resource.members(["blastoise", "pikachu"]) - end - - it "describes its state" do - state = @resource.state - state[:members].should eql(["blastoise", "pikachu"]) - end - - it "returns the group name as its identity" do - @resource.identity.should == "pokemon" - end - end -end diff --git a/spec/unit/resource/homebrew_package_spec.rb b/spec/unit/resource/homebrew_package_spec.rb deleted file mode 100644 index bb657607b7..0000000000 --- a/spec/unit/resource/homebrew_package_spec.rb +++ /dev/null @@ -1,57 +0,0 @@ -# -# Author:: Joshua Timberman (<joshua@getchef.com>) -# Copyright (c) 2014, Chef Software, Inc. <legal@getchef.com> -# -# 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::HomebrewPackage, 'initialize' do - - let(:resource) { Chef::Resource::HomebrewPackage.new('emacs') } - - it 'returns a Chef::Resource::HomebrewPackage' do - expect(resource).to be_a_kind_of(Chef::Resource::HomebrewPackage) - end - - it 'sets the resource_name to :homebrew_package' do - expect(resource.resource_name).to eql(:homebrew_package) - end - - it 'sets the provider to Chef::Provider::Package::Homebrew' do - expect(resource.provider).to eql(Chef::Provider::Package::Homebrew) - end - - it 'sets the homebrew_user to nil' do - expect(resource.homebrew_user).to eql(nil) - end - - 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 'as an integer' do - let(:user) { 1001 } - include_examples 'home_brew user set and returned' - end - end - -end diff --git a/spec/unit/resource/http_request_spec.rb b/spec/unit/resource/http_request_spec.rb deleted file mode 100644 index b636ca9994..0000000000 --- a/spec/unit/resource/http_request_spec.rb +++ /dev/null @@ -1,59 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: Tyler Cloke (<tyler@opscode.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' - -describe Chef::Resource::HttpRequest do - - before(:each) do - @resource = Chef::Resource::HttpRequest.new("fakey_fakerton") - end - - it "should create a new Chef::Resource::HttpRequest" do - @resource.should be_a_kind_of(Chef::Resource) - @resource.should be_a_kind_of(Chef::Resource::HttpRequest) - end - - it "should set url to a string" do - @resource.url "http://slashdot.org" - @resource.url.should eql("http://slashdot.org") - end - - it "should set the message to the name by default" do - @resource.message.should eql("fakey_fakerton") - end - - it "should set message to a string" do - @resource.message "monkeybars" - @resource.message.should eql("monkeybars") - end - - describe "when it has a message and headers" do - before do - @resource.url("http://www.trololol.net") - @resource.message("Get sum post brah.") - @resource.headers({"head" => "tail"}) - end - - it "returns the url as its identity" do - @resource.identity.should == "http://www.trololol.net" - end - end - -end diff --git a/spec/unit/resource/ifconfig_spec.rb b/spec/unit/resource/ifconfig_spec.rb deleted file mode 100644 index 10a4d09982..0000000000 --- a/spec/unit/resource/ifconfig_spec.rb +++ /dev/null @@ -1,105 +0,0 @@ -# -# Author:: Tyler Cloke (<tyler@opscode.com>) -# Copyright:: Copyright (c) 2009 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 'spec_helper' - -describe Chef::Resource::Ifconfig do - - before(:each) do - @node = Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - @resource = Chef::Resource::Ifconfig.new("fakey_fakerton", @run_context) - end - - describe "when it has target, hardware address, inet address, and a mask" do - before do - @resource.device("charmander") - @resource.target("team_rocket") - @resource.hwaddr("11.2223.223") - @resource.inet_addr("434.2343.23") - @resource.mask("255.255.545") - end - - it "describes its state" do - state = @resource.state - state[:inet_addr].should == "434.2343.23" - state[:mask].should == "255.255.545" - end - - it "returns the device as its identity" do - @resource.identity.should == "charmander" - end - end - - shared_examples "being a platform using the default ifconfig provider" do |platform, version| - before do - @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 - @resource.provider_for_action(:add).should be_a_kind_of(Chef::Provider::Ifconfig) - @resource.provider_for_action(:add).should_not be_a_kind_of(Chef::Provider::Ifconfig::Debian) - @resource.provider_for_action(:add).should_not be_a_kind_of(Chef::Provider::Ifconfig::Redhat) - end - end - - shared_examples "being a platform based on RedHat" do |platform, version| - before do - @node.automatic_attrs[:platform] = platform - @node.automatic_attrs[:platform_version] = version - end - - it "should use an Provider::Ifconfig::Redhat as a provider for #{platform} #{version}" do - @resource.provider_for_action(:add).should be_a_kind_of(Chef::Provider::Ifconfig::Redhat) - end - end - - shared_examples "being a platform based on a recent Debian" do |platform, version| - before do - @node.automatic_attrs[:platform] = platform - @node.automatic_attrs[:platform_version] = version - end - - it "should use an Ifconfig::Debian as a provider for #{platform} #{version}" do - @resource.provider_for_action(:add).should be_a_kind_of(Chef::Provider::Ifconfig::Debian) - end - end - - describe "when it is a RedHat platform" do - it_should_behave_like "being a platform based on RedHat", "redhat", "4.0" - 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" - end - - describe "when it is a new Debian platform" do - it_should_behave_like "being a platform based on a recent Debian", "debian", "7.0" - 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" - end - - describe "when it is a new Ubuntu platform" do - it_should_behave_like "being a platform based on a recent Debian", "ubuntu", "11.10" - end - -end diff --git a/spec/unit/resource/ips_package_spec.rb b/spec/unit/resource/ips_package_spec.rb deleted file mode 100644 index 61661922fa..0000000000 --- a/spec/unit/resource/ips_package_spec.rb +++ /dev/null @@ -1,43 +0,0 @@ -# -# Author:: Bryan McLellan <btm@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::Resource::IpsPackage, "initialize" do - - before(:each) do - @resource = Chef::Resource::IpsPackage.new("crypto/gnupg") - end - - it "should return a Chef::Resource::IpsPackage" do - @resource.should be_a_kind_of(Chef::Resource::IpsPackage) - end - - it "should set the resource_name to :ips_package" do - @resource.resource_name.should eql(:ips_package) - end - - it "should set the provider to Chef::Provider::Package::Ips" do - @resource.provider.should eql(Chef::Provider::Package::Ips) - end - - it "should support accept_license" do - @resource.accept_license(true) - @resource.accept_license.should eql(true) - end -end diff --git a/spec/unit/resource/link_spec.rb b/spec/unit/resource/link_spec.rb deleted file mode 100644 index 221617f9b3..0000000000 --- a/spec/unit/resource/link_spec.rb +++ /dev/null @@ -1,119 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: Tyler Cloke (<tyler@opscode.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' - -describe Chef::Resource::Link do - - before(:each) do - Chef::Resource::Link.any_instance.should_receive(:verify_links_supported!).and_return(true) - @resource = Chef::Resource::Link.new("fakey_fakerton") - end - - it "should create a new Chef::Resource::Link" do - @resource.should be_a_kind_of(Chef::Resource) - @resource.should be_a_kind_of(Chef::Resource::Link) - end - - it "should have a name" do - @resource.name.should eql("fakey_fakerton") - end - - it "should have a default action of 'create'" do - @resource.action.should eql(:create) - end - - { :create => false, :delete => false, :blues => true }.each do |action,bad_value| - it "should #{bad_value ? 'not' : ''} accept #{action.to_s}" do - if bad_value - lambda { @resource.action action }.should raise_error(ArgumentError) - else - lambda { @resource.action action }.should_not raise_error - end - end - end - - it "should use the object name as the target_file by default" do - @resource.target_file.should eql("fakey_fakerton") - end - - it "should accept a string as the link source via 'to'" do - lambda { @resource.to "/tmp" }.should_not raise_error - end - - it "should not accept a Hash for the link source via 'to'" do - lambda { @resource.to Hash.new }.should raise_error(ArgumentError) - end - - it "should allow you to set a link source via 'to'" do - @resource.to "/tmp/foo" - @resource.to.should eql("/tmp/foo") - end - - it "should allow you to specify the link type" do - @resource.link_type "symbolic" - @resource.link_type.should eql(:symbolic) - end - - it "should default to a symbolic link" do - @resource.link_type.should eql(:symbolic) - end - - it "should accept a hard link_type" do - @resource.link_type :hard - @resource.link_type.should eql(:hard) - end - - it "should reject any other link_type but :hard and :symbolic" do - lambda { @resource.link_type "x-men" }.should raise_error(ArgumentError) - end - - it "should accept a group name or id for group" do - lambda { @resource.group "root" }.should_not raise_error - lambda { @resource.group 123 }.should_not raise_error - lambda { @resource.group "root:goo" }.should raise_error(ArgumentError) - end - - it "should accept a user name or id for owner" do - lambda { @resource.owner "root" }.should_not raise_error - lambda { @resource.owner 123 }.should_not raise_error - lambda { @resource.owner "root:goo" }.should raise_error(ArgumentError) - end - - describe "when it has to, link_type, owner, and group" do - before do - @resource.target_file("/var/target.tar") - @resource.to("/to/dir/file.tar") - @resource.link_type(:symbolic) - @resource.owner("root") - @resource.group("0664") - end - - it "describes its state" do - state = @resource.state - state[:to].should == "/to/dir/file.tar" - state[:owner].should == "root" - state[:group].should == "0664" - end - - it "returns the target file as its identity" do - @resource.identity.should == "/var/target.tar" - end - end -end diff --git a/spec/unit/resource/log_spec.rb b/spec/unit/resource/log_spec.rb deleted file mode 100644 index c0201e57f3..0000000000 --- a/spec/unit/resource/log_spec.rb +++ /dev/null @@ -1,73 +0,0 @@ -# -# Author:: Cary Penniman (<cary@rightscale.com>) -# Author:: Tyler Cloke (<tyler@opscode.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' - -describe Chef::Resource::Log do - - before(:each) do - @log_str = "this is my string to log" - @resource = Chef::Resource::Log.new(@log_str) - end - - it "should create a new Chef::Resource::Log" do - @resource.should be_a_kind_of(Chef::Resource) - @resource.should be_a_kind_of(Chef::Resource::Log) - end - - it "supports the :write actions" do - @resource.allowed_actions.should include(:write) - end - - it "should have a name of log" do - @resource.resource_name.should == :log - end - - it "should allow you to set a log string" do - @resource.name.should == @log_str - end - - it "should set the message to the first argument to new" do - @resource.message.should == @log_str - end - - it "should accept a string for the log message" do - @resource.message "this is different" - @resource.message.should == "this is different" - end - - it "should accept a vaild level option" do - @resource.level :debug - @resource.level :info - @resource.level :warn - @resource.level :error - @resource.level :fatal - lambda { @resource.level :unsupported }.should raise_error(ArgumentError) - end - - describe "when the identity is defined" do - before do - @resource = Chef::Resource::Log.new("ery day I'm loggin-in") - end - - it "returns the log string as its identity" do - @resource.identity.should == "ery day I'm loggin-in" - end - end -end diff --git a/spec/unit/resource/macports_package_spec.rb b/spec/unit/resource/macports_package_spec.rb deleted file mode 100644 index 7e2e200487..0000000000 --- a/spec/unit/resource/macports_package_spec.rb +++ /dev/null @@ -1,37 +0,0 @@ -# -# Author:: David Balatero (<dbalatero@gmail.com>) -# Copyright:: Copyright (c) 2009 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::MacportsPackage, "initialize" do - before(:each) do - @resource = Chef::Resource::MacportsPackage.new("foo") - end - - it "should return a Chef::Resource::MacportsPackage" do - @resource.should be_a_kind_of(Chef::Resource::MacportsPackage) - end - - it "should set the resource_name to :macports_package" do - @resource.resource_name.should eql(:macports_package) - end - - it "should set the provider to Chef::Provider::Package::Macports" do - @resource.provider.should eql(Chef::Provider::Package::Macports) - end -end diff --git a/spec/unit/resource/mdadm_spec.rb b/spec/unit/resource/mdadm_spec.rb deleted file mode 100644 index daf10bcfea..0000000000 --- a/spec/unit/resource/mdadm_spec.rb +++ /dev/null @@ -1,102 +0,0 @@ -# -# Author:: Joe Williams (<joe@joetify.com>) -# Author:: Tyler Cloke (<tyler@opscode.com>) -# Copyright:: Copyright (c) 2009 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 'spec_helper' - -describe Chef::Resource::Mdadm do - - before(:each) do - @resource = Chef::Resource::Mdadm.new("fakey_fakerton") - end - - it "should create a new Chef::Resource::Mdadm" do - @resource.should be_a_kind_of(Chef::Resource) - @resource.should be_a_kind_of(Chef::Resource::Mdadm) - end - - it "should have a resource name of :mdadm" do - @resource.resource_name.should eql(:mdadm) - end - - it "should have a default action of create" do - @resource.action.should eql(:create) - end - - it "should accept create, assemble, stop as actions" do - lambda { @resource.action :create }.should_not raise_error - lambda { @resource.action :assemble }.should_not raise_error - lambda { @resource.action :stop }.should_not raise_error - end - - it "should allow you to set the raid_device attribute" do - @resource.raid_device "/dev/md3" - @resource.raid_device.should eql("/dev/md3") - end - - it "should allow you to set the chunk attribute" do - @resource.chunk 256 - @resource.chunk.should eql(256) - end - - it "should allow you to set the level attribute" do - @resource.level 1 - @resource.level.should eql(1) - end - - it "should allow you to set the metadata attribute" do - @resource.metadata "1.2" - @resource.metadata.should eql("1.2") - end - - it "should allow you to set the bitmap attribute" do - @resource.metadata "internal" - @resource.metadata.should eql("internal") - end - - it "should allow you to set the devices attribute" do - @resource.devices ["/dev/sda", "/dev/sdb"] - @resource.devices.should eql(["/dev/sda", "/dev/sdb"]) - end - - it "should allow you to set the exists attribute" do - @resource.exists true - @resource.exists.should eql(true) - end - - describe "when it has devices, level, and chunk" do - before do - @resource.raid_device("raider") - @resource.devices(["device1", "device2"]) - @resource.level(1) - @resource.chunk(42) - end - - it "describes its state" do - state = @resource.state - state[:devices].should eql(["device1", "device2"]) - state[:level].should == 1 - state[:chunk].should == 42 - end - - it "returns the raid device as its identity" do - @resource.identity.should == "raider" - end - end - -end diff --git a/spec/unit/resource/mount_spec.rb b/spec/unit/resource/mount_spec.rb deleted file mode 100644 index 0a154342c7..0000000000 --- a/spec/unit/resource/mount_spec.rb +++ /dev/null @@ -1,214 +0,0 @@ -# -# Author:: Joshua Timberman (<joshua@opscode.com>) -# Author:: Tyler Cloke (<tyler@opscode.com>) -# Copyright:: Copyright (c) 2009 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::Mount do - before(:each) do - @resource = Chef::Resource::Mount.new("filesystem") - end - - it "should create a new Chef::Resource::Mount" do - @resource.should be_a_kind_of(Chef::Resource) - @resource.should be_a_kind_of(Chef::Resource::Mount) - end - - it "should have a name" do - @resource.name.should eql("filesystem") - end - - it "should set mount_point to the name" do - @resource.mount_point.should eql("filesystem") - end - - it "should have a default action of mount" do - @resource.action.should eql(:mount) - end - - it "should accept mount, umount and remount as actions" do - lambda { @resource.action :mount }.should_not raise_error - lambda { @resource.action :umount }.should_not raise_error - lambda { @resource.action :remount }.should_not raise_error - lambda { @resource.action :brooklyn }.should raise_error(ArgumentError) - end - - it "should allow you to set the device attribute" do - @resource.device "/dev/sdb3" - @resource.device.should eql("/dev/sdb3") - end - - it "should set fsck_device to '-' by default" do - @resource.fsck_device.should eql('-') - end - - it "should allow you to set the fsck_device attribute" do - @resource.fsck_device "/dev/rdsk/sdb3" - @resource.fsck_device.should eql("/dev/rdsk/sdb3") - end - - it "should allow you to set the fstype attribute" do - @resource.fstype "nfs" - @resource.fstype.should eql("nfs") - end - - it "should allow you to set the dump attribute" do - @resource.dump 1 - @resource.dump.should eql(1) - end - - it "should allow you to set the pass attribute" do - @resource.pass 1 - @resource.pass.should eql(1) - end - - it "should set the options attribute to defaults" do - @resource.options.should eql(["defaults"]) - end - - it "should allow options to be sent as a string, and convert to array" do - @resource.options "rw,noexec" - @resource.options.should be_a_kind_of(Array) - end - - it "should allow options attribute as an array" do - @resource.options ["ro", "nosuid"] - @resource.options.should be_a_kind_of(Array) - end - - it "should allow options to be sent as a delayed evaluator" do - @resource.options Chef::DelayedEvaluator.new {["rw", "noexec"]} - @resource.options.should 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.should be_a_kind_of(Array) - @resource.options.should eql(["rw", "noexec"]) - end - - it "should accept true for mounted" do - @resource.mounted(true) - @resource.mounted.should eql(true) - end - - it "should accept false for mounted" do - @resource.mounted(false) - @resource.mounted.should eql(false) - end - - it "should set mounted to false by default" do - @resource.mounted.should eql(false) - end - - it "should not accept a string for mounted" do - lambda { @resource.mounted("poop") }.should raise_error(ArgumentError) - end - - it "should accept true for enabled" do - @resource.enabled(true) - @resource.enabled.should eql(true) - end - - it "should accept false for enabled" do - @resource.enabled(false) - @resource.enabled.should eql(false) - end - - it "should set enabled to false by default" do - @resource.enabled.should eql(false) - end - - it "should not accept a string for enabled" do - lambda { @resource.enabled("poop") }.should raise_error(ArgumentError) - end - - it "should default all feature support to false" do - support_hash = { :remount => false } - @resource.supports.should == support_hash - end - - it "should allow you to set feature support as an array" do - support_array = [ :remount ] - support_hash = { :remount => true } - @resource.supports(support_array) - @resource.supports.should == support_hash - end - - it "should allow you to set feature support as a hash" do - support_hash = { :remount => true } - @resource.supports(support_hash) - @resource.supports.should == support_hash - end - - it "should allow you to set username" do - @resource.username("Administrator") - @resource.username.should == "Administrator" - end - - it "should allow you to set password" do - @resource.password("Jetstream123!") - @resource.password.should == "Jetstream123!" - end - - it "should allow you to set domain" do - @resource.domain("TEST_DOMAIN") - @resource.domain.should == "TEST_DOMAIN" - end - - describe "when it has mount point, device type, and fstype" do - before do - @resource.device("charmander") - @resource.mount_point("123.456") - @resource.device_type(:device) - @resource.fstype("ranked") - end - - it "describes its state" do - state = @resource.state - state[:mount_point].should == "123.456" - state[:device_type].should eql(:device) - state[:fstype].should == "ranked" - end - - it "returns the device as its identity" do - @resource.identity.should == "charmander" - end - end - - describe "when it has username, password and domain" do - before do - @resource.mount_point("T:") - @resource.device("charmander") - @resource.username("Administrator") - @resource.password("Jetstream123!") - @resource.domain("TEST_DOMAIN") - end - - it "describes its state" do - state = @resource.state - state[:mount_point].should == "T:" - state[:username].should == "Administrator" - state[:password].should == "Jetstream123!" - state[:domain].should == "TEST_DOMAIN" - state[:device_type].should eql(:device) - state[:fstype].should == "auto" - end - - end -end diff --git a/spec/unit/resource/ohai_spec.rb b/spec/unit/resource/ohai_spec.rb deleted file mode 100644 index b8d062b4c9..0000000000 --- a/spec/unit/resource/ohai_spec.rb +++ /dev/null @@ -1,62 +0,0 @@ -# -# Author:: Michael Leinartas (<mleinartas@gmail.com>) -# Copyright:: Copyright (c) 2010 Michael Leinartas -# 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::Ohai do - - before(:each) do - @resource = Chef::Resource::Ohai.new("ohai_reload") - end - - it "should create a new Chef::Resource::Ohai" do - @resource.should be_a_kind_of(Chef::Resource) - @resource.should be_a_kind_of(Chef::Resource::Ohai) - end - - it "should have a resource name of :ohai" do - @resource.resource_name.should eql(:ohai) - end - - it "should have a default action of create" do - @resource.action.should eql(:reload) - end - - it "should allow you to set the plugin attribute" do - @resource.plugin "passwd" - @resource.plugin.should eql("passwd") - end - - describe "when it has a plugin value" do - before do - @resource.name("test") - @resource.plugin("passwd") - end - - it "describes its state" do - state = @resource.state - state[:plugin].should == "passwd" - end - - it "returns the name as its identity" do - @resource.identity.should == "test" - end - end - - -end diff --git a/spec/unit/resource/package_spec.rb b/spec/unit/resource/package_spec.rb deleted file mode 100644 index 8a1a13394e..0000000000 --- a/spec/unit/resource/package_spec.rb +++ /dev/null @@ -1,93 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: Tyler Cloke (<tyler@opscode.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' - -describe Chef::Resource::Package do - - before(:each) do - @resource = Chef::Resource::Package.new("emacs") - end - - it "should create a new Chef::Resource::Package" do - @resource.should be_a_kind_of(Chef::Resource) - @resource.should be_a_kind_of(Chef::Resource::Package) - end - - it "should set the package_name to the first argument to new" do - @resource.package_name.should eql("emacs") - end - - it "should accept a string for the package name" do - @resource.package_name "something" - @resource.package_name.should eql("something") - end - - it "should accept a string for the version" do - @resource.version "something" - @resource.version.should eql("something") - end - - it "should accept a string for the response file" do - @resource.response_file "something" - @resource.response_file.should eql("something") - end - - it "should accept a hash for response file template variables" do - @resource.response_file_variables({:variables => true}) - @resource.response_file_variables.should eql({:variables => true}) - end - - it "should accept a string for the source" do - @resource.source "something" - @resource.source.should eql("something") - end - - it "should accept a string for the options" do - @resource.options "something" - @resource.options.should eql("something") - end - - describe "when it has a package_name and version" do - before do - @resource.package_name("tomcat") - @resource.version("10.9.8") - @resource.options("-al") - end - - it "describes its state" do - state = @resource.state - state[:version].should == "10.9.8" - state[:options].should == "-al" - end - - it "returns the file path as its identity" do - @resource.identity.should == "tomcat" - end - end - - # String, Integer - [ "600", 600 ].each do |val| - it "supports setting a timeout as a #{val.class}" do - @resource.timeout(val) - expect(@resource.timeout).to eql(val) - end - end - -end diff --git a/spec/unit/resource/pacman_package_spec.rb b/spec/unit/resource/pacman_package_spec.rb deleted file mode 100644 index ec5feeb82c..0000000000 --- a/spec/unit/resource/pacman_package_spec.rb +++ /dev/null @@ -1,38 +0,0 @@ -# -# Author:: Jan Zimmek (<jan.zimmek@web.de>) -# Copyright:: Copyright (c) 2010 Jan Zimmek -# 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::PacmanPackage, "initialize" do - - before(:each) do - @resource = Chef::Resource::PacmanPackage.new("foo") - end - - it "should return a Chef::Resource::PacmanPackage" do - @resource.should be_a_kind_of(Chef::Resource::PacmanPackage) - end - - it "should set the resource_name to :pacman_package" do - @resource.resource_name.should eql(:pacman_package) - end - - it "should set the provider to Chef::Provider::Package::Pacman" do - @resource.provider.should eql(Chef::Provider::Package::Pacman) - end -end diff --git a/spec/unit/resource/perl_spec.rb b/spec/unit/resource/perl_spec.rb deleted file mode 100644 index d25dc98563..0000000000 --- a/spec/unit/resource/perl_spec.rb +++ /dev/null @@ -1,40 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef::Resource::Perl do - - before(:each) do - @resource = Chef::Resource::Perl.new("fakey_fakerton") - end - - it "should create a new Chef::Resource::Perl" do - @resource.should be_a_kind_of(Chef::Resource) - @resource.should be_a_kind_of(Chef::Resource::Perl) - end - - it "should have a resource name of :perl" do - @resource.resource_name.should eql(:perl) - end - - it "should have an interpreter of perl" do - @resource.interpreter.should eql("perl") - end - -end diff --git a/spec/unit/resource/portage_package_spec.rb b/spec/unit/resource/portage_package_spec.rb deleted file mode 100644 index 510f3b5864..0000000000 --- a/spec/unit/resource/portage_package_spec.rb +++ /dev/null @@ -1,38 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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 File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper")) - -describe Chef::Resource::PortagePackage, "initialize" do - - before(:each) do - @resource = Chef::Resource::PortagePackage.new("foo") - end - - it "should return a Chef::Resource::PortagePackage" do - @resource.should be_a_kind_of(Chef::Resource::PortagePackage) - end - - it "should set the resource_name to :portage_package" do - @resource.resource_name.should eql(:portage_package) - end - - it "should set the provider to Chef::Provider::Package::Portage" do - @resource.provider.should eql(Chef::Provider::Package::Portage) - end -end diff --git a/spec/unit/resource/powershell_spec.rb b/spec/unit/resource/powershell_spec.rb deleted file mode 100644 index da20c4f0bf..0000000000 --- a/spec/unit/resource/powershell_spec.rb +++ /dev/null @@ -1,131 +0,0 @@ -# -# Author:: Adam Edwards (<adamed@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 - @resource.should be_a_kind_of(Chef::Resource::PowershellScript) - end - - it "should set convert_boolean_return to false by default" do - @resource.convert_boolean_return.should == false - end - - it "should return the value for convert_boolean_return that was set" do - @resource.convert_boolean_return true - @resource.convert_boolean_return.should == true - @resource.convert_boolean_return false - @resource.convert_boolean_return.should == false - end - - context "when using guards" do - let(:resource) { @resource } - before(:each) do - resource.stub(:run_action) - resource.stub(: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 ] - - inherited_difference.should == [] - 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 deleted file mode 100644 index 3362b68c62..0000000000 --- a/spec/unit/resource/python_spec.rb +++ /dev/null @@ -1,40 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef::Resource::Python do - - before(:each) do - @resource = Chef::Resource::Python.new("fakey_fakerton") - end - - it "should create a new Chef::Resource::Python" do - @resource.should be_a_kind_of(Chef::Resource) - @resource.should be_a_kind_of(Chef::Resource::Python) - end - - it "should have a resource name of :python" do - @resource.resource_name.should eql(:python) - end - - it "should have an interpreter of python" do - @resource.interpreter.should eql("python") - end - -end diff --git a/spec/unit/resource/registry_key_spec.rb b/spec/unit/resource/registry_key_spec.rb deleted file mode 100644 index 00c301d61d..0000000000 --- a/spec/unit/resource/registry_key_spec.rb +++ /dev/null @@ -1,199 +0,0 @@ -# -# Author:: Lamont Granquist (<lamont@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::Resource::RegistryKey, "initialize" do - before(:each) do - @resource = Chef::Resource::RegistryKey.new('HKCU\Software\Raxicoricofallapatorius') - end - - it "should create a new Chef::Resource::RegistryKey" do - @resource.should be_a_kind_of(Chef::Resource) - @resource.should be_a_kind_of(Chef::Resource::RegistryKey) - end - - it "should set the resource_name to :registry_key" do - @resource.resource_name.should eql(:registry_key) - end - - it "should set the key equal to the argument to initialize" do - @resource.key.should eql('HKCU\Software\Raxicoricofallapatorius') - end - - it "should default recursive to false" do - @resource.recursive.should eql(false) - end - - it "should default architecture to :machine" do - @resource.architecture.should eql(:machine) - end - - it "should set action to :create" do - @resource.action.should eql(:create) - end - - %w{create create_if_missing delete delete_key}.each do |action| - it "should allow action #{action}" do - @resource.allowed_actions.detect { |a| a == action.to_sym }.should eql(action.to_sym) - end - end -end - -describe Chef::Resource::RegistryKey, "key" do - before(:each) do - @resource = Chef::Resource::RegistryKey.new('HKCU\Software\Raxicoricofallapatorius') - end - - it "should allow a string" do - @resource.key 'HKCU\Software\Poosh' - @resource.key.should eql('HKCU\Software\Poosh') - end - - it "should not allow an integer" do - lambda { @resource.send(:key, 100) }.should raise_error(ArgumentError) - end - - it "should not allow a hash" do - lambda { @resource.send(:key, { :sonic => "screwdriver" }) }.should raise_error(ArgumentError) - end -end - -describe Chef::Resource::RegistryKey, "values" do - before(:each) do - @resource = Chef::Resource::RegistryKey.new('HKCU\Software\Raxicoricofallapatorius') - end - - it "should allow a single proper hash of registry values" do - @resource.values( { :name => 'poosh', :type => :string, :data => 'carmen' } ) - @resource.values.should 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' } ] - @resource.values.should 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 }) - @resource.values.should eql([ { :name => 'poosh', :type => :binary, :data => "00594fd4f42ba43fc1ca0427a0576295" } ]) - end - - it "should throw an exception if the name field is missing" do - lambda { @resource.values [ { :type => :string, :data => 'carmen' } ] }.should raise_error(ArgumentError) - end - - it "should throw an exception if the type field is missing" do - lambda { @resource.values [ { :name => 'poosh', :data => 'carmen' } ] }.should raise_error(ArgumentError) - end - - it "should throw an exception if the data field is missing" do - lambda { @resource.values [ { :name => 'poosh', :type => :string } ] }.should raise_error(ArgumentError) - end - - it "should throw an exception if extra fields are present" do - lambda { @resource.values [ { :name => 'poosh', :type => :string, :data => 'carmen', :screwdriver => 'sonic' } ] }.should raise_error(ArgumentError) - end - - it "should not allow a string" do - lambda { @resource.send(:values, 'souffle') }.should raise_error(ArgumentError) - end - - it "should not allow an integer" do - lambda { @resource.send(:values, 100) }.should raise_error(ArgumentError) - end -end - -describe Chef::Resource::RegistryKey, "recursive" do - before(:each) do - @resource = Chef::Resource::RegistryKey.new('HKCU\Software\Raxicoricofallapatorius') - end - - it "should allow a boolean" do - @resource.recursive(true) - @resource.recursive.should eql(true) - end - - it "should not allow a hash" do - lambda { @resource.recursive({:sonic => :screwdriver}) }.should raise_error(ArgumentError) - end - - it "should not allow an array" do - lambda { @resource.recursive([:nose, :chin]) }.should raise_error(ArgumentError) - end - - it "should not allow a string" do - lambda { @resource.recursive('souffle') }.should raise_error(ArgumentError) - end - - it "should not allow an integer" do - lambda { @resource.recursive(100) }.should raise_error(ArgumentError) - end -end - -describe Chef::Resource::RegistryKey, "architecture" do - before(:each) do - @resource = Chef::Resource::RegistryKey.new('HKCU\Software\Raxicoricofallapatorius') - end - - [ :i386, :x86_64, :machine ].each do |arch| - it "should allow #{arch} as a symbol" do - @resource.architecture(arch) - @resource.architecture.should eql(arch) - end - end - - it "should not allow a hash" do - lambda { @resource.architecture({:sonic => :screwdriver}) }.should raise_error(ArgumentError) - end - - it "should not allow an array" do - lambda { @resource.architecture([:nose, :chin]) }.should raise_error(ArgumentError) - end - - it "should not allow a string" do - lambda { @resource.architecture('souffle') }.should raise_error(ArgumentError) - end - - it "should not allow an integer" do - lambda { @resource.architecture(100) }.should raise_error(ArgumentError) - end -end - -describe Chef::Resource::RegistryKey, ":unscrubbed_values" do - before(:each) do - @resource = Chef::Resource::RegistryKey.new('HKCU\Software\Raxicoricofallapatorius') - end - - it "should return unsafe data as-is" do - key_values = [ { :name => 'poosh', :type => :binary, :data => 255.chr * 1 } ] - @resource.values(key_values) - @resource.unscrubbed_values.should eql(key_values) - end -end - -describe Chef::Resource::RegistryKey, "state" do - before(:each) do - @resource = Chef::Resource::RegistryKey.new('HKCU\Software\Raxicoricofallapatorius') - end - - it "should return scrubbed values" do - @resource.values([ { :name => 'poosh', :type => :binary, :data => 255.chr * 1 } ]) - @resource.state.should eql( { :values => [{ :name => 'poosh', :type => :binary, :data => "00594fd4f42ba43fc1ca0427a0576295" }] } ) - end -end diff --git a/spec/unit/resource/remote_directory_spec.rb b/spec/unit/resource/remote_directory_spec.rb deleted file mode 100644 index d3800062ae..0000000000 --- a/spec/unit/resource/remote_directory_spec.rb +++ /dev/null @@ -1,97 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef::Resource::RemoteDirectory do - - before(:each) do - @resource = Chef::Resource::RemoteDirectory.new("/etc/dunk") - end - - it "should create a new Chef::Resource::RemoteDirectory" do - @resource.should be_a_kind_of(Chef::Resource) - @resource.should be_a_kind_of(Chef::Resource::RemoteDirectory) - end - - it "should set the path to the first argument to new" do - @resource.path.should eql("/etc/dunk") - end - - it "should accept a string for the remote directory source" do - @resource.source "foo" - @resource.source.should eql("foo") - end - - it "should have the basename of the remote directory resource as the default source" do - @resource.source.should eql("dunk") - end - - it "should accept a number for the remote files backup" do - @resource.files_backup 1 - @resource.files_backup.should eql(1) - end - - it "should accept false for the remote files backup" do - @resource.files_backup false - @resource.files_backup.should eql(false) - end - - it "should accept 3 or 4 digets for the files_mode" do - @resource.files_mode 100 - @resource.files_mode.should eql(100) - @resource.files_mode 1000 - @resource.files_mode.should eql(1000) - end - - it "should accept a string or number for the files group" do - @resource.files_group "heart" - @resource.files_group.should eql("heart") - @resource.files_group 1000 - @resource.files_group.should eql(1000) - end - - it "should accept a string or number for the files owner" do - @resource.files_owner "heart" - @resource.files_owner.should eql("heart") - @resource.files_owner 1000 - @resource.files_owner.should eql(1000) - end - - describe "when it has cookbook, files owner, files mode, and source" do - before do - @resource.path("/var/path/") - @resource.cookbook("pokemon.rb") - @resource.files_owner("root") - @resource.files_group("supergroup") - @resource.files_mode("0664") - @resource.source("/var/source/") - end - - it "describes its state" do - state = @resource.state - state[:files_owner].should == "root" - state[:files_group].should == "supergroup" - state[:files_mode].should == "0664" - end - - it "returns the path as its identity" do - @resource.identity.should == "/var/path/" - end - end -end diff --git a/spec/unit/resource/remote_file_spec.rb b/spec/unit/resource/remote_file_spec.rb deleted file mode 100644 index 8f1633119d..0000000000 --- a/spec/unit/resource/remote_file_spec.rb +++ /dev/null @@ -1,192 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: Tyler Cloke (<tyler@opscode.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' - -describe Chef::Resource::RemoteFile do - - before(:each) do - @resource = Chef::Resource::RemoteFile.new("fakey_fakerton") - end - - describe "initialize" do - it "should create a new Chef::Resource::RemoteFile" do - @resource.should be_a_kind_of(Chef::Resource) - @resource.should be_a_kind_of(Chef::Resource::File) - @resource.should be_a_kind_of(Chef::Resource::RemoteFile) - end - end - - it "says its provider is RemoteFile when the source is an absolute URI" do - @resource.source("http://www.google.com/robots.txt") - @resource.provider.should == Chef::Provider::RemoteFile - Chef::Platform.find_provider(:noplatform, 'noversion', @resource).should == Chef::Provider::RemoteFile - end - - - describe "source" do - it "does not have a default value for 'source'" do - @resource.source.should eql([]) - end - - it "should accept a URI for the remote file source" do - @resource.source "http://opscode.com/" - @resource.source.should eql([ "http://opscode.com/" ]) - end - - it "should accept a delayed evalutator (string) for the remote file source" do - @resource.source Chef::DelayedEvaluator.new {"http://opscode.com/"} - @resource.source.should eql([ "http://opscode.com/" ]) - end - - it "should accept an array of URIs for the remote file source" do - @resource.source([ "http://opscode.com/", "http://puppetlabs.com/" ]) - @resource.source.should eql([ "http://opscode.com/", "http://puppetlabs.com/" ]) - end - - it "should accept a delated evaluator (array) for the remote file source" do - @resource.source Chef::DelayedEvaluator.new { [ "http://opscode.com/", "http://puppetlabs.com/" ] } - @resource.source.should eql([ "http://opscode.com/", "http://puppetlabs.com/" ]) - end - - it "should accept an multiple URIs as arguments for the remote file source" do - @resource.source("http://opscode.com/", "http://puppetlabs.com/") - @resource.source.should eql([ "http://opscode.com/", "http://puppetlabs.com/" ]) - end - - it "should only accept a single argument if a delayed evalutor is used" do - lambda { - @resource.source("http://opscode.com/", Chef::DelayedEvaluator.new {"http://opscode.com/"}) - }.should raise_error(Chef::Exceptions::InvalidRemoteFileURI) - end - - it "should only accept a single array item if a delayed evalutor is used" do - lambda { - @resource.source(["http://opscode.com/", Chef::DelayedEvaluator.new {"http://opscode.com/"}]) - }.should raise_error(Chef::Exceptions::InvalidRemoteFileURI) - end - - it "does not accept a non-URI as the source" do - lambda { @resource.source("not-a-uri") }.should raise_error(Chef::Exceptions::InvalidRemoteFileURI) - end - - it "does not accept a non-URI as the source when read from a delayed evaluator" do - lambda { - @resource.source(Chef::DelayedEvaluator.new {"not-a-uri"}) - @resource.source - }.should raise_error(Chef::Exceptions::InvalidRemoteFileURI) - end - - it "should raise an exception when source is an empty array" do - lambda { @resource.source([]) }.should raise_error(ArgumentError) - end - - end - - describe "checksum" do - it "should accept a string for the checksum object" do - @resource.checksum "asdf" - @resource.checksum.should eql("asdf") - end - - it "should default to nil" do - @resource.checksum.should == nil - end - end - - describe "ftp_active_mode" do - it "should accept a boolean for the ftp_active_mode object" do - @resource.ftp_active_mode true - @resource.ftp_active_mode.should be_true - end - - it "should default to false" do - @resource.ftp_active_mode.should be_false - end - end - - describe "conditional get options" do - it "defaults to using etags and last modified" do - @resource.use_etags.should be_true - @resource.use_last_modified.should be_true - end - - it "enable or disables etag and last modified options as a group" do - @resource.use_conditional_get(false) - @resource.use_etags.should be_false - @resource.use_last_modified.should be_false - - @resource.use_conditional_get(true) - @resource.use_etags.should be_true - @resource.use_last_modified.should be_true - end - - it "disables etags indivdually" do - @resource.use_etags(false) - @resource.use_etags.should be_false - @resource.use_last_modified.should be_true - end - - it "disables last modified individually" do - @resource.use_last_modified(false) - @resource.use_last_modified.should be_false - @resource.use_etags.should be_true - end - - end - - describe "when it has group, mode, owner, source, and checksum" do - before do - if Chef::Platform.windows? - @resource.path("C:/temp/origin/file.txt") - @resource.rights(:read, "Everyone") - @resource.deny_rights(:full_control, "Clumsy_Sam") - else - @resource.path("/this/path/") - @resource.group("pokemon") - @resource.mode("0664") - @resource.owner("root") - end - @resource.source("https://www.google.com/images/srpr/logo3w.png") - @resource.checksum("1"*26) - end - - it "describes its state" do - state = @resource.state - if Chef::Platform.windows? - puts state - state[:rights].should == [{:permissions => :read, :principals => "Everyone"}] - state[:deny_rights].should == [{:permissions => :full_control, :principals => "Clumsy_Sam"}] - else - state[:group].should == "pokemon" - state[:mode].should == "0664" - state[:owner].should == "root" - state[:checksum].should == "1"*26 - end - end - - it "returns the path as its identity" do - if Chef::Platform.windows? - @resource.identity.should == "C:/temp/origin/file.txt" - else - @resource.identity.should == "/this/path/" - end - end - end -end diff --git a/spec/unit/resource/route_spec.rb b/spec/unit/resource/route_spec.rb deleted file mode 100644 index 4522438402..0000000000 --- a/spec/unit/resource/route_spec.rb +++ /dev/null @@ -1,107 +0,0 @@ -# -# Author:: Bryan McLellan (btm@loftninjas.org) -# Author:: Tyler Cloke (<tyler@opscode.com>) -# Copyright:: Copyright (c) 2008 Bryan McLellan -# 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::Route do - - before(:each) do - @resource = Chef::Resource::Route.new("10.0.0.10") - end - - it "should create a new Chef::Resource::Route" do - @resource.should be_a_kind_of(Chef::Resource) - @resource.should be_a_kind_of(Chef::Resource::Route) - end - - it "should have a name" do - @resource.name.should eql("10.0.0.10") - end - - it "should have a default action of 'add'" do - @resource.action.should eql([:add]) - end - - it "should accept add or delete for action" do - lambda { @resource.action :add }.should_not raise_error - lambda { @resource.action :delete }.should_not raise_error - lambda { @resource.action :lolcat }.should raise_error(ArgumentError) - end - - it "should use the object name as the target by default" do - @resource.target.should eql("10.0.0.10") - end - - it "should allow you to specify the netmask" do - @resource.netmask "255.255.255.0" - @resource.netmask.should eql("255.255.255.0") - end - - it "should allow you to specify the gateway" do - @resource.gateway "10.0.0.1" - @resource.gateway.should eql("10.0.0.1") - end - - it "should allow you to specify the metric" do - @resource.metric 10 - @resource.metric.should eql(10) - end - - it "should allow you to specify the device" do - @resource.device "eth0" - @resource.device.should eql("eth0") - end - - it "should allow you to specify the route type" do - @resource.route_type "host" - @resource.route_type.should eql(:host) - end - - it "should default to a host route type" do - @resource.route_type.should eql(:host) - end - - it "should accept a net route type" do - @resource.route_type :net - @resource.route_type.should eql(:net) - end - - it "should reject any other route_type but :host and :net" do - lambda { @resource.route_type "lolcat" }.should raise_error(ArgumentError) - end - - describe "when it has netmask, gateway, and device" do - before do - @resource.target("charmander") - @resource.netmask("lemask") - @resource.gateway("111.111.111") - @resource.device("forcefield") - end - - it "describes its state" do - state = @resource.state - state[:netmask].should == "lemask" - state[:gateway].should == "111.111.111" - end - - it "returns the target as its identity" do - @resource.identity.should == "charmander" - end - end -end diff --git a/spec/unit/resource/rpm_package_spec.rb b/spec/unit/resource/rpm_package_spec.rb deleted file mode 100644 index 25930a5484..0000000000 --- a/spec/unit/resource/rpm_package_spec.rb +++ /dev/null @@ -1,38 +0,0 @@ -# -# Author:: Thomas Bishop (<bishop.thomas@gmail.com>) -# Copyright:: Copyright (c) 2010 Thomas Bishop -# 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::RpmPackage, "initialize" do - - before(:each) do - @resource = Chef::Resource::RpmPackage.new("foo") - end - - it "should return a Chef::Resource::RpmPackage" do - @resource.should be_a_kind_of(Chef::Resource::RpmPackage) - end - - it "should set the resource_name to :rpm_package" do - @resource.resource_name.should eql(:rpm_package) - end - - it "should set the provider to Chef::Provider::Package::Rpm" do - @resource.provider.should eql(Chef::Provider::Package::Rpm) - end -end diff --git a/spec/unit/resource/ruby_block_spec.rb b/spec/unit/resource/ruby_block_spec.rb deleted file mode 100644 index 82bbd1ffc7..0000000000 --- a/spec/unit/resource/ruby_block_spec.rb +++ /dev/null @@ -1,61 +0,0 @@ -# -# Author:: AJ Christensen (<aj@opscode.com>) -# Author:: Tyler Cloke (<tyler@opscode.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' - -describe Chef::Resource::RubyBlock do - - before(:each) do - @resource = Chef::Resource::RubyBlock.new("fakey_fakerton") - end - - it "should create a new Chef::Resource::RubyBlock" do - @resource.should be_a_kind_of(Chef::Resource) - @resource.should be_a_kind_of(Chef::Resource::RubyBlock) - end - - it "should have a default action of 'create'" do - @resource.action.should eql("run") - end - - it "should have a resource name of :ruby_block" do - @resource.resource_name.should eql(:ruby_block) - end - - it "should accept a ruby block/proc/.. for the 'block' parameter" do - @resource.block do - "foo" - end.call.should eql("foo") - end - - it "allows the action to be 'create'" do - @resource.action :create - @resource.action.should == [:create] - end - - describe "when it has been initialized with block code" do - before do - @resource.block_name("puts 'harrrr'") - end - - it "returns the block as its identity" do - @resource.identity.should == "puts 'harrrr'" - end - end -end diff --git a/spec/unit/resource/ruby_spec.rb b/spec/unit/resource/ruby_spec.rb deleted file mode 100644 index 9bf7316e6d..0000000000 --- a/spec/unit/resource/ruby_spec.rb +++ /dev/null @@ -1,40 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef::Resource::Ruby do - - before(:each) do - @resource = Chef::Resource::Ruby.new("fakey_fakerton") - end - - it "should create a new Chef::Resource::Ruby" do - @resource.should be_a_kind_of(Chef::Resource) - @resource.should be_a_kind_of(Chef::Resource::Ruby) - end - - it "should have a resource name of :ruby" do - @resource.resource_name.should eql(:ruby) - end - - it "should have an interpreter of ruby" do - @resource.interpreter.should eql("ruby") - end - -end diff --git a/spec/unit/resource/scm_spec.rb b/spec/unit/resource/scm_spec.rb deleted file mode 100644 index eeb2fb1c3c..0000000000 --- a/spec/unit/resource/scm_spec.rb +++ /dev/null @@ -1,193 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@kallistec.com>) -# Author:: Tyler Cloke (<tyler@opscode.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' - -describe Chef::Resource::Scm do - - before(:each) do - @resource = Chef::Resource::Scm.new("my awesome app") - end - - it "should be a SCM resource" do - @resource.should be_a_kind_of(Chef::Resource::Scm) - end - - it "supports :checkout, :export, :sync, :diff, and :log actions" do - @resource.allowed_actions.should include(:checkout) - @resource.allowed_actions.should include(:export) - @resource.allowed_actions.should include(:sync) - @resource.allowed_actions.should include(:diff) - @resource.allowed_actions.should include(:log) - end - - it "takes the destination path as a string" do - @resource.destination "/path/to/deploy/dir" - @resource.destination.should eql("/path/to/deploy/dir") - end - - it "takes a string for the repository URL" do - @resource.repository "git://github.com/opscode/chef.git" - @resource.repository.should eql("git://github.com/opscode/chef.git") - end - - it "takes a string for the revision" do - @resource.revision "abcdef" - @resource.revision.should eql("abcdef") - end - - it "defaults to the ``HEAD'' revision" do - @resource.revision.should eql("HEAD") - end - - it "takes a string for the user to run as" do - @resource.user "dr_deploy" - @resource.user.should eql("dr_deploy") - end - - it "also takes an integer for the user to run as" do - @resource.user 0 - @resource.user.should eql(0) - end - - it "takes a string for the group to run as, defaulting to nil" do - @resource.group.should be_nil - @resource.group "opsdevs" - @resource.group.should == "opsdevs" - end - - it "also takes an integer for the group to run as" do - @resource.group 23 - @resource.group.should == 23 - end - - it "has a svn_username String attribute" do - @resource.svn_username "moartestsplz" - @resource.svn_username.should eql("moartestsplz") - end - - it "has a svn_password String attribute" do - @resource.svn_password "taftplz" - @resource.svn_password.should eql("taftplz") - end - - it "has a svn_arguments String attribute" do - @resource.svn_arguments "--more-taft plz" - @resource.svn_arguments.should eql("--more-taft plz") - end - - it "has a svn_info_args String attribute" do - @resource.svn_info_args.should be_nil - @resource.svn_info_args("--no-moar-plaintext-creds yep") - @resource.svn_info_args.should == "--no-moar-plaintext-creds yep" - end - - it "takes the depth as an integer for shallow clones" do - @resource.depth 5 - @resource.depth.should == 5 - lambda {@resource.depth "five"}.should raise_error(ArgumentError) - end - - it "defaults to nil depth for a full clone" do - @resource.depth.should be_nil - end - - it "takes a boolean for #enable_submodules" do - @resource.enable_submodules true - @resource.enable_submodules.should be_true - lambda {@resource.enable_submodules "lolz"}.should raise_error(ArgumentError) - end - - it "defaults to not enabling submodules" do - @resource.enable_submodules.should be_false - end - - it "takes a boolean for #enable_checkout" do - @resource.enable_checkout true - @resource.enable_checkout.should be_true - lambda {@resource.enable_checkout "lolz"}.should raise_error(ArgumentError) - end - - it "defaults to enabling checkout" do - @resource.enable_checkout.should be_true - end - - it "takes a string for the remote" do - @resource.remote "opscode" - @resource.remote.should eql("opscode") - lambda {@resource.remote 1337}.should raise_error(ArgumentError) - end - - it "defaults to ``origin'' for the remote" do - @resource.remote.should == "origin" - end - - it "takes a string for the ssh wrapper" do - @resource.ssh_wrapper "with_ssh_fu" - @resource.ssh_wrapper.should eql("with_ssh_fu") - end - - it "defaults to nil for the ssh wrapper" do - @resource.ssh_wrapper.should be_nil - end - - it "defaults to nil for the environment" do - @resource.environment.should be_nil - end - - describe "when it has a timeout attribute" do - let(:ten_seconds) { 10 } - before { @resource.timeout(ten_seconds) } - it "stores this timeout" do - @resource.timeout.should == ten_seconds - end - end - describe "when it has no timeout attribute" do - it "should have no default timeout" do - @resource.timeout.should be_nil - end - end - - describe "when it has repository, revision, user, and group" do - before do - @resource.destination("hell") - @resource.repository("apt") - @resource.revision("1.2.3") - @resource.user("root") - @resource.group("super_adventure_club") - end - - it "describes its state" do - state = @resource.state - state[:revision].should == "1.2.3" - end - - it "returns the destination as its identity" do - @resource.identity.should == "hell" - end - end - - describe "when it has a environment attribute" do - let(:test_environment) { {'CHEF_ENV' => '/tmp' } } - before { @resource.environment(test_environment) } - it "stores this environment" do - @resource.environment.should == test_environment - end - end -end diff --git a/spec/unit/resource/script_spec.rb b/spec/unit/resource/script_spec.rb deleted file mode 100644 index f100b0dc85..0000000000 --- a/spec/unit/resource/script_spec.rb +++ /dev/null @@ -1,46 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: Tyler Cloke (<tyler@opscode.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' - -describe Chef::Resource::Script do - let(:resource_instance_name) { "fakey_fakerton" } - let(:script_resource) { Chef::Resource::Script.new(resource_instance_name) } - let(:resource_name) { :script } - - it "should accept a string for the interpreter" do - script_resource.interpreter "naaaaNaNaNaaNaaNaaNaa" - script_resource.interpreter.should eql("naaaaNaNaNaaNaaNaaNaa") - end - - describe "when it has interpreter and flags" do - before do - script_resource.command("grep") - script_resource.interpreter("gcc") - script_resource.flags("-al") - end - - it "returns the command as its identity" do - script_resource.identity.should == "grep" - end - end - - it_behaves_like "a script resource" -end - diff --git a/spec/unit/resource/service_spec.rb b/spec/unit/resource/service_spec.rb deleted file mode 100644 index ec62d012bb..0000000000 --- a/spec/unit/resource/service_spec.rb +++ /dev/null @@ -1,190 +0,0 @@ -# -# Author:: AJ Christensen (<aj@hjksolutions.com>) -# Author:: Tyler Cloke (<tyler@opscode.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' - -describe Chef::Resource::Service do - - before(:each) do - @resource = Chef::Resource::Service.new("chef") - end - - it "should create a new Chef::Resource::Service" do - @resource.should be_a_kind_of(Chef::Resource) - @resource.should be_a_kind_of(Chef::Resource::Service) - end - - it "should not set a provider unless node[:init_package] is defined as systemd" do - @resource.provider.should == nil - end - - it "should set the provider to Chef::Provider::Service::Systemd if node[:init_package] is systemd" do - node = Chef::Node.new - node.set[:init_package] = "systemd" - cookbook_collection = Chef::CookbookCollection.new([]) - events = Chef::EventDispatch::Dispatcher.new - run_context = Chef::RunContext.new(node, cookbook_collection, events) - @resource = Chef::Resource::Service.new("chef", run_context) - @resource.provider.should == Chef::Provider::Service::Systemd - end - - it "should set the service_name to the first argument to new" do - @resource.service_name.should eql("chef") - end - - it "should set the pattern to be the service name by default" do - @resource.pattern.should eql("chef") - end - - it "should accept a string for the service name" do - @resource.service_name "something" - @resource.service_name.should eql("something") - end - - it "should accept a string for the service pattern" do - @resource.pattern ".*" - @resource.pattern.should eql(".*") - end - - it "should not accept a regexp for the service pattern" do - lambda { - @resource.pattern /.*/ - }.should raise_error(ArgumentError) - end - - it "should accept a string for the service start command" do - @resource.start_command "/etc/init.d/chef start" - @resource.start_command.should eql("/etc/init.d/chef start") - end - - it "should not accept a regexp for the service start command" do - lambda { - @resource.start_command /.*/ - }.should raise_error(ArgumentError) - end - - it "should accept a string for the service stop command" do - @resource.stop_command "/etc/init.d/chef stop" - @resource.stop_command.should eql("/etc/init.d/chef stop") - end - - it "should not accept a regexp for the service stop command" do - lambda { - @resource.stop_command /.*/ - }.should raise_error(ArgumentError) - end - - it "should accept a string for the service status command" do - @resource.status_command "/etc/init.d/chef status" - @resource.status_command.should eql("/etc/init.d/chef status") - end - - it "should not accept a regexp for the service status command" do - lambda { - @resource.status_command /.*/ - }.should raise_error(ArgumentError) - end - - it "should accept a string for the service restart command" do - @resource.restart_command "/etc/init.d/chef restart" - @resource.restart_command.should eql("/etc/init.d/chef restart") - end - - it "should not accept a regexp for the service restart command" do - lambda { - @resource.restart_command /.*/ - }.should raise_error(ArgumentError) - end - - it "should accept a string for the service reload command" do - @resource.reload_command "/etc/init.d/chef reload" - @resource.reload_command.should eql("/etc/init.d/chef reload") - end - - it "should not accept a regexp for the service reload command" do - lambda { - @resource.reload_command /.*/ - }.should raise_error(ArgumentError) - end - - it "should accept a string for the service init command" do - @resource.init_command "/etc/init.d/chef" - @resource.init_command.should eql("/etc/init.d/chef") - end - - it "should not accept a regexp for the service init command" do - lambda { - @resource.init_command /.*/ - }.should raise_error(ArgumentError) - end - - %w{enabled running}.each do |attrib| - it "should accept true for #{attrib}" do - @resource.send(attrib, true) - @resource.send(attrib).should eql(true) - end - - it "should accept false for #{attrib}" do - @resource.send(attrib, false) - @resource.send(attrib).should eql(false) - end - - it "should not accept a string for #{attrib}" do - lambda { @resource.send(attrib, "poop") }.should raise_error(ArgumentError) - end - - it "should default all the feature support to false" do - support_hash = { :status => false, :restart => false, :reload=> false } - @resource.supports.should == 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 } - @resource.supports(support_array) - @resource.supports.should == support_hash - end - - it "should allow you to set what features this resource supports as a hash" do - support_hash = { :status => true, :restart => true, :reload => false } - @resource.supports(support_hash) - @resource.supports.should == support_hash - end - end - - describe "when it has pattern and supports" do - before do - @resource.service_name("superfriend") - @resource.enabled(true) - @resource.running(false) - end - - it "describes its state" do - state = @resource.state - state[:enabled].should eql(true) - state[:running].should eql(false) - end - - it "returns the service name as its identity" do - @resource.identity.should == "superfriend" - end - end - - -end diff --git a/spec/unit/resource/smartos_package_spec.rb b/spec/unit/resource/smartos_package_spec.rb deleted file mode 100644 index 391713c8ff..0000000000 --- a/spec/unit/resource/smartos_package_spec.rb +++ /dev/null @@ -1,38 +0,0 @@ -# -# Author:: Thomas Bishop (<bishop.thomas@gmail.com>) -# Copyright:: Copyright (c) 2010 Thomas Bishop -# 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 File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper")) - -describe Chef::Resource::SmartosPackage, "initialize" do - - before(:each) do - @resource = Chef::Resource::SmartosPackage.new("foo") - end - - it "should return a Chef::Resource::SmartosPackage" do - @resource.should be_a_kind_of(Chef::Resource::SmartosPackage) - end - - it "should set the resource_name to :smartos_package" do - @resource.resource_name.should eql(:smartos_package) - end - - it "should set the provider to Chef::Provider::Package::SmartOS" do - @resource.provider.should eql(Chef::Provider::Package::SmartOS) - end -end diff --git a/spec/unit/resource/solaris_package_spec.rb b/spec/unit/resource/solaris_package_spec.rb deleted file mode 100644 index 6d0260ab5a..0000000000 --- a/spec/unit/resource/solaris_package_spec.rb +++ /dev/null @@ -1,57 +0,0 @@ -# -# Author:: Prabhu Das (<prabhu.das@clogeny.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::SolarisPackage, "initialize" do - - before(:each) do - @resource = Chef::Resource::SolarisPackage.new("foo") - end - - it "should return a Chef::Resource::SolarisPackage object" do - @resource.should be_a_kind_of(Chef::Resource::SolarisPackage) - end - - it "should not raise any Error when valid number of arguments are provided" do - expect { Chef::Resource::SolarisPackage.new("foo") }.to_not raise_error - end - - it "should raise ArgumentError when incorrect number of arguments are provided" do - expect { Chef::Resource::SolarisPackage.new }.to raise_error(ArgumentError) - end - - it "should set the package_name to the name provided" do - @resource.package_name.should eql("foo") - end - - it "should set the resource_name to :solaris_package" do - @resource.resource_name.should eql(:solaris_package) - end - - it "should set the run_context to the run_context provided" do - @run_context = double() - @run_context.stub(:node) - resource = Chef::Resource::SolarisPackage.new("foo", @run_context) - resource.run_context.should eql(@run_context) - end - - it "should set the provider to Chef::Provider::Package::Solaris" do - @resource.provider.should eql(Chef::Provider::Package::Solaris) - end -end diff --git a/spec/unit/resource/subversion_spec.rb b/spec/unit/resource/subversion_spec.rb deleted file mode 100644 index ae06ce665a..0000000000 --- a/spec/unit/resource/subversion_spec.rb +++ /dev/null @@ -1,63 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@kallistec.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' - -describe Chef::Resource::Subversion do - - before do - @svn = Chef::Resource::Subversion.new("ohai, svn project!") - end - - it "is a subclass of Resource::Scm" do - @svn.should be_an_instance_of(Chef::Resource::Subversion) - @svn.should be_a_kind_of(Chef::Resource::Scm) - end - - it "uses the subversion provider" do - @svn.provider.should eql(Chef::Provider::Subversion) - end - - it "allows the force_export action" do - @svn.allowed_actions.should include(:force_export) - end - - it "sets svn info arguments to --no-auth-cache by default" do - @svn.svn_info_args.should == '--no-auth-cache' - end - - it "resets svn info arguments to nil when given false in the setter" do - @svn.svn_info_args(false) - @svn.svn_info_args.should be_nil - end - - it "sets svn arguments to --no-auth-cache by default" do - @svn.svn_arguments.should == '--no-auth-cache' - end - - it "resets svn arguments to nil when given false in the setter" do - @svn.svn_arguments(false) - @svn.svn_arguments.should be_nil - end - - it "hides password from custom exception message" do - @svn.svn_password "l33th4x0rpa$$w0rd" - e = @svn.customize_exception(Chef::Exceptions::Exec.new "Exception with password #{@svn.svn_password}") - e.message.include?(@svn.svn_password).should be_false - end -end diff --git a/spec/unit/resource/template_spec.rb b/spec/unit/resource/template_spec.rb deleted file mode 100644 index c9dfdc7014..0000000000 --- a/spec/unit/resource/template_spec.rb +++ /dev/null @@ -1,211 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef::Resource::Template do - - before(:each) do - @resource = Chef::Resource::Template.new("fakey_fakerton") - end - - describe "initialize" do - it "should create a new Chef::Resource::Template" do - @resource.should be_a_kind_of(Chef::Resource) - @resource.should be_a_kind_of(Chef::Resource::File) - @resource.should be_a_kind_of(Chef::Resource::Template) - end - end - - describe "source" do - it "should accept a string for the template source" do - @resource.source "something" - @resource.source.should eql("something") - end - - it "should have a default based on the param name with .erb appended" do - @resource.source.should eql("fakey_fakerton.erb") - end - - it "should use only the basename of the file as the default" do - r = Chef::Resource::Template.new("/tmp/obit/fakey_fakerton") - r.source.should eql("fakey_fakerton.erb") - end - end - - describe "variables" do - it "should accept a hash for the variable list" do - @resource.variables({ :reluctance => :awkward }) - @resource.variables.should == { :reluctance => :awkward } - end - end - - describe "cookbook" do - it "should accept a string for the cookbook name" do - @resource.cookbook("foo") - @resource.cookbook.should == "foo" - end - - it "should default to nil" do - @resource.cookbook.should == nil - end - end - - describe "local" do - it "should accept a boolean for whether a template is local or remote" do - @resource.local(true) - @resource.local.should == true - end - - it "should default to false" do - @resource.local.should == false - end - end - - describe "when it has a path, owner, group, mode, and checksum" do - before do - @resource.path("/tmp/foo.txt") - @resource.owner("root") - @resource.group("wheel") - @resource.mode("0644") - @resource.checksum("1" * 64) - end - - context "on unix", :unix_only do - it "describes its state" do - state = @resource.state - state[:owner].should == "root" - state[:group].should == "wheel" - state[:mode].should == "0644" - state[:checksum].should == "1" * 64 - end - end - - context "on windows", :windows_only do - # according to Chef::Resource::File, windows state attributes are rights + deny_rights - pending "it describes its state" - end - - it "returns the file path as its identity" do - @resource.identity.should == "/tmp/foo.txt" - end - end - - describe "defining helper methods" do - - module ExampleHelpers - def static_example - "static_example" - end - end - - it "collects helper method bodies as blocks" do - @resource.helper(:example_1) { "example_1" } - @resource.helper(:example_2) { "example_2" } - @resource.inline_helper_blocks[:example_1].call.should == "example_1" - @resource.inline_helper_blocks[:example_2].call.should == "example_2" - end - - it "compiles helper methods into a module" do - @resource.helper(:example_1) { "example_1" } - @resource.helper(:example_2) { "example_2" } - modules = @resource.helper_modules - modules.should have(1).module - o = Object.new - modules.each {|m| o.extend(m)} - o.example_1.should == "example_1" - o.example_2.should == "example_2" - end - - it "compiles helper methods with arguments into a module" do - @resource.helper(:shout) { |quiet| quiet.upcase } - modules = @resource.helper_modules - o = Object.new - modules.each {|m| o.extend(m)} - o.shout("shout").should == "SHOUT" - end - - it "raises an error when attempting to define a helper method without a method body" do - lambda { @resource.helper(:example) }.should raise_error(Chef::Exceptions::ValidationFailed) - end - - it "raises an error when attempting to define a helper method with a non-Symbod method name" do - lambda { @resource.helper("example") { "fail" } }.should raise_error(Chef::Exceptions::ValidationFailed) - end - - it "collects helper module bodies as blocks" do - @resource.helpers do - def example_1 - "example_1" - end - end - module_body = @resource.inline_helper_modules.first - module_body.should be_a(Proc) - end - - it "compiles helper module bodies into modules" do - @resource.helpers do - def example_1 - "example_1" - end - end - modules = @resource.helper_modules - modules.should have(1).module - o = Object.new - modules.each {|m| o.extend(m)} - o.example_1.should == "example_1" - end - - it "raises an error when no block or module name is given for helpers definition" do - lambda { @resource.helpers() }.should raise_error(Chef::Exceptions::ValidationFailed) - end - - it "raises an error when a non-module is given for helpers definition" do - lambda { @resource.helpers("NotAModule") }.should raise_error(Chef::Exceptions::ValidationFailed) - end - - it "raises an error when a module name and block are both given for helpers definition" do - lambda { @resource.helpers(ExampleHelpers) { module_code } }.should raise_error(Chef::Exceptions::ValidationFailed) - end - - it "collects helper modules" do - @resource.helpers(ExampleHelpers) - @resource.helper_modules.should include(ExampleHelpers) - end - - it "combines all helpers into a set of compiled modules" do - @resource.helpers(ExampleHelpers) - @resource.helpers do - def inline_module - "inline_module" - end - end - @resource.helper(:inline_method) { "inline_method" } - @resource.should have(3).helper_modules - - o = Object.new - @resource.helper_modules.each {|m| o.extend(m)} - o.static_example.should == "static_example" - o.inline_module.should == "inline_module" - o.inline_method.should == "inline_method" - end - - - end - -end diff --git a/spec/unit/resource/timestamped_deploy_spec.rb b/spec/unit/resource/timestamped_deploy_spec.rb deleted file mode 100644 index f380ffca87..0000000000 --- a/spec/unit/resource/timestamped_deploy_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@kallistec.com>) -# Copyright:: Copyright (c) 2009 Daniel DeLeo -# 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::TimestampedDeploy do - - it "defaults to the TimestampedDeploy provider" do - @resource = Chef::Resource::TimestampedDeploy.new("stuff") - @resource.provider.should == Chef::Provider::Deploy::Timestamped - end - -end diff --git a/spec/unit/resource/user_spec.rb b/spec/unit/resource/user_spec.rb deleted file mode 100644 index 70b866202b..0000000000 --- a/spec/unit/resource/user_spec.rb +++ /dev/null @@ -1,133 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef::Resource::User, "initialize" do - before(:each) do - @resource = Chef::Resource::User.new("adam") - end - - it "should create a new Chef::Resource::User" do - @resource.should be_a_kind_of(Chef::Resource) - @resource.should be_a_kind_of(Chef::Resource::User) - end - - it "should set the resource_name to :user" do - @resource.resource_name.should eql(:user) - end - - it "should set the username equal to the argument to initialize" do - @resource.username.should eql("adam") - end - - %w{comment uid gid home shell password}.each do |attrib| - it "should set #{attrib} to nil" do - @resource.send(attrib).should eql(nil) - end - end - - it "should set action to :create" do - @resource.action.should eql(:create) - end - - it "should set supports[:manage_home] to false" do - @resource.supports[:manage_home].should eql(false) - end - - it "should set supports[:non_unique] to false" do - @resource.supports[:non_unique].should eql(false) - end - - it "should set force to false" do - @resource.force.should eql(false) - end - - %w{create remove modify manage lock unlock}.each do |action| - it "should allow action #{action}" do - @resource.allowed_actions.detect { |a| a == action.to_sym }.should eql(action.to_sym) - end - end - - it "should accept domain users (@ or \ separator) on non-windows" do - lambda { @resource.username "domain\@user" }.should_not raise_error - @resource.username.should == "domain\@user" - lambda { @resource.username "domain\\user" }.should_not raise_error - @resource.username.should == "domain\\user" - end -end - -%w{username comment home shell password}.each do |attrib| - describe Chef::Resource::User, attrib do - before(:each) do - @resource = Chef::Resource::User.new("adam") - end - - it "should allow a string" do - @resource.send(attrib, "adam") - @resource.send(attrib).should eql("adam") - end - - it "should not allow a hash" do - lambda { @resource.send(attrib, { :woot => "i found it" }) }.should raise_error(ArgumentError) - end - end -end - -%w{uid gid}.each do |attrib| - describe Chef::Resource::User, attrib do - before(:each) do - @resource = Chef::Resource::User.new("adam") - end - - it "should allow a string" do - @resource.send(attrib, "100") - @resource.send(attrib).should eql("100") - end - - it "should allow an integer" do - @resource.send(attrib, 100) - @resource.send(attrib).should eql(100) - end - - it "should not allow a hash" do - lambda { @resource.send(attrib, { :woot => "i found it" }) }.should raise_error(ArgumentError) - end - end - - describe "when it has uid, gid, and home" do - before do - @resource = Chef::Resource::User.new("root") - @resource.uid(123) - @resource.gid(456) - @resource.home("/usr/local/root/") - end - - it "describes its state" do - state = @resource.state - state[:uid].should == 123 - state[:gid].should == 456 - state[:home].should == "/usr/local/root/" - end - - it "returns the username as its identity" do - @resource.identity.should == "root" - end - end - -end diff --git a/spec/unit/resource/windows_package_spec.rb b/spec/unit/resource/windows_package_spec.rb deleted file mode 100644 index c9ef8d910c..0000000000 --- a/spec/unit/resource/windows_package_spec.rb +++ /dev/null @@ -1,74 +0,0 @@ -# -# Author:: Bryan McLellan <btm@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 'spec_helper' - -describe Chef::Resource::WindowsPackage, "initialize", :windows_only do - - let(:resource) { Chef::Resource::WindowsPackage.new("solitaire.msi") } - - it "returns a Chef::Resource::WindowsPackage" do - expect(resource).to be_a_kind_of(Chef::Resource::WindowsPackage) - end - - it "sets the resource_name to :windows_package" do - expect(resource.resource_name).to eql(:windows_package) - end - - it "sets the provider to Chef::Provider::Package::Windows" do - expect(resource.provider).to eql(Chef::Provider::Package::Windows) - end - - it "supports setting installer_type" do - resource.installer_type("msi") - expect(resource.installer_type).to eql("msi") - end - - # String, Integer - [ "600", 600 ].each do |val| - it "supports setting a timeout as a #{val.class}" do - resource.timeout(val) - expect(resource.timeout).to eql(val) - end - end - - # String, Integer, Array - [ "42", 42, [47, 48, 49] ].each do |val| - it "supports setting an alternate return value as a #{val.class}" do - resource.returns(val) - expect(resource.returns).to eql(val) - end - end - - it "coverts a source to an absolute path" do - ::File.stub(:absolute_path).and_return("c:\\Files\\frost.msi") - resource.source("frost.msi") - expect(resource.source).to eql "c:\\Files\\frost.msi" - end - - it "converts slashes to backslashes in the source path" do - ::File.stub(:absolute_path).and_return("c:\\frost.msi") - resource.source("c:/frost.msi") - expect(resource.source).to eql "c:\\frost.msi" - end - - it "defaults source to the resource name" do - # it's a little late to stub out File.absolute_path - expect(resource.source).to include("solitaire.msi") - end -end diff --git a/spec/unit/resource/windows_service_spec.rb b/spec/unit/resource/windows_service_spec.rb deleted file mode 100644 index c92c3be1b0..0000000000 --- a/spec/unit/resource/windows_service_spec.rb +++ /dev/null @@ -1,46 +0,0 @@ -# -# Author:: Bryan McLellan <btm@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 'spec_helper' - -describe Chef::Resource::WindowsService, "initialize", :windows_only do - - let(:resource) { Chef::Resource::WindowsService.new("BITS") } - - it "returns a Chef::Resource::WindowsService" do - expect(resource).to be_a_kind_of(Chef::Resource::WindowsService) - end - - it "sets the resource_name to :windows_service" do - expect(resource.resource_name).to eql(:windows_service) - end - - it "sets the provider to Chef::Provider::Service::Windows" do - expect(resource.provider).to eql(Chef::Provider::Service::Windows) - end - - it "supports setting startup_type" do - resource.startup_type(:manual) - expect(resource.startup_type).to eql(:manual) - end - - it "allows the action to be 'configure_startup'" do - resource.action :configure_startup - resource.action.should == [:configure_startup] - end -end diff --git a/spec/unit/resource/yum_package_spec.rb b/spec/unit/resource/yum_package_spec.rb deleted file mode 100644 index 57ab4dfcd9..0000000000 --- a/spec/unit/resource/yum_package_spec.rb +++ /dev/null @@ -1,85 +0,0 @@ -# -# Author:: AJ Christensen (<aj@opscode.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' - -describe Chef::Resource::YumPackage, "initialize" do - - before(:each) do - @resource = Chef::Resource::YumPackage.new("foo") - end - - it "should return a Chef::Resource::YumPackage" do - @resource.should be_a_kind_of(Chef::Resource::YumPackage) - end - - it "should set the resource_name to :yum_package" do - @resource.resource_name.should eql(:yum_package) - end - - it "should set the provider to Chef::Provider::Package::Yum" do - @resource.provider.should eql(Chef::Provider::Package::Yum) - end -end - -describe Chef::Resource::YumPackage, "arch" do - before(:each) do - @resource = Chef::Resource::YumPackage.new("foo") - end - - it "should set the arch variable to whatever is passed in" do - @resource.arch("i386") - @resource.arch.should eql("i386") - end -end - -describe Chef::Resource::YumPackage, "flush_cache" do - before(:each) do - @resource = Chef::Resource::YumPackage.new("foo") - end - - it "should default the flush timing to false" do - flush_hash = { :before => false, :after => false } - @resource.flush_cache.should == flush_hash - end - - it "should allow you to set the flush timing with an array" do - flush_array = [ :before, :after ] - flush_hash = { :before => true, :after => true } - @resource.flush_cache(flush_array) - @resource.flush_cache.should == flush_hash - end - - it "should allow you to set the flush timing with a hash" do - flush_hash = { :before => true, :after => true } - @resource.flush_cache(flush_hash) - @resource.flush_cache.should == flush_hash - end -end - -describe Chef::Resource::YumPackage, "allow_downgrade" do - before(:each) do - @resource = Chef::Resource::YumPackage.new("foo") - end - - it "should allow you to specify whether allow_downgrade is true or false" do - lambda { @resource.allow_downgrade true }.should_not raise_error - lambda { @resource.allow_downgrade false }.should_not raise_error - lambda { @resource.allow_downgrade "monkey" }.should raise_error(ArgumentError) - end -end diff --git a/spec/unit/resource_collection/stepable_iterator_spec.rb b/spec/unit/resource_collection/stepable_iterator_spec.rb deleted file mode 100644 index b649f8be6e..0000000000 --- a/spec/unit/resource_collection/stepable_iterator_spec.rb +++ /dev/null @@ -1,144 +0,0 @@ -# Author:: Daniel DeLeo (<dan@kallistec.com>) -# Copyright:: Copyright (c) 2009 Daniel DeLeo -# 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::ResourceCollection::StepableIterator do - CRSI = Chef::ResourceCollection::StepableIterator - - it "has an empty array for its collection by default" do - CRSI.new.collection.should == [] - end - - describe "doing basic iteration" do - before do - @simple_collection = [1,2,3,4] - @iterator = CRSI.for_collection(@simple_collection) - end - - it "re-initializes the instance with a collection" do - @iterator.collection.should equal(@simple_collection) - @iterator.size.should == 4 - end - - it "iterates over the collection" do - sum = 0 - @iterator.each do |int| - sum += int - end - sum.should == 10 - end - - it "iterates over the collection with each_index" do - collected_by_index = [] - @iterator.each_index do |idx| - collected_by_index << @simple_collection[idx] - end - collected_by_index.should == @simple_collection - collected_by_index.should_not equal(@simple_collection) - end - - it "iterates over the collection with index and element" do - collected = {} - @iterator.each_with_index do |element, index| - collected[index] = element - end - collected.should == {0=>1, 1=>2, 2=>3, 3=>4} - end - - end - - describe "pausing and resuming iteration" do - - before do - @collection = [] - @snitch_var = nil - @collection << lambda { @snitch_var = 23 } - @collection << lambda { @iterator.pause } - @collection << lambda { @snitch_var = 42 } - - @iterator = CRSI.for_collection(@collection) - @iterator.each { |proc| proc.call } - end - - it "allows the iteration to be paused" do - @snitch_var.should == 23 - end - - it "allows the iteration to be resumed" do - @snitch_var.should == 23 - @iterator.resume - @snitch_var.should == 42 - end - - it "allows iteration to be rewound" do - @iterator.skip_back(2) - @iterator.resume - @snitch_var.should == 23 - @iterator.resume - @snitch_var.should == 42 - end - - it "allows iteration to be fast forwarded" do - @iterator.skip_forward - @iterator.resume - @snitch_var.should == 23 - end - - it "allows iteration to be rewound" do - @snitch_var = nil - @iterator.rewind - @iterator.position.should == 0 - @iterator.resume - @snitch_var.should == 23 - end - - it "allows iteration to be stepped" do - @snitch_var = nil - @iterator.rewind - @iterator.step - @iterator.position.should == 1 - @snitch_var.should == 23 - end - - it "doesn't step if there are no more steps" do - @iterator.step.should == 3 - lambda {@iterator.step}.should_not raise_error - @iterator.step.should be_nil - end - - it "allows the iteration to start by being stepped" do - @snitch_var = nil - @iterator = CRSI.for_collection(@collection) - @iterator.iterate_on(:element) { |proc| proc.call } - @iterator.step - @iterator.position.should == 1 - @snitch_var.should == 23 - end - - it "should work correctly when elements are added to the collection during iteration" do - @collection.insert(2, lambda { @snitch_var = 815}) - @collection.insert(3, lambda { @iterator.pause }) - @iterator.resume - @snitch_var.should == 815 - @iterator.resume - @snitch_var.should == 42 - end - - end - -end diff --git a/spec/unit/resource_collection_spec.rb b/spec/unit/resource_collection_spec.rb deleted file mode 100644 index eddd92e098..0000000000 --- a/spec/unit/resource_collection_spec.rb +++ /dev/null @@ -1,319 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: Christopher Walters (<cw@opscode.com>) -# Copyright:: Copyright (c) 2008, 2009 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::ResourceCollection do - - before(:each) do - @rc = Chef::ResourceCollection.new() - @resource = Chef::Resource::ZenMaster.new("makoto") - end - - describe "initialize" do - it "should return a Chef::ResourceCollection" do - @rc.should be_kind_of(Chef::ResourceCollection) - end - end - - describe "[]" do - it "should accept Chef::Resources through [index]" do - lambda { @rc[0] = @resource }.should_not raise_error - lambda { @rc[0] = "string" }.should raise_error - end - - it "should allow you to fetch Chef::Resources by position" do - @rc[0] = @resource - @rc[0].should eql(@resource) - end - end - - describe "push" do - it "should accept Chef::Resources through pushing" do - lambda { @rc.push(@resource) }.should_not raise_error - lambda { @rc.push("string") }.should raise_error - end - end - - describe "<<" do - it "should accept the << operator" do - lambda { @rc << @resource }.should_not raise_error - end - end - - describe "insert" do - it "should accept only Chef::Resources" do - lambda { @rc.insert(@resource) }.should_not raise_error - lambda { @rc.insert("string") }.should raise_error - end - - it "should append resources to the end of the collection when not executing a run" do - zmr = Chef::Resource::ZenMaster.new("there is no spoon") - @rc.insert(@resource) - @rc.insert(zmr) - @rc[0].should eql(@resource) - @rc[1].should eql(zmr) - end - - it "should insert resources to the middle of the collection if called while executing a run" do - resource_to_inject = Chef::Resource::ZenMaster.new("there is no spoon") - zmr = Chef::Resource::ZenMaster.new("morpheus") - dummy = Chef::Resource::ZenMaster.new("keanu reeves") - @rc.insert(zmr) - @rc.insert(dummy) - - @rc.execute_each_resource do |resource| - @rc.insert(resource_to_inject) if resource == zmr - end - - @rc[0].should eql(zmr) - @rc[1].should eql(resource_to_inject) - @rc[2].should eql(dummy) - end - end - - describe "insert_at" do - it "should accept only Chef::Resources" do - lambda { @rc.insert_at(0, @resource, @resource) }.should_not raise_error - lambda { @rc.insert_at(0, "string") }.should raise_error - lambda { @rc.insert_at(0, @resource, "string") }.should raise_error - end - - it "should toss an error if it receives a bad index" do - @rc.insert_at(10, @resource) - end - - it "should insert resources at the beginning when asked" do - @rc.insert(Chef::Resource::ZenMaster.new('1')) - @rc.insert(Chef::Resource::ZenMaster.new('2')) - @rc.insert_at(0, Chef::Resource::ZenMaster.new('X')) - @rc.all_resources.map { |r| r.name }.should == [ 'X', '1', '2' ] - end - - it "should insert resources in the middle when asked" do - @rc.insert(Chef::Resource::ZenMaster.new('1')) - @rc.insert(Chef::Resource::ZenMaster.new('2')) - @rc.insert_at(1, Chef::Resource::ZenMaster.new('X')) - @rc.all_resources.map { |r| r.name }.should == [ '1', 'X', '2' ] - end - - it "should insert resources at the end when asked" do - @rc.insert(Chef::Resource::ZenMaster.new('1')) - @rc.insert(Chef::Resource::ZenMaster.new('2')) - @rc.insert_at(2, Chef::Resource::ZenMaster.new('X')) - @rc.all_resources.map { |r| r.name }.should == [ '1', '2', 'X' ] - end - end - - describe "each" do - it "should allow you to iterate over every resource in the collection" do - load_up_resources - results = Array.new - lambda { - @rc.each do |r| - results << r.name - end - }.should_not raise_error - results.each_index do |i| - case i - when 0 - results[i].should eql("dog") - when 1 - results[i].should eql("cat") - when 2 - results[i].should eql("monkey") - end - end - end - end - - describe "each_index" do - it "should allow you to iterate over every resource by index" do - load_up_resources - results = Array.new - lambda { - @rc.each_index do |i| - results << @rc[i].name - end - }.should_not raise_error - results.each_index do |i| - case i - when 0 - results[i].should eql("dog") - when 1 - results[i].should eql("cat") - when 2 - results[i].should eql("monkey") - end - end - end - end - - describe "lookup" do - it "should allow you to find resources by name via lookup" do - zmr = Chef::Resource::ZenMaster.new("dog") - @rc << zmr - @rc.lookup(zmr.to_s).should eql(zmr) - - zmr = Chef::Resource::ZenMaster.new("cat") - @rc[0] = zmr - @rc.lookup(zmr).should eql(zmr) - - zmr = Chef::Resource::ZenMaster.new("monkey") - @rc.push(zmr) - @rc.lookup(zmr).should eql(zmr) - end - - it "should raise an exception if you send something strange to lookup" do - lambda { @rc.lookup(:symbol) }.should raise_error(ArgumentError) - end - - it "should raise an exception if it cannot find a resource with lookup" do - lambda { @rc.lookup("zen_master[dog]") }.should raise_error(Chef::Exceptions::ResourceNotFound) - end - end - - describe "resources" do - - it "should find a resource by symbol and name (:zen_master => monkey)" do - load_up_resources - @rc.resources(:zen_master => "monkey").name.should eql("monkey") - end - - it "should find a resource by symbol and array of names (:zen_master => [a,b])" do - load_up_resources - results = @rc.resources(:zen_master => [ "monkey", "dog" ]) - results.length.should eql(2) - check_by_names(results, "monkey", "dog") - end - - it "should find resources of multiple kinds (:zen_master => a, :file => b)" do - load_up_resources - results = @rc.resources(:zen_master => "monkey", :file => "something") - results.length.should eql(2) - check_by_names(results, "monkey", "something") - end - - it "should find a resource by string zen_master[a]" do - load_up_resources - @rc.resources("zen_master[monkey]").name.should eql("monkey") - end - - it "should find resources by strings of zen_master[a,b]" do - load_up_resources - results = @rc.resources("zen_master[monkey,dog]") - results.length.should eql(2) - check_by_names(results, "monkey", "dog") - end - - it "should find resources of multiple types by strings of zen_master[a]" do - load_up_resources - results = @rc.resources("zen_master[monkey]", "file[something]") - results.length.should eql(2) - check_by_names(results, "monkey", "something") - end - - it "should raise an exception if you pass a bad name to resources" do - lambda { @rc.resources("michael jackson") }.should raise_error(ArgumentError) - end - - it "should raise an exception if you pass something other than a string or hash to resource" do - lambda { @rc.resources([Array.new]) }.should raise_error(ArgumentError) - end - - it "raises an error when attempting to find a resource that does not exist" do - lambda {@rc.find("script[nonesuch]")}.should raise_error(Chef::Exceptions::ResourceNotFound) - end - - end - - describe "when validating a resource query object" do - it "accepts a string of the form 'resource_type[resource_name]'" do - @rc.validate_lookup_spec!("resource_type[resource_name]").should be_true - end - - it "accepts a single-element :resource_type => 'resource_name' Hash" do - @rc.validate_lookup_spec!(:service => "apache2").should be_true - end - - - it "accepts a chef resource object" do - res = Chef::Resource.new("foo", nil) - @rc.validate_lookup_spec!(res).should be_true - end - - it "rejects a malformed query string" do - lambda do - @rc.validate_lookup_spec!("resource_type[missing-end-bracket") - end.should raise_error(Chef::Exceptions::InvalidResourceSpecification) - end - - it "rejects an argument that is not a String, Hash, or Chef::Resource" do - lambda do - @rc.validate_lookup_spec!(Object.new) - end.should raise_error(Chef::Exceptions::InvalidResourceSpecification) - end - - end - - describe "to_json" do - it "should serialize to json" do - json = @rc.to_json - json.should =~ /json_class/ - json.should =~ /instance_vars/ - end - end - - describe "self.from_json" do - it "should deserialize itself from json" do - @rc << @resource - json = @rc.to_json - s_rc = Chef::JSONCompat.from_json(json) - s_rc.should be_a_kind_of(Chef::ResourceCollection) - s_rc[0].name.should eql(@resource.name) - end - end - - describe "provides access to the raw resources array" do - it "returns the resources via the all_resources method" do - @rc.all_resources.should equal(@rc.instance_variable_get(:@resources)) - end - end - - describe "provides access to stepable iterator" do - it "returns the iterator object" do - @rc.instance_variable_set(:@iterator, :fooboar) - @rc.iterator.should == :fooboar - end - end - - def check_by_names(results, *names) - names.each do |res_name| - results.detect{ |res| res.name == res_name }.should_not eql(nil) - end - end - - def load_up_resources - %w{dog cat monkey}.each do |n| - @rc << Chef::Resource::ZenMaster.new(n) - end - @rc << Chef::Resource::File.new("something") - end - -end diff --git a/spec/unit/resource_definition_spec.rb b/spec/unit/resource_definition_spec.rb deleted file mode 100644 index f24254cfce..0000000000 --- a/spec/unit/resource_definition_spec.rb +++ /dev/null @@ -1,119 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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' - -describe Chef::ResourceDefinition do - before(:each) do - @def = Chef::ResourceDefinition.new() - end - - describe "initialize" do - it "should be a Chef::ResourceDefinition" do - @def.should be_a_kind_of(Chef::ResourceDefinition) - end - - it "should not initialize a new node if one is not provided" do - @def.node.should eql(nil) - end - - it "should accept a node as an argument" do - node = Chef::Node.new - node.name("bobo") - @def = Chef::ResourceDefinition.new(node) - @def.node.name.should == "bobo" - end - end - - describe "node" do - it "should set the node with node=" do - node = Chef::Node.new - node.name("bobo") - @def.node = node - @def.node.name.should == "bobo" - end - - it "should return the node" do - @def.node = Chef::Node.new - @def.node.should be_a_kind_of(Chef::Node) - end - end - - it "should accept a new definition with a symbol for a name" do - lambda { - @def.define :smoke do - end - }.should_not raise_error - lambda { - @def.define "george washington" do - end - }.should raise_error(ArgumentError) - @def.name.should eql(:smoke) - end - - it "should accept a new definition with a hash" do - lambda { - @def.define :smoke, :cigar => "cuban", :cigarette => "marlboro" do - end - }.should_not raise_error - end - - it "should expose the prototype hash params in the params hash" do - @def.define :smoke, :cigar => "cuban", :cigarette => "marlboro" do; end - @def.params[:cigar].should eql("cuban") - @def.params[:cigarette].should eql("marlboro") - end - - it "should store the block passed to define as a proc under recipe" do - @def.define :smoke do - "I am what I am" - end - @def.recipe.should be_a_kind_of(Proc) - @def.recipe.call.should eql("I am what I am") - end - - it "should set paramaters based on method_missing" do - @def.mind "to fly" - @def.params[:mind].should eql("to fly") - end - - it "should raise an exception if prototype_params is not a hash" do - lambda { - @def.define :monkey, Array.new do - end - }.should raise_error(ArgumentError) - end - - it "should raise an exception if define is called without a block" do - lambda { - @def.define :monkey - }.should raise_error(ArgumentError) - end - - it "should load a description from a file" do - @def.from_file(File.join(CHEF_SPEC_DATA, "definitions", "test.rb")) - @def.name.should eql(:rico_suave) - @def.params[:rich].should eql("smooth") - end - - it "should turn itself into a string based on the name with to_s" do - @def.name = :woot - @def.to_s.should eql("woot") - end - -end diff --git a/spec/unit/resource_platform_map_spec.rb b/spec/unit/resource_platform_map_spec.rb deleted file mode 100644 index 99673d868f..0000000000 --- a/spec/unit/resource_platform_map_spec.rb +++ /dev/null @@ -1,164 +0,0 @@ -# -# Author:: Seth Chisamore (<schisamo@opscode.com>) -# Copyright:: Copyright (c) 2011 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::PlatformMap do - - before(:each) do - @platform_map = Chef::Resource::PlatformMap.new({ - :windows => { - "6.1" => { - :file => "softiefile", - :else => "thing" - }, - :default => { - :file => Chef::Resource::File, - :ping => "pong", - :cat => "nice" - } - }, - :pop_tron => { - }, - :default => { - :soundwave => "lazerbeak", - :directory => Chef::Resource::Directory, - } - }) - end - - describe 'filtering the map' do - it "returns resources for platform and version" do - pmap = @platform_map.filter("Windows", "6.1") - pmap.should be_a_kind_of(Hash) - pmap[:file].should eql("softiefile") - end - - it "returns platform default resources if version does not exist" do - pmap = @platform_map.filter("windows", "1") - pmap.should be_a_kind_of(Hash) - pmap[:file].should eql(Chef::Resource::File) - end - - it "returns global default resources if none exist for plaform" do - pmap = @platform_map.filter("pop_tron", "1") - pmap.should be_a_kind_of(Hash) - pmap[:directory].should eql(Chef::Resource::Directory) - end - - it "returns global default resources if platform does not exist" do - pmap = @platform_map.filter("BeOS", "1") - pmap.should be_a_kind_of(Hash) - pmap[:soundwave].should eql("lazerbeak") - end - - it "returns a merged map of platform version and plaform default resources" do - pmap = @platform_map.filter("Windows", "6.1") - pmap[:file].should eql("softiefile") - pmap[:ping].should eql("pong") - end - - it "returns a merged map of platform specific version and global defaults" do - pmap = @platform_map.filter("Windows", "6.1") - pmap[:file].should eql("softiefile") - pmap[:soundwave].should eql("lazerbeak") - end - end - - describe 'finding a resource' do - it "returns a resource for a platform directly by short name" do - @platform_map.get(:file, "windows", "6.1").should eql("softiefile") - end - - it "returns a default resource if platform and version don't exist" do - @platform_map.get(:remote_file).should eql(Chef::Resource::RemoteFile) - end - - it "raises an exception if a resource cannot be found" do - lambda { @platform_map.get(:coffee, "windows", "6.1")}.should raise_error(NameError) - end - - it "returns a resource with a Chef::Resource object" do - kitty = Chef::Resource::Cat.new("loulou") - @platform_map.get(kitty, "windows", "6.1").should eql("nice") - end - end - - describe 'building the map' do - it "allows passing of a resource map at creation time" do - @new_map = Chef::Resource::PlatformMap.new({:the_dude => {:default => 'abides'}}) - @new_map.map[:the_dude][:default].should eql("abides") - end - - it "defaults to a resource map with :default key" do - @new_map = Chef::Resource::PlatformMap.new - @new_map.map.has_key?(:default) - end - - it "updates the resource map with a map" do - @platform_map.set( - :platform => :darwin, - :version => "9.2.2", - :short_name => :file, - :resource => "masterful" - ) - @platform_map.map[:darwin]["9.2.2"][:file].should eql("masterful") - - @platform_map.set( - :platform => :darwin, - :short_name => :file, - :resource => "masterful" - ) - @platform_map.map[:darwin][:default][:file].should eql("masterful") - - @platform_map.set( - :short_name => :file, - :resource => "masterful" - ) - @platform_map.map[:default][:file].should eql("masterful") - - @platform_map.set( - :platform => :hero, - :version => "9.2.2", - :short_name => :file, - :resource => "masterful" - ) - @platform_map.map[:hero]["9.2.2"][:file].should eql("masterful") - - @platform_map.set( - :short_name => :file, - :resource => "masterful" - ) - @platform_map.map[:default][:file].should eql("masterful") - - @platform_map.set( - :short_name => :file, - :resource => "masterful" - ) - @platform_map.map[:default][:file].should eql("masterful") - - @platform_map.set( - :platform => :neurosis, - :short_name => :package, - :resource => "masterful" - ) - @platform_map.map[:neurosis][:default][:package].should eql("masterful") - end - end - -end diff --git a/spec/unit/resource_reporter_spec.rb b/spec/unit/resource_reporter_spec.rb deleted file mode 100644 index fe6a895b5a..0000000000 --- a/spec/unit/resource_reporter_spec.rb +++ /dev/null @@ -1,759 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@opscode.com>) -# Author:: Prajakta Purohit (<prajakta@opscode.com>) -# Author:: Tyler Cloke (<tyler@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 File.expand_path("../../spec_helper", __FILE__) -require 'chef/resource_reporter' -require 'socket' - -describe Chef::ResourceReporter do - before(:all) do - @reporting_toggle_default = Chef::Config[:enable_reporting] - Chef::Config[:enable_reporting] = true - end - - after(:all) do - Chef::Config[:enable_reporting] = @reporting_toggle_default - end - - before do - @node = Chef::Node.new - @node.name("spitfire") - @rest_client = double("Chef::REST (mock)") - @rest_client.stub(:post_rest).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") - @new_resource.stub(:cookbook_version).and_return(@cookbook_version) - @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_id = @run_status.run_id - Time.stub(:now).and_return(@start_time, @end_time) - end - - context "when first created" do - - it "has no updated resources" do - @resource_reporter.should have(0).updated_resources - end - - it "reports a successful run" do - @resource_reporter.status.should == "success" - end - - it "assumes the resource history feature is supported" do - @resource_reporter.reporting_enabled?.should be_true - end - - it "should have no error_descriptions" do - @resource_reporter.error_descriptions.should eq({}) - # @resource_reporter.error_descriptions.should be_empty - # @resource_reporter.should have(0).error_descriptions - end - - end - - context "after the chef run completes" do - - before do - end - - it "reports a successful run" do - pending "refactor how node gets set." - @resource_reporter.status.should == "success" - end - end - - context "when chef fails" do - before do - @rest_client.stub(:create_url).and_return("reports/nodes/spitfire/runs/#{@run_id}"); - @rest_client.stub(:raw_http_request).and_return({"result"=>"ok"}); - @rest_client.stub(:post_rest).and_return({"uri"=>"https://example.com/reports/nodes/spitfire/runs/#{@run_id}"}); - - end - - context "before converging any resources" do - before do - @resource_reporter.run_started(@run_status) - @exception = Exception.new - @resource_reporter.run_failed(@exception) - end - - it "sets the run status to 'failure'" do - @resource_reporter.status.should == "failure" - end - - it "keeps the exception data" do - @resource_reporter.exception.should == @exception - end - end - - context "when a resource fails before loading current state" do - before do - @exception = Exception.new - @exception.set_backtrace(caller) - @resource_reporter.resource_action_start(@new_resource, :create) - @resource_reporter.resource_failed(@new_resource, :create, @exception) - @resource_reporter.resource_completed(@new_resource) - end - - it "collects the resource as an updated resource" do - @resource_reporter.should have(1).updated_resources - end - - it "collects the desired state of the resource" do - update_record = @resource_reporter.updated_resources.first - update_record.new_resource.should == @new_resource - end - end - - # TODO: make sure a resource that is skipped because of `not_if` doesn't - # leave us in a bad state. - - context "once the a resource's current state is loaded" do - before do - @resource_reporter.resource_action_start(@new_resource, :create) - @resource_reporter.resource_current_state_loaded(@new_resource, :create, @current_resource) - end - - context "and the resource was not updated" do - before do - @resource_reporter.resource_up_to_date(@new_resource, :create) - end - - it "has no updated resources" do - @resource_reporter.should have(0).updated_resources - end - end - - context "and the resource was updated" do - before do - @new_resource.content("this is the old content") - @current_resource.content("this is the new hotness") - @resource_reporter.resource_updated(@new_resource, :create) - @resource_reporter.resource_completed(@new_resource) - end - - it "collects the updated resource" do - @resource_reporter.should have(1).updated_resources - end - - it "collects the old state of the resource" do - update_record = @resource_reporter.updated_resources.first - update_record.current_resource.should == @current_resource - end - - it "collects the new state of the resource" do - update_record = @resource_reporter.updated_resources.first - update_record.new_resource.should == @new_resource - end - - context "and a subsequent resource fails before loading current resource" do - before do - @next_new_resource = Chef::Resource::Service.new("apache2") - @exception = Exception.new - @exception.set_backtrace(caller) - @resource_reporter.resource_failed(@next_new_resource, :create, @exception) - @resource_reporter.resource_completed(@next_new_resource) - end - - it "collects the desired state of the failed resource" do - failed_resource_update = @resource_reporter.updated_resources.last - failed_resource_update.new_resource.should == @next_new_resource - end - - it "does not have the current state of the failed resource" do - failed_resource_update = @resource_reporter.updated_resources.last - failed_resource_update.current_resource.should be_nil - end - end - end - - # Some providers, such as RemoteDirectory and some LWRPs use other - # resources for their implementation. These should be hidden from reporting - # since we only care about the top-level resource and not the sub-resources - # used for implementation. - 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 - - it "does not collect data about the nested resource" do - @resource_reporter.should have(1).updated_resources - end - end - - context "and a nested resource runs but is not 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_up_to_date(@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 - @resource_reporter.should have(1).updated_resources - end - end - - context "and the resource failed to converge" do - before do - @exception = Exception.new - @exception.set_backtrace(caller) - @resource_reporter.resource_failed(@new_resource, :create, @exception) - @resource_reporter.resource_completed(@new_resource) - end - - it "collects the resource as an updated resource" do - @resource_reporter.should have(1).updated_resources - end - - it "collects the desired state of the resource" do - update_record = @resource_reporter.updated_resources.first - update_record.new_resource.should == @new_resource - end - - it "collects the current state of the resource" do - update_record = @resource_reporter.updated_resources.first - update_record.current_resource.should == @current_resource - end - end - - end - end - - describe "when generating a report for the server" do - - before do - @rest_client.stub(:create_url).and_return("reports/nodes/spitfire/runs/#{@run_id}"); - @rest_client.stub(:raw_http_request).and_return({"result"=>"ok"}); - @rest_client.stub(:post_rest).and_return({"uri"=>"https://example.com/reports/nodes/spitfire/runs/#{@run_id}"}); - - @resource_reporter.run_started(@run_status) - end - - context "when the new_resource does not have a string for name and identity" do - context "the new_resource name and id are nil" do - before do - @bad_resource = Chef::Resource::File.new("/tmp/nameless_file.txt") - @bad_resource.stub(:name).and_return(nil) - @bad_resource.stub(:identity).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) - @resource_reporter.resource_completed(@bad_resource) - @run_status.stop_clock - @report = @resource_reporter.prepare_run_data - @first_update_report = @report["resources"].first - end - - it "resource_name in prepared_run_data is a string" do - @first_update_report["name"].class.should == String - end - - it "resource_id in prepared_run_data is a string" do - @first_update_report["id"].class.should == String - end - end - - context "the new_resource name and id are hashes" do - before do - @bad_resource = Chef::Resource::File.new("/tmp/filename_as_hash.txt") - @bad_resource.stub(:name).and_return({:foo=>:bar}) - @bad_resource.stub(:identity).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) - @resource_reporter.resource_completed(@bad_resource) - @run_status.stop_clock - @report = @resource_reporter.prepare_run_data - @first_update_report = @report["resources"].first - end - # Ruby 1.8.7 flattens out hash to string using join instead of inspect, resulting in - # irb(main):001:0> {:foo => :bar}.to_s - # => "foobar" - # instead of the expected - # irb(main):001:0> {:foo => :bar}.to_s - # => "{:foo=>:bar}" - # Hence checking for the class instead of the actual value. - it "resource_name in prepared_run_data is a string" do - @first_update_report["name"].class.should == String - end - - it "resource_id in prepared_run_data is a string" do - @first_update_report["id"].class.should == String - end - end - end - - shared_examples_for "a successful client run" do - before do - # TODO: add inputs to generate expected output. - - # expected_data = { - # "action" : "end", - # "resources" : [ - # { - # "type" : "file", - # "id" : "/etc/passwd", - # "name" : "User Defined Resource Block Name", - # "duration" : "1200", - # "result" : "modified", - # "before" : { - # "state" : "exists", - # "group" : "root", - # "owner" : "root", - # "checksum" : "xyz" - # }, - # "after" : { - # "state" : "modified", - # "group" : "root", - # "owner" : "root", - # "checksum" : "abc" - # }, - # "delta" : "" - # }, - # {...} - # ], - # "status" : "success" - # "data" : "" - # } - @resource_reporter.resource_action_start(new_resource, :create) - @resource_reporter.resource_current_state_loaded(new_resource, :create, current_resource) - @resource_reporter.resource_updated(new_resource, :create) - @resource_reporter.resource_completed(new_resource) - @run_status.stop_clock - @report = @resource_reporter.prepare_run_data - @first_update_report = @report["resources"].first - end - - it "includes the run's status" do - @report.should have_key("status") - end - - it "includes a list of updated resources" do - @report.should have_key("resources") - end - - it "includes an updated resource's type" do - @first_update_report.should have_key("type") - end - - it "includes an updated resource's initial state" do - @first_update_report["before"].should == current_resource.state - end - - it "includes an updated resource's final state" do - @first_update_report["after"].should == new_resource.state - end - - it "includes the resource's name" do - @first_update_report["name"].should == new_resource.name - end - - it "includes the resource's id attribute" do - @first_update_report["id"].should == new_resource.identity - end - - it "includes the elapsed time for the resource to converge" do - # TODO: API takes integer number of milliseconds as a string. This - # should be an int. - @first_update_report.should have_key("duration") - @first_update_report["duration"].to_i.should be_within(100).of(0) - end - - it "includes the action executed by the resource" do - # TODO: rename as "action" - @first_update_report["result"].should == "create" - end - - it "includes the cookbook name of the resource" do - @first_update_report.should have_key("cookbook_name") - @first_update_report["cookbook_name"].should == @cookbook_name - end - - it "includes the cookbook version of the resource" do - @first_update_report.should have_key("cookbook_version") - @first_update_report["cookbook_version"].should == "1.2.3" - end - - it "includes the total resource count" do - @report.should have_key("total_res_count") - @report["total_res_count"].should == "1" - end - - it "includes the data hash" do - @report.should have_key("data") - @report["data"].should == {} - end - - it "includes the run_list" do - @report.should have_key("run_list") - @report["run_list"].should == @run_status.node.run_list.to_json - end - - it "includes the end_time" do - @report.should have_key("end_time") - @report["end_time"].should == @run_status.end_time.to_s - end - - end - - context "when the resource is a File" do - let(:new_resource) { @new_resource } - let(:current_resource) { @current_resource } - - it_should_behave_like "a successful client run" - end - - 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.stub(:cookbook_name).and_return(@cookbook_name) - resource.stub(:cookbook_version).and_return(@cookbook_version) - resource - end - - let(:current_resource) do - resource = Chef::Resource::RegistryKey.new('Wubba\Lubba\Dub\Dubs') - resource.values([ { :name => 'rick', :type => :binary, :data => 255.chr * 1 } ]) - resource - end - - it_should_behave_like "a successful client run" - end - - context "for an unsuccessful run" do - - before do - @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 - @exception.stub(:inspect).and_return("Net::HTTPServerException") - @exception.stub(:message).and_return("Object not found") - @exception.stub(:backtrace).and_return(@backtrace) - @resource_reporter.run_list_expand_failed(@node, @exception) - @resource_reporter.run_failed(@exception) - @report = @resource_reporter.prepare_run_data - end - - it "includes the exception type in the event data" do - @report.should have_key("data") - @report["data"]["exception"].should have_key("class") - @report["data"]["exception"]["class"].should == "Net::HTTPServerException" - end - - it "includes the exception message in the event data" do - @report["data"]["exception"].should have_key("message") - @report["data"]["exception"]["message"].should == "Object not found" - end - - it "includes the exception trace in the event data" do - @report["data"]["exception"].should have_key("backtrace") - @report["data"]["exception"]["backtrace"].should == @backtrace.to_json - end - - it "includes the error inspector output in the event data" do - @report["data"]["exception"].should have_key("description") - @report["data"]["exception"]["description"].should include({"title"=>"Error expanding the run_list:", "sections"=>[{"Unexpected Error:" => "ArgumentError: Object not found"}]}) - end - - end - - context "when new_resource does not have a cookbook_name" do - before do - @bad_resource = Chef::Resource::File.new("/tmp/a-file.txt") - @bad_resource.cookbook_name = 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) - @resource_reporter.resource_completed(@bad_resource) - @run_status.stop_clock - @report = @resource_reporter.prepare_run_data - @first_update_report = @report["resources"].first - end - - it "includes an updated resource's initial state" do - @first_update_report["before"].should == @current_resource.state - end - - it "includes an updated resource's final state" do - @first_update_report["after"].should == @new_resource.state - end - - it "includes the resource's name" do - @first_update_report["name"].should == @new_resource.name - end - - it "includes the resource's id attribute" do - @first_update_report["id"].should == @new_resource.identity - end - - it "includes the elapsed time for the resource to converge" do - # TODO: API takes integer number of milliseconds as a string. This - # should be an int. - @first_update_report.should have_key("duration") - @first_update_report["duration"].to_i.should be_within(100).of(0) - end - - it "includes the action executed by the resource" do - # TODO: rename as "action" - @first_update_report["result"].should == "create" - end - - it "does not include a cookbook name for the resource" do - @first_update_report.should_not have_key("cookbook_name") - end - - it "does not include a cookbook version for the resource" do - @first_update_report.should_not have_key("cookbook_version") - end - end - - context "when including a resource that overrides Resource#state" do - before do - @current_state_resource = Chef::Resource::WithState.new("Stateful", @run_context) - @current_state_resource.state = nil - - @new_state_resource = Chef::Resource::WithState.new("Stateful", @run_context) - @new_state_resource.state = "Running" - @resource_reporter.resource_action_start(@new_state_resource, :create) - @resource_reporter.resource_current_state_loaded(@new_state_resource, :create, @current_state_resource) - @resource_reporter.resource_updated(@new_state_resource, :create) - @resource_reporter.resource_completed(@new_state_resource) - @run_status.stop_clock - @report = @resource_reporter.prepare_run_data - @first_update_report = @report["resources"].first - end - - it "sets before to {} instead of nil" do - @first_update_report.should have_key("before") - @first_update_report['before'].should eq({}) - end - - it "sets after to {} instead of 'Running'" do - @first_update_report.should have_key("after") - @first_update_report['after'].should eq({}) - end - end - - end - - describe "when updating resource history on the server" do - before do - @resource_reporter.run_started(@run_status) - @run_status.start_clock - end - - context "when the server does not support storing resource history" do - before do - # 404 getting the run_id - @response = Net::HTTPNotFound.new("a response body", "404", "Not Found") - @error = Net::HTTPServerException.new("404 message", @response) - @rest_client.should_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}). - and_raise(@error) - end - - it "assumes the feature is not enabled" do - @resource_reporter.run_started(@run_status) - @resource_reporter.reporting_enabled?.should be_false - end - - it "does not send a resource report to the server" do - @resource_reporter.run_started(@run_status) - @rest_client.should_not_receive(:post_rest) - @resource_reporter.run_completed(@node) - end - - it "prints an error about the 404" do - Chef::Log.should_receive(:debug).with(/404/) - @resource_reporter.run_started(@run_status) - end - - end - - context "when the server returns a 500 to the client" do - before do - # 500 getting the run_id - @response = Net::HTTPInternalServerError.new("a response body", "500", "Internal Server Error") - @error = Net::HTTPServerException.new("500 message", @response) - @rest_client.should_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}). - and_raise(@error) - end - - it "assumes the feature is not enabled" do - @resource_reporter.run_started(@run_status) - @resource_reporter.reporting_enabled?.should be_false - end - - it "does not send a resource report to the server" do - @resource_reporter.run_started(@run_status) - @rest_client.should_not_receive(:post_rest) - @resource_reporter.run_completed(@node) - end - - it "prints an error about the error" do - Chef::Log.should_receive(:info).with(/500/) - @resource_reporter.run_started(@run_status) - end - end - - context "when the server returns a 500 to the client and enable_reporting_url_fatals is true" do - before do - @enable_reporting_url_fatals = Chef::Config[:enable_reporting_url_fatals] - Chef::Config[:enable_reporting_url_fatals] = true - # 500 getting the run_id - @response = Net::HTTPInternalServerError.new("a response body", "500", "Internal Server Error") - @error = Net::HTTPServerException.new("500 message", @response) - @rest_client.should_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}). - and_raise(@error) - end - - after do - Chef::Config[:enable_reporting_url_fatals] = @enable_reporting_url_fatals - end - - it "fails the run and prints an message about the error" do - Chef::Log.should_receive(:error).with(/500/) - lambda { - @resource_reporter.run_started(@run_status) - }.should raise_error(Net::HTTPServerException) - end - end - - context "after creating the run history document" do - before do - response = {"uri"=>"https://example.com/reports/nodes/spitfire/runs/@run_id"} - @rest_client.should_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}). - and_return(response) - @resource_reporter.run_started(@run_status) - end - - it "creates a run document on the server at the start of the run" do - @resource_reporter.run_id.should == @run_id - end - - it "updates the run document with resource updates at the end of the run" do - # update some resources... - @resource_reporter.resource_action_start(@new_resource, :create) - @resource_reporter.resource_current_state_loaded(@new_resource, :create, @current_resource) - @resource_reporter.resource_updated(@new_resource, :create) - - @resource_reporter.stub(:end_time).and_return(@end_time) - @expected_data = @resource_reporter.prepare_run_data - - post_url = "https://chef_server/example_url" - response = {"result"=>"ok"} - - @rest_client.should_receive(:create_url). - with("reports/nodes/spitfire/runs/#{@run_id}"). - ordered. - and_return(post_url) - @rest_client.should_receive(:raw_http_request).ordered do |method, url, headers, data| - method.should eq(:POST) - url.should eq(post_url) - headers.should 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 - data.should eq(@expected_data.to_json) - response - end - - @resource_reporter.run_completed(@node) - end - end - - context "when data report post is enabled and the server response fails" 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 - @rest_client.stub(:create_url) - end - - after do - Chef::Config[:enable_reporting_url_fatals] = @enable_reporting_url_fatals - end - - it "should log 4xx errors" do - response = Net::HTTPClientError.new("forbidden", "403", "Forbidden") - error = Net::HTTPServerException.new("403 message", response) - @rest_client.stub(:raw_http_request).and_raise(error) - Chef::Log.should_receive(:error).with(/403/) - - @resource_reporter.post_reporting_data - end - - it "should log error 5xx errors" do - response = Net::HTTPServerError.new("internal error", "500", "Internal Server Error") - error = Net::HTTPFatalError.new("500 message", response) - @rest_client.stub(:raw_http_request).and_raise(error) - Chef::Log.should_receive(:error).with(/500/) - - @resource_reporter.post_reporting_data - end - - it "should log if a socket error happens" do - @rest_client.stub(:raw_http_request).and_raise(SocketError.new("test socket error")) - Chef::Log.should_receive(:error).with(/test socket error/) - - @resource_reporter.post_reporting_data - - end - - it "should raise if an unkwown error happens" do - @rest_client.stub(:raw_http_request).and_raise(Exception.new) - - lambda { - @resource_reporter.post_reporting_data - }.should raise_error(Exception) - end - end - end -end diff --git a/spec/unit/resource_spec.rb b/spec/unit/resource_spec.rb deleted file mode 100644 index e85633eaab..0000000000 --- a/spec/unit/resource_spec.rb +++ /dev/null @@ -1,975 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: Christopher Walters (<cw@opscode.com>) -# Author:: Tim Hinderliter (<tim@opscode.com>) -# Author:: Seth Chisamore (<schisamo@opscode.com>) -# Copyright:: Copyright (c) 2008-2011 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' - -class ResourceTestHarness < Chef::Resource - provider_base Chef::Provider::Package -end - -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) - end - - describe "when inherited" do - - it "adds an entry to a list of subclasses" do - subclass = Class.new(Chef::Resource) - Chef::Resource.resource_classes.should include(subclass) - end - - it "keeps track of subclasses of subclasses" do - subclass = Class.new(Chef::Resource) - subclass_of_subclass = Class.new(subclass) - Chef::Resource.resource_classes.should include(subclass_of_subclass) - end - - end - - describe "when declaring the identity attribute" do - it "has no identity attribute by default" do - Chef::Resource.identity_attr.should be_nil - end - - it "sets an identity attribute" do - resource_class = Class.new(Chef::Resource) - resource_class.identity_attr(:path) - resource_class.identity_attr.should == :path - end - - it "inherits an identity attribute from a superclass" do - resource_class = Class.new(Chef::Resource) - resource_subclass = Class.new(resource_class) - resource_class.identity_attr(:package_name) - resource_subclass.identity_attr.should == :package_name - end - - it "overrides the identity attribute from a superclass when the identity attr is set" do - resource_class = Class.new(Chef::Resource) - resource_subclass = Class.new(resource_class) - resource_class.identity_attr(:package_name) - resource_subclass.identity_attr(:something_else) - resource_subclass.identity_attr.should == :something_else - end - end - - describe "when no identity attribute has been declared" do - before do - @resource_sans_id = Chef::Resource.new("my-name") - end - - # 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 - @resource_sans_id.identity.should == "my-name" - end - end - - describe "when an identity attribute has been declared" do - before do - @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 - - it "gives the value of its identity attribute" do - @file_resource.identity.should == "/tmp/foo.txt" - end - end - - describe "when declaring state attributes" do - it "has no state_attrs by default" do - Chef::Resource.state_attrs.should be_empty - end - - it "sets a list of state attributes" do - resource_class = Class.new(Chef::Resource) - resource_class.state_attrs(:checksum, :owner, :group, :mode) - resource_class.state_attrs.should =~ [:checksum, :owner, :group, :mode] - end - - it "inherits state attributes from the superclass" do - resource_class = Class.new(Chef::Resource) - resource_subclass = Class.new(resource_class) - resource_class.state_attrs(:checksum, :owner, :group, :mode) - resource_subclass.state_attrs.should =~ [:checksum, :owner, :group, :mode] - end - - it "combines inherited state attributes with non-inherited state attributes" do - resource_class = Class.new(Chef::Resource) - resource_subclass = Class.new(resource_class) - resource_class.state_attrs(:checksum, :owner) - resource_subclass.state_attrs(:group, :mode) - resource_subclass.state_attrs.should =~ [:checksum, :owner, :group, :mode] - end - - end - - describe "when a set of state attributes has been declared" do - before do - @file_resource_class = Class.new(Chef::Resource) do - - state_attrs :checksum, :owner, :group, :mode - - attr_accessor :checksum - attr_accessor :owner - attr_accessor :group - 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 - - it "describes its state" do - resource_state = @file_resource.state - resource_state.keys.should =~ [:checksum, :owner, :group, :mode] - resource_state[:checksum].should == "abc123" - resource_state[:owner].should == "root" - resource_state[:group].should == "wheel" - resource_state[:mode].should == "0644" - end - end - - describe "load_prior_resource" do - 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 - end - - it "should load the attributes of a prior resource" do - @resource.load_prior_resource - @resource.supports.should == { :funky => true } - end - - it "should not inherit the action from the prior resource" do - @resource.load_prior_resource - @resource.action.should_not == @prior_resource.action - end - end - - describe "name" do - it "should have a name" do - @resource.name.should eql("funk") - end - - it "should let you set a new name" do - @resource.name "monkey" - @resource.name.should eql("monkey") - end - - it "should not be valid without a name" do - lambda { @resource.name false }.should raise_error(ArgumentError) - end - - it "should always have a string for name" do - lambda { @resource.name Hash.new }.should raise_error(ArgumentError) - end - end - - describe "noop" do - it "should accept true or false for noop" do - lambda { @resource.noop true }.should_not raise_error - lambda { @resource.noop false }.should_not raise_error - lambda { @resource.noop "eat it" }.should 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") - @resource.delayed_notifications.detect{|e| e.resource.name == "coffee" && e.action == :reload}.should_not 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 - @resource.immediate_notifications.detect{|e| e.resource.name == "coffee" && e.action == :reload}.should_not 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") - lambda { - @resource.notifies :reload, @run_context.resource_collection.find(:zen_master => "coffee"), :someday - }.should 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") - @resource.delayed_notifications.detect{|e| e.resource.name == "coffee" && e.action == :reload}.should_not be_nil - - @run_context.resource_collection << Chef::Resource::ZenMaster.new("beans") - @resource.notifies :reload, @run_context.resource_collection.find(:zen_master => "beans") - @resource.delayed_notifications.detect{|e| e.resource.name == "beans" && e.action == :reload}.should_not 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) - @resource.delayed_notifications.should 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) - @resource.immediate_notifications.should 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) - @resource.delayed_notifications.should include(expected_notification) - 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 - zr.delayed_notifications.detect{|e| e.resource.name == "funk" && e.action == :reload}.should_not 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 - zr.delayed_notifications.detect{|e| e.resource.name == @resource.name && e.action == :reload}.should_not be_nil - - @run_context.resource_collection << Chef::Resource::ZenMaster.new("bean") - zrb = @run_context.resource_collection.find(:zen_master => "bean") - zrb.subscribes :reload, zr - zr.delayed_notifications.detect{|e| e.resource.name == @resource.name && e.action == :reload}.should_not 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 - zr.immediate_notifications.detect{|e| e.resource.name == @resource.name && e.action == :reload}.should_not 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'" - @resource.defined_at.should == "/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'" - @resource.defined_at.should == "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" - @resource.defined_at.should == "animals::wombats line 80" - end - - it "should recognize dynamically defined resources" do - @resource.defined_at.should == "dynamically defined" - end - end - - describe "to_s" do - it "should become a string like resource_name[name]" do - zm = Chef::Resource::ZenMaster.new("coffee") - zm.to_s.should eql("zen_master[coffee]") - end - end - - describe "is" do - it "should return the arguments passed with 'is'" do - zm = Chef::Resource::ZenMaster.new("coffee") - zm.is("one", "two", "three").should == %w|one two three| - end - - it "should allow arguments preceeded by is to methods" do - @resource.noop(@resource.is(true)) - @resource.noop.should eql(true) - end - end - - describe "to_json" do - it "should serialize to json" do - json = @resource.to_json - json.should =~ /json_class/ - json.should =~ /instance_vars/ - end - end - - describe "to_hash" do - it "should convert to a hash" do - hash = @resource.to_hash - expected_keys = [ :allowed_actions, :params, :provider, :updated, - :updated_by_last_action, :before, :supports, - :noop, :ignore_failure, :name, :source_line, - :action, :retries, :retry_delay, :elapsed_time, - :guard_interpreter, :sensitive ] - (hash.keys - expected_keys).should == [] - (expected_keys - hash.keys).should == [] - hash[:name].should eql("funk") - end - end - - describe "self.json_create" do - it "should deserialize itself from json" do - json = @resource.to_json - serialized_node = Chef::JSONCompat.from_json(json) - serialized_node.should be_a_kind_of(Chef::Resource) - serialized_node.name.should 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) - @resource.supports.should eql(support_hash) - end - - it "should return the current value of supports" do - @resource.supports.should == {} - end - end - - describe "ignore_failure" do - it "should default to throwing an error if a provider fails for a resource" do - @resource.ignore_failure.should == false - end - - it "should allow you to set whether a provider should throw exceptions with ignore_failure" do - @resource.ignore_failure(true) - @resource.ignore_failure.should == true - end - - it "should allow you to epic_fail" do - @resource.epic_fail(true) - @resource.epic_fail.should == true - end - end - - describe "retries" do - it "should default to not retrying if a provider fails for a resource" do - @resource.retries.should == 0 - end - - it "should allow you to set how many retries a provider should attempt after a failure" do - @resource.retries(2) - @resource.retries.should == 2 - end - - it "should default to a retry delay of 2 seconds" do - @resource.retry_delay.should == 2 - end - - it "should allow you to set the retry delay" do - @resource.retry_delay(10) - @resource.retry_delay.should == 10 - end - end - - describe "setting the base provider class for the resource" do - - it "defaults to Chef::Provider for the base class" do - Chef::Resource.provider_base.should == Chef::Provider - end - - it "allows the base provider to be overriden by a " do - ResourceTestHarness.provider_base.should == Chef::Provider::Package - end - - end - - it "runs an action by finding its provider, loading the current resource and then running the action" do - pending - end - - describe "when updated by a provider" do - before do - @resource.updated_by_last_action(true) - end - - it "records that it was updated" do - @resource.should be_updated - end - - it "records that the last action updated the resource" do - @resource.should be_updated_by_last_action - end - - describe "and then run again without being updated" do - before do - @resource.updated_by_last_action(false) - end - - it "reports that it is updated" do - @resource.should be_updated - end - - it "reports that it was not updated by the last action" do - @resource.should_not be_updated_by_last_action - end - - end - - end - - describe "when invoking its action" do - 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' - 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) - end - - it "runs runs an only_if when one is given" do - snitch_variable = nil - @resource.only_if { snitch_variable = true } - @resource.only_if.first.positivity.should == :only_if - #Chef::Mixin::Command.should_receive(:only_if).with(true, {}).and_return(false) - @resource.run_action(:purr) - snitch_variable.should be_true - 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) - snitch_var1.should == 1 - snitch_var2.should == 2 - end - - it "accepts command options for only_if conditionals" do - Chef::Resource::Conditional.any_instance.should_receive(:evaluate_command).at_least(1).times - @resource.only_if("true", :cwd => '/tmp') - @resource.only_if.first.command_opts.should == {:cwd => '/tmp'} - @resource.run_action(:purr) - end - - it "runs not_if as a command when it is a string" do - Chef::Resource::Conditional.any_instance.should_receive(:evaluate_command).at_least(1).times - @resource.not_if "pwd" - @resource.run_action(:purr) - end - - it "runs not_if as a block when it is a ruby block" do - Chef::Resource::Conditional.any_instance.should_receive(:evaluate_block).at_least(1).times - @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) - end - - it "accepts command options for not_if conditionals" do - @resource.not_if("pwd" , :cwd => '/tmp') - @resource.not_if.first.command_opts.should == {: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) - snitch_var1.should be_nil - snitch_var2.should be_false - end - - it "reports 0 elapsed time if actual elapsed time is < 0" do - expected = Time.now - Time.stub(:now).and_return(expected, expected - 1) - @resource.run_action(:purr) - @resource.elapsed_time.should == 0 - end - - describe "guard_interpreter attribute" do - let(:resource) { @resource } - - it "should be set to :default by default" do - resource.guard_interpreter.should == :default - end - - it "if set to :default should return :default when read" do - resource.guard_interpreter(:default) - resource.guard_interpreter.should == :default - 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) - end - - it "should not raise an exception when setting the guard interpreter attribute to a Symbol" do - Chef::GuardInterpreter::ResourceGuardInterpreter.stub(:new).and_return(nil) - expect { resource.guard_interpreter(:command_dot_com) }.not_to raise_error - end - end - end - - describe "should_skip?" do - before do - @resource = Chef::Resource::Cat.new("sugar", @run_context) - end - - it "should return false by default" do - @resource.should_skip?(:purr).should be_false - end - - it "should return false when only_if is met" do - @resource.only_if { true } - @resource.should_skip?(:purr).should be_false - end - - it "should return true when only_if is not met" do - @resource.only_if { false } - @resource.should_skip?(:purr).should be_true - end - - it "should return true when not_if is met" do - @resource.not_if { true } - @resource.should_skip?(:purr).should be_true - end - - it "should return false when not_if is not met" do - @resource.not_if { false } - @resource.should_skip?(:purr).should be_false - 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 } - @resource.should_skip?(:purr).should be_true - 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 } - @resource.should_skip?(:purr).should be_true - 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 } - @resource.should_skip?(:purr).should be_true - end - - it "should return true when action is :nothing" do - @resource.should_skip?(:nothing).should be_true - end - - it "should return true when action is :nothing ignoring only_if/not_if conditionals" do - @resource.only_if { true } - @resource.not_if { false } - @resource.should_skip?(:nothing).should be_true - 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) - @run_context.stub(:events).and_return(fdoc) - fdoc.should_receive(:puts).with(" (skipped due to action :nothing)", anything()) - @resource.should_skip?(:nothing) - end - - end - - describe "when resource action is :nothing" do - 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' - 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) - snitch_var1.should == 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) - Chef::Platform.set( - :resource => :cat, - :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 - - @run_context.resource_collection << @resource1 - @run_context.resource_collection << @resource2 - @runner.converge - - snitch_var1.should == 1 - snitch_var2.should == 2 - end - end - - describe "building the platform map" do - - it 'adds mappings for a single platform' do - klz = Class.new(Chef::Resource) - Chef::Resource.platform_map.should_receive(:set).with( - :platform => :autobots, :short_name => :dinobot, :resource => klz - ) - klz.provides :dinobot, :on_platforms => ['autobots'] - end - - it 'adds mappings for multiple platforms' do - klz = Class.new(Chef::Resource) - Chef::Resource.platform_map.should_receive(:set).twice - klz.provides :energy, :on_platforms => ['autobots','decepticons'] - end - - it 'adds mappings for all platforms' do - klz = Class.new(Chef::Resource) - Chef::Resource.platform_map.should_receive(:set).with( - :short_name => :tape_deck, :resource => klz - ) - klz.provides :tape_deck - end - - end - - describe "lookups from the platform map" do - - before(:each) do - @node = Chef::Node.new - @node.name("bumblebee") - @node.automatic[:platform] = "autobots" - @node.automatic[:platform_version] = "6.1" - Object.const_set('Soundwave', Class.new(Chef::Resource)) - Object.const_set('Grimlock', Class.new(Chef::Resource){ provides :dinobot, :on_platforms => ['autobots'] }) - end - - after(:each) do - Object.send(:remove_const, :Soundwave) - Object.send(:remove_const, :Grimlock) - end - - describe "resource_for_platform" do - it 'return a resource by short_name and platform' do - Chef::Resource.resource_for_platform(:dinobot,'autobots','6.1').should eql(Grimlock) - end - it "returns a resource by short_name if nothing else matches" do - Chef::Resource.resource_for_node(:soundwave, @node).should eql(Soundwave) - end - end - - describe "resource_for_node" do - it "returns a resource by short_name and node" do - Chef::Resource.resource_for_node(:dinobot, @node).should eql(Grimlock) - end - it "returns a resource by short_name if nothing else matches" do - Chef::Resource.resource_for_node(:soundwave, @node).should eql(Soundwave) - end - end - - end - - describe "when creating notifications" do - - describe "with a string resource spec" do - - it "creates a delayed notification when timing is not specified" do - @resource.notifies(:run, "execute[foo]") - @run_context.delayed_notification_collection.should have(1).notifications - end - - it "creates a delayed notification when :delayed is not specified" do - @resource.notifies(:run, "execute[foo]", :delayed) - @run_context.delayed_notification_collection.should have(1).notifications - end - - it "creates an immediate notification when :immediate is specified" do - @resource.notifies(:run, "execute[foo]", :immediate) - @run_context.immediate_notification_collection.should have(1).notifications - end - - it "creates an immediate notification when :immediately is specified" do - @resource.notifies(:run, "execute[foo]", :immediately) - @run_context.immediate_notification_collection.should have(1).notifications - end - - describe "with a syntax error in the resource spec" do - - it "raises an exception immmediately" do - lambda do - @resource.notifies(:run, "typo[missing-closing-bracket") - end.should 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 - - it "creates a delayed notification when timing is not specified" do - @resource.notifies(:run, @notified_resource) - @run_context.delayed_notification_collection.should have(1).notifications - end - - it "creates a delayed notification when :delayed is not specified" do - @resource.notifies(:run, @notified_resource, :delayed) - @run_context.delayed_notification_collection.should have(1).notifications - end - - it "creates an immediate notification when :immediate is specified" do - @resource.notifies(:run, @notified_resource, :immediate) - @run_context.immediate_notification_collection.should have(1).notifications - end - - it "creates an immediate notification when :immediately is specified" do - @resource.notifies(:run, @notified_resource, :immediately) - @run_context.immediate_notification_collection.should have(1).notifications - 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 - - def compiled_resource_data(resource, action, err) - error_inspector = Chef::Formatters::ErrorInspectors::ResourceFailureInspector.new(resource, action, err) - description = Chef::Formatters::ErrorDescription.new("test") - error_inspector.add_explanation(description) - Chef::Log.info("descrtiption: #{description.inspect},error_inspector: #{error_inspector}") - description.sections[1]["Compiled Resource:"] - end - - it "set to false by default" do - @resource.sensitive.should be_false - end - - it "when set to false should show compiled resource for failed resource" do - expect { @resource_file.run_action(@action) }.to raise_error { |err| - compiled_resource_data(@resource_file, @action, err).should 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| - compiled_resource_data(@resource_file, @action, err).should eql("suppressed sensitive resource output") - } - end - - end -end - -describe Chef::Resource::Notification do - before do - @notification = Chef::Resource::Notification.new(:service_apache, :restart, :template_httpd_conf) - end - - it "has a resource to be notified" do - @notification.resource.should == :service_apache - end - - it "has an action to take on the service" do - @notification.action.should == :restart - end - - it "has a notifying resource" do - @notification.notifying_resource.should == :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) - @notification.duplicates?(other).should be_true - end - - it "is not a duplicate of another notification if the actions differ" do - other = Chef::Resource::Notification.new(:service_apache, :enable, :install_apache) - @notification.duplicates?(other).should be_false - 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) - @notification.duplicates?(other).should be_false - end - - it "raises an ArgumentError if you try to check a non-ducktype object for duplication" do - lambda {@notification.duplicates?(:not_a_notification)}.should 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 - @long_cat = Chef::Resource::Cat.new("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) - @notification.resource.should == @keyboard_cat - end - - it "resolves a lazy reference to a resource" do - @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) - @notification.resource.should == @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"} - @long_cat = Chef::Resource::Cat.new("long_cat") - @resource_collection = Chef::ResourceCollection.new - @resource_collection << @long_cat - @notification.resolve_resource_reference(@resource_collection) - @notification.notifying_resource.should == @long_cat - end - - it "resolves lazy references to both its resource and its notifying resource" do - @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"} - @long_cat = Chef::Resource::Cat.new("long_cat") - @resource_collection << @long_cat - @notification.resolve_resource_reference(@resource_collection) - @notification.resource.should == @keyboard_cat - @notification.notifying_resource.should == @long_cat - end - - it "raises a RuntimeError if you try to reference multiple resources" do - @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 - lambda {@notification.resolve_resource_reference(@resource_collection)}.should 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"]} - @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 - lambda {@notification.resolve_resource_reference(@resource_collection)}.should 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"} - @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 - lambda {@notification.resolve_resource_reference(@resource_collection)}.should 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"} - @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 - lambda {@notification.resolve_resource_reference(@resource_collection)}.should 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" - @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 - lambda {@notification.resolve_resource_reference(@resource_collection)}.should 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" - @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 - lambda {@notification.resolve_resource_reference(@resource_collection)}.should raise_error(ArgumentError) - end - - # Create test to resolve lazy references to both notifying resource and dest. resource - # Create tests to check proper error raising - -end diff --git a/spec/unit/rest/auth_credentials_spec.rb b/spec/unit/rest/auth_credentials_spec.rb deleted file mode 100644 index 477da0faec..0000000000 --- a/spec/unit/rest/auth_credentials_spec.rb +++ /dev/null @@ -1,328 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: Christopher Brown (<cb@opscode.com>) -# Author:: Daniel DeLeo (<dan@opscode.com>) -# Copyright:: Copyright (c) 2008 Opscode, Inc. -# 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. -# - -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 - - -describe Chef::REST::AuthCredentials do - before do - @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 - - it "has a client name" do - @auth_credentials.client_name.should == "client-name" - end - - it "loads the private key when initialized with the path to the key" do - @auth_credentials.key.should respond_to(:private_encrypt) - @auth_credentials.key.to_s.should == KEY_DOT_PEM - 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' - lambda {Chef::REST::AuthCredentials.new("client-name", @key_file_fixture)}.should_not 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"} - end - - it "generates signature headers for the request" do - Time.stub(:now).and_return(@request_time) - actual = @auth_credentials.signature_headers(@request_params) - actual["HOST"].should == "localhost" - actual["X-OPS-AUTHORIZATION-1"].should == "kBssX1ENEwKtNYFrHElN9vYGWS7OeowepN9EsYc9csWfh8oUovryPKDxytQ/" - actual["X-OPS-AUTHORIZATION-2"].should == "Wc2/nSSyxdWJjjfHzrE+YrqNQTaArOA7JkAf5p75eTUonCWcvNPjFrZVgKGS" - actual["X-OPS-AUTHORIZATION-3"].should == "yhzHJQh+lcVA9wwARg5Hu9q+ddS8xBOdm3Vp5atl5NGHiP0loiigMYvAvzPO" - actual["X-OPS-AUTHORIZATION-4"].should == "r9853eIxwYMhn5hLGhAGFQznJbE8+7F/lLU5Zmk2t2MlPY8q3o1Q61YD8QiJ" - actual["X-OPS-AUTHORIZATION-5"].should == "M8lIt53ckMyUmSU0DDURoiXLVkE9mag/6Yq2tPNzWq2AdFvBqku9h2w+DY5k" - actual["X-OPS-AUTHORIZATION-6"].should == "qA5Rnzw5rPpp3nrWA9jKkPw4Wq3+4ufO2Xs6w7GCjA==" - actual["X-OPS-CONTENT-HASH"].should == "1tuzs5XKztM1ANrkGNPah6rW9GY=" - actual["X-OPS-SIGN"].should =~ %r{(version=1\.0)|(algorithm=sha1;version=1.0;)} - actual["X-OPS-TIMESTAMP"].should == "2010-04-10T17:34:20Z" - actual["X-OPS-USERID"].should == "client-name" - - end - - describe "when configured for version 1.1 of the authn protocol" do - before do - Chef::Config[:authentication_protocol_version] = "1.1" - end - - after do - Chef::Config[:authentication_protocol_version] = "1.0" - end - - it "generates the correct signature for version 1.1" do - Time.stub(:now).and_return(@request_time) - actual = @auth_credentials.signature_headers(@request_params) - actual["HOST"].should == "localhost" - actual["X-OPS-CONTENT-HASH"].should == "1tuzs5XKztM1ANrkGNPah6rW9GY=" - actual["X-OPS-SIGN"].should == "algorithm=sha1;version=1.1;" - actual["X-OPS-TIMESTAMP"].should == "2010-04-10T17:34:20Z" - actual["X-OPS-USERID"].should == "client-name" - - # mixlib-authN will test the actual signature stuff for each version of - # the protocol so we won't test it again here. - end - end - end -end - -describe Chef::REST::RESTRequest do - 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') - @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", - "Accept-Encoding" => Chef::REST::RESTRequest::ENCODING_GZIP_DEFLATE, - "Host" => "chef.example.com:4000" } - @request = Chef::REST::RESTRequest.new(:POST, @url, @req_body, @headers) - end - - it "stores the url it was created with" do - @request.url.should == @url - end - - it "stores the HTTP method" do - @request.method.should == :POST - end - - it "adds the chef version header" do - @request.headers.should == @headers.merge("X-Chef-Version" => ::Chef::VERSION) - end - - describe "configuring the HTTP request" do - it "configures GET requests" do - @req_body = nil - rest_req = new_request(:GET) - rest_req.http_request.should be_a_kind_of(Net::HTTP::Get) - rest_req.http_request.path.should == "/?q=chef_is_awesome" - rest_req.http_request.body.should be_nil - end - - it "configures POST requests, including the body" do - @request.http_request.should be_a_kind_of(Net::HTTP::Post) - @request.http_request.path.should == "/?q=chef_is_awesome" - @request.http_request.body.should == @req_body - end - - it "configures PUT requests, including the body" do - rest_req = new_request(:PUT) - rest_req.http_request.should be_a_kind_of(Net::HTTP::Put) - rest_req.http_request.path.should == "/?q=chef_is_awesome" - rest_req.http_request.body.should == @req_body - end - - it "configures DELETE requests" do - rest_req = new_request(:DELETE) - rest_req.http_request.should be_a_kind_of(Net::HTTP::Delete) - rest_req.http_request.path.should == "/?q=chef_is_awesome" - rest_req.http_request.body.should be_nil - end - - it "configures HTTP basic auth" do - @url = URI.parse("http://homie:theclown@chef.example.com:4000/?q=chef_is_awesome") - rest_req = new_request(:GET) - rest_req.http_request.to_hash["authorization"].should == ["Basic aG9taWU6dGhlY2xvd24="] - end - end - - describe "configuring the HTTP client" do - it "configures the HTTP client for the host and port" do - http_client = new_request.http_client - http_client.address.should == "chef.example.com" - http_client.port.should == 4000 - end - - it "configures the HTTP client with the read timeout set in the config file" do - Chef::Config[:rest_timeout] = 9001 - new_request.http_client.read_timeout.should == 9001 - end - - describe "for proxy" do - before do - Chef::Config[:http_proxy] = "http://proxy.example.com:3128" - Chef::Config[:https_proxy] = "http://sproxy.example.com:3129" - Chef::Config[:http_proxy_user] = nil - Chef::Config[:http_proxy_pass] = nil - Chef::Config[:https_proxy_user] = nil - Chef::Config[:https_proxy_pass] = nil - Chef::Config[:no_proxy] = nil - end - - after do - Chef::Config[:http_proxy] = nil - Chef::Config[:https_proxy] = nil - Chef::Config[:http_proxy_user] = nil - Chef::Config[:http_proxy_pass] = nil - Chef::Config[:https_proxy_user] = nil - Chef::Config[:https_proxy_pass] = nil - Chef::Config[:no_proxy] = nil - end - - describe "with :no_proxy nil" do - it "configures the proxy address and port when using http scheme" do - http_client = new_request.http_client - http_client.proxy?.should == true - http_client.proxy_address.should == "proxy.example.com" - http_client.proxy_port.should == 3128 - http_client.proxy_user.should be_nil - http_client.proxy_pass.should be_nil - end - - it "configures the proxy address and port when using https scheme" do - @url.scheme = "https" - http_client = new_request.http_client - http_client.proxy?.should == true - http_client.proxy_address.should == "sproxy.example.com" - http_client.proxy_port.should == 3129 - http_client.proxy_user.should be_nil - http_client.proxy_pass.should be_nil - end - end - - describe "with :no_proxy set" do - before do - Chef::Config[:no_proxy] = "10.*,*.example.com" - end - - it "does not configure the proxy address and port when using http scheme" do - http_client = new_request.http_client - http_client.proxy?.should == false - http_client.proxy_address.should be_nil - http_client.proxy_port.should be_nil - http_client.proxy_user.should be_nil - http_client.proxy_pass.should be_nil - end - - it "does not configure the proxy address and port when using https scheme" do - @url.scheme = "https" - http_client = new_request.http_client - http_client.proxy?.should == false - http_client.proxy_address.should be_nil - http_client.proxy_port.should be_nil - http_client.proxy_user.should be_nil - http_client.proxy_pass.should be_nil - end - end - - describe "with :http_proxy_user and :http_proxy_pass set" do - before do - Chef::Config[:http_proxy_user] = "homie" - Chef::Config[:http_proxy_pass] = "theclown" - end - - after do - Chef::Config[:http_proxy_user] = nil - Chef::Config[:http_proxy_pass] = nil - end - - it "configures the proxy user and pass when using http scheme" do - http_client = new_request.http_client - http_client.proxy?.should == true - http_client.proxy_user.should == "homie" - http_client.proxy_pass.should == "theclown" - end - - it "does not configure the proxy user and pass when using https scheme" do - @url.scheme = "https" - http_client = new_request.http_client - http_client.proxy?.should == true - http_client.proxy_user.should be_nil - http_client.proxy_pass.should be_nil - end - end - - describe "with :https_proxy_user and :https_proxy_pass set" do - before do - Chef::Config[:https_proxy_user] = "homie" - Chef::Config[:https_proxy_pass] = "theclown" - end - - after do - Chef::Config[:https_proxy_user] = nil - Chef::Config[:https_proxy_pass] = nil - end - - it "does not configure the proxy user and pass when using http scheme" do - http_client = new_request.http_client - http_client.proxy?.should == true - http_client.proxy_user.should be_nil - http_client.proxy_pass.should be_nil - end - - it "configures the proxy user and pass when using https scheme" do - @url.scheme = "https" - http_client = new_request.http_client - http_client.proxy?.should == true - http_client.proxy_user.should == "homie" - http_client.proxy_pass.should == "theclown" - end - end - end - end - -end diff --git a/spec/unit/rest_spec.rb b/spec/unit/rest_spec.rb deleted file mode 100644 index 424fd12ee9..0000000000 --- a/spec/unit/rest_spec.rb +++ /dev/null @@ -1,744 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: Christopher Brown (<cb@opscode.com>) -# Author:: Daniel DeLeo (<dan@opscode.com>) -# Copyright:: Copyright (c) 2008 Opscode, Inc. -# 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. -# - -require 'spec_helper' -require 'uri' -require 'net/https' -require 'stringio' - -SIGNING_KEY_DOT_PEM="-----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-----" - -describe Chef::REST do - let(:base_url) { "http://chef.example.com:4000" } - - let(:monkey_uri) { URI.parse("http://chef.example.com:4000/monkey") } - - let(:log_stringio) { StringIO.new } - - let(:request_id) {"1234"} - - let(:rest) do - Chef::REST::CookieJar.stub(:instance).and_return({}) - Chef::RequestID.instance.stub(:request_id).and_return(request_id) - rest = Chef::REST.new(base_url, nil, nil) - Chef::REST::CookieJar.instance.clear - 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}} - - before(:each) do - Chef::Log.init(log_stringio) - end - - it "should have content length validation middleware after compressor middleware" do - middlewares = rest.instance_variable_get(:@middlewares) - content_length = middlewares.find_index { |e| e.is_a? Chef::HTTP::ValidateContentLength } - decompressor = middlewares.find_index { |e| e.is_a? Chef::HTTP::Decompressor } - - content_length.should_not be_nil - decompressor.should_not be_nil - (decompressor < content_length).should be_true - end - - it "should allow the options hash to be frozen" do - options = {}.freeze - # should not raise any exception - Chef::REST.new(base_url, nil, nil, options) - end - - describe "calling an HTTP verb on a path or absolute URL" do - it "adds a relative URL to the base url it was initialized with" do - expect(rest.create_url("foo/bar/baz")).to eq(URI.parse(base_url + "/foo/bar/baz")) - end - - it "replaces the base URL when given an absolute URL" do - expect(rest.create_url("http://chef-rulez.example.com:9000")).to eq(URI.parse("http://chef-rulez.example.com:9000")) - end - - it "makes a :GET request with the composed url object" do - rest.should_receive(:send_http_request). - with(:GET, monkey_uri, standard_read_headers, false). - and_return([1,2,3]) - rest.should_receive(:apply_response_middleware).with(1,2,3).and_return([1,2,3]) - rest.should_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 - rest.should_receive(:streaming_request).with('monkey', {}) - rest.get_rest("monkey", true) - end - - it "makes a :DELETE request with the composed url object" do - rest.should_receive(:send_http_request). - with(:DELETE, monkey_uri, standard_read_headers, false). - and_return([1,2,3]) - rest.should_receive(:apply_response_middleware).with(1,2,3).and_return([1,2,3]) - rest.should_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 - rest.should_receive(:send_http_request). - with(:POST, monkey_uri, standard_write_headers, "\"data\""). - and_return([1,2,3]) - rest.should_receive(:apply_response_middleware).with(1,2,3).and_return([1,2,3]) - rest.should_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 - rest.should_receive(:send_http_request). - with(:PUT, monkey_uri, standard_write_headers, "\"data\""). - and_return([1,2,3]) - rest.should_receive(:apply_response_middleware).with(1,2,3).and_return([1,2,3]) - rest.should_receive('success_response?'.to_sym).with(1).and_return(true) - rest.put_rest("monkey", "data") - end - end - - describe "legacy API" do - let(:rest) do - Chef::REST.new(base_url) - end - - before(:each) do - Chef::Config[:node_name] = "webmonkey.example.com" - Chef::Config[:client_key] = CHEF_SPEC_DATA + "/ssl/private_key.pem" - end - - 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 - data = "\"secure data\"" - - auth_headers = standard_write_headers.merge({"auth_done"=>"yep"}) - - rest.authenticator.should_receive(:handle_request). - with(:POST, monkey_uri, standard_write_headers, data). - and_return([:POST, monkey_uri, auth_headers, data]) - rest.should_receive(:send_http_request). - with(:POST, monkey_uri, auth_headers, data). - and_return([1,2,3]) - rest.should_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 - data = "\"secure data\"" - method, uri, auth_headers, d = rest.authenticator.handle_request(:POST, monkey_uri, standard_write_headers, data) - - rest.should_receive(:send_http_request). - with(:POST, monkey_uri, auth_headers, data). - and_return([1,2,3]) - rest.should_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") } - - let(:rest) do - Chef::REST.new(base_url) - end - - before do - Chef::Config[:node_name] = "webmonkey.example.com" - Chef::Config[:client_key] = CHEF_SPEC_DATA + "/ssl/private_key.pem" - end - - it "configures itself to use the node_name and client_key in the config by default" do - expect(rest.client_name).to eq("webmonkey.example.com") - expect(rest.signing_key_filename).to eq(CHEF_SPEC_DATA + "/ssl/private_key.pem") - end - - it "provides access to the raw key data" do - expect(rest.signing_key).to eq(SIGNING_KEY_DOT_PEM) - end - - it "does not error out when initialized without credentials" do - rest = Chef::REST.new(base_url, nil, nil) #should_not raise_error hides the bt from you, so screw it. - expect(rest.client_name).to be_nil - expect(rest.signing_key).to be_nil - end - - it "indicates that requests should not be signed when it has no credentials" do - rest = Chef::REST.new(base_url, nil, nil) - expect(rest.sign_requests?).to be_false - 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) - 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) - end - - it "can take private key as a sting :raw_key in options during initializaton" do - expect(Chef::REST.new(base_url, "client-name", nil, :raw_key => SIGNING_KEY_DOT_PEM).signing_key).to eq(SIGNING_KEY_DOT_PEM) - 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) - end - - end - - context "when making REST requests" do - let(:body) { "ninja" } - - let(:http_response) do - http_response = Net::HTTPSuccess.new("1.1", "200", "successful rest req") - http_response.stub(:read_body) - http_response.stub(:body).and_return(body) - http_response["Content-Length"] = body.bytesize.to_s - http_response - end - - let(:host_header) { "one" } - - let(:url) { URI.parse("http://one:80/?foo=bar") } - - let(:base_url) { "http://chef.example.com:4000" } - - let!(:http_client) do - http_client = Net::HTTP.new(url.host, url.port) - http_client.stub(:request).and_yield(http_response).and_return(http_response) - http_client - end - - let(:rest) do - Net::HTTP.stub(:new).and_return(http_client) - Chef::REST::CookieJar.stub(:instance).and_return({}) - Chef::RequestID.instance.stub(:request_id).and_return(request_id) - rest = Chef::REST.new(base_url, nil, nil) - Chef::REST::CookieJar.instance.clear - 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 - end - - describe "as JSON API requests" do - let(:request_mock) { {} } - - 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 - } - end - - before do - Net::HTTP::Get.stub(:new).and_return(request_mock) - end - - it "should always include the X-Chef-Version header" do - Net::HTTP::Get.should_receive(:new).with("/?foo=bar", base_headers).and_return(request_mock) - rest.request(:GET, url, {}) - end - - it "should always include the X-Remote-Request-Id header" do - Net::HTTP::Get.should_receive(:new).with("/?foo=bar", base_headers).and_return(request_mock) - rest.request(:GET, url, {}) - end - - it "sets the user agent to chef-client" 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}/) - end - - # CHEF-3140 - context "when configured to disable compression" do - let(:rest) do - Net::HTTP.stub(:new).and_return(http_client) - Chef::REST.new(base_url, nil, nil, :disable_gzip => true) - end - - it "does not accept encoding gzip" do - expect(rest.send(:build_headers, :GET, url, {})).not_to have_key("Accept-Encoding") - end - - it "does not decompress a response encoded as gzip" do - http_response.add_field("content-encoding", "gzip") - request = Net::HTTP::Get.new(url.path) - Net::HTTP::Get.should_receive(:new).and_return(request) - # will raise a Zlib error if incorrect - expect(rest.request(:GET, url, {})).to eq("ninja") - end - end - - context "when configured with custom http headers" do - let(:custom_headers) do - { - 'X-Custom-ChefSecret' => 'sharpknives', - 'X-Custom-RequestPriority' => 'extremely low' - } - end - - before(:each) do - Chef::Config[:custom_http_headers] = custom_headers - end - - after(:each) do - Chef::Config[:custom_http_headers] = nil - end - - it "should set them on the http request" do - url_string = an_instance_of(String) - header_hash = hash_including(custom_headers) - Net::HTTP::Get.should_receive(:new).with(url_string, header_hash) - rest.request(:GET, url, {}) - end - end - - context "when setting cookies" do - let(:rest) do - Net::HTTP.stub(:new).and_return(http_client) - Chef::REST::CookieJar.instance["#{url.host}:#{url.port}"] = "cookie monster" - Chef::RequestID.instance.stub(:request_id).and_return(request_id) - rest = Chef::REST.new(base_url, nil, nil) - rest - end - - it "should set the cookie for this request if one exists for the given host:port" do - Net::HTTP::Get.should_receive(:new).with("/?foo=bar", base_headers.merge('Cookie' => "cookie monster")).and_return(request_mock) - rest.request(:GET, url, {}) - end - end - - it "should build a new HTTP GET request" do - Net::HTTP::Get.should_receive(:new).with("/?foo=bar", base_headers).and_return(request_mock) - rest.request(:GET, url, {}) - end - - 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') - - Net::HTTP::Post.should_receive(:new).with("/?foo=bar", expected_headers).and_return(request) - 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') - Net::HTTP::Put.should_receive(:new).with("/?foo=bar",expected_headers).and_return(request) - rest.request(:PUT, url, {}, {:one=>:two}) - expect(request.body).to eq('{"one":"two"}') - end - - it "should build a new HTTP DELETE request" do - Net::HTTP::Delete.should_receive(:new).with("/?foo=bar", base_headers).and_return(request_mock) - rest.request(:DELETE, url) - end - - it "should raise an error if the method is not GET/PUT/POST/DELETE" do - expect { rest.request(:MONKEY, url) }.to raise_error(ArgumentError) - end - - it "returns nil when the response is successful but content-type is not JSON" do - expect(rest.request(:GET, url)).to eq("ninja") - end - - it "should fail if the response is truncated" do - http_response["Content-Length"] = (body.bytesize + 99).to_s - expect { rest.request(:GET, url) }.to raise_error(Chef::Exceptions::ContentLengthMismatch) - end - - 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"}) - end - - it "should fail if the response is truncated" do - 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| - describe "when encountering a #{resp_name} redirect" do - let(:http_response) do - resp_cls = Net.const_get(resp_name) - resp_code = Net::HTTPResponse::CODE_TO_OBJ.keys.detect { |k| Net::HTTPResponse::CODE_TO_OBJ[k] == resp_cls } - http_response = Net::HTTPFound.new("1.1", resp_code, "bob is somewhere else again") - http_response.add_field("location", url.path) - http_response.stub(:read_body) - http_response - end - it "should call request again" do - - expect { rest.request(:GET, url) }.to raise_error(Chef::Exceptions::RedirectLimitExceeded) - - [:PUT, :POST, :DELETE].each do |method| - expect { rest.request(method, url) }.to raise_error(Chef::Exceptions::InvalidRedirect) - end - end - end - end - - context "when the response is 304 NotModified" do - let (:http_response) do - http_response = Net::HTTPNotModified.new("1.1", "304", "it's the same as when you asked 5 minutes ago") - http_response.stub(:read_body) - http_response - end - - it "should return `false`" do - expect(rest.request(:GET, url)).to be_false - end - end - - describe "when the request fails" do - before do - @original_log_level = Chef::Log.level - Chef::Log.level = :info - end - - after do - Chef::Log.level = @original_log_level - end - - context "on an unsuccessful response with a JSON error" do - let(:http_response) do - http_response = Net::HTTPServerError.new("1.1", "500", "drooling from inside of mouth") - http_response.add_field("content-type", "application/json") - http_response.stub(:body).and_return('{ "error":[ "Ears get sore!", "Not even four" ] }') - http_response.stub(:read_body) - http_response - end - - it "should show the JSON error message" do - rest.stub(: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')) - end - end - - context "on an unsuccessful response with a JSON error that is compressed" do - let(:http_response) do - http_response = Net::HTTPServerError.new("1.1", "500", "drooling from inside of mouth") - http_response.add_field("content-type", "application/json") - http_response.add_field("content-encoding", "deflate") - unzipped_body = '{ "error":[ "Ears get sore!", "Not even four" ] }' - gzipped_body = Zlib::Deflate.deflate(unzipped_body) - gzipped_body.force_encoding(Encoding::BINARY) if "strings".respond_to?(:force_encoding) - - http_response.stub(:body).and_return gzipped_body - http_response.stub(:read_body) - http_response - end - it "decompresses the JSON error message" do - rest.stub(:sleep) - rest.stub(:http_retry_count).and_return(0) - - 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) - end - end - - context "on a generic unsuccessful request" do - let(:http_response) do - http_response = Net::HTTPServerError.new("1.1", "500", "drooling from inside of mouth") - http_response.stub(:body) - http_response.stub(:read_body) - http_response - end - - it "retries then throws an exception" do - rest.stub(:sleep) - 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 - - context "when streaming downloads to a tempfile" do - let!(:tempfile) { Tempfile.open("chef-rspec-rest_spec-line-@{__LINE__}--") } - - let(:request_mock) { {} } - - let(:http_response) do - http_response = Net::HTTPSuccess.new("1.1",'200', "it-works") - - http_response.stub(:read_body) - http_response.should_not_receive(:body) - http_response["Content-Length"] = "0" # call set_content_length (in test), if otherwise - http_response - end - - def set_content_length - content_length = 0 - http_response.read_body do |chunk| - content_length += chunk.bytesize - end - http_response["Content-Length"] = content_length.to_s - end - - before do - Tempfile.stub(:new).with("chef-rest").and_return(tempfile) - Net::HTTP::Get.stub(:new).and_return(request_mock) - end - - after do - tempfile.close! - 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 - } - Net::HTTP::Get.should_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 - } - Net::HTTP::Get.should_receive(:new).with("/?foo=bar", expected_headers).and_return(request_mock) - rest.streaming_request(url, {}) - end - - it "returns a tempfile containing the streamed response body" do - expect(rest.streaming_request(url, {})).to equal(tempfile) - end - - it "writes the response body to a tempfile" do - http_response.stub(:read_body).and_yield("real").and_yield("ultimate").and_yield("power") - set_content_length - rest.streaming_request(url, {}) - expect(IO.read(tempfile.path).chomp).to eq("realultimatepower") - end - - it "closes the tempfile" do - rest.streaming_request(url, {}) - expect(tempfile).to be_closed - end - - it "yields the tempfile containing the streamed response body and then unlinks it when given a block" do - http_response.stub(:read_body).and_yield("real").and_yield("ultimate").and_yield("power") - set_content_length - tempfile_path = nil - rest.streaming_request(url, {}) do |tempfile| - tempfile_path = tempfile.path - expect(File.exist?(tempfile.path)).to be_true - expect(IO.read(tempfile.path).chomp).to eq("realultimatepower") - end - expect(File.exist?(tempfile_path)).to be_false - end - - it "does not raise a divide by zero exception if the content's actual size is 0" do - http_response['Content-Length'] = "5" - http_response.stub(: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.stub(:read_body).and_yield("ninja") - expect { rest.streaming_request(url, {}) }.to raise_error(Chef::Exceptions::ContentLengthMismatch) - end - - it "it raises an exception when the download is truncated" do - http_response["Content-Length"] = (body.bytesize + 99).to_s - http_response.stub(:read_body).and_yield("ninja") - expect { rest.streaming_request(url, {}) }.to raise_error(Chef::Exceptions::ContentLengthMismatch) - end - - it "fetches a file and yields the tempfile it is streamed to" do - http_response.stub(:read_body).and_yield("real").and_yield("ultimate").and_yield("power") - set_content_length - tempfile_path = nil - rest.fetch("cookbooks/a_cookbook") do |tempfile| - tempfile_path = tempfile.path - expect(IO.read(tempfile.path).chomp).to eq("realultimatepower") - end - expect(File.exist?(tempfile_path)).to be_false - end - - it "closes and unlinks the tempfile if there is an error while streaming the content to the tempfile" do - path = tempfile.path - expect(path).not_to be_nil - tempfile.stub(:write).and_raise(IOError) - rest.fetch("cookbooks/a_cookbook") {|tmpfile| "shouldn't get here"} - expect(File.exists?(path)).to be_false - end - - it "closes and unlinks the tempfile when the response is a redirect" do - tempfile = double("A tempfile", :path => "/tmp/ragefist", :close => true, :binmode => true) - tempfile.should_receive(:close!).at_least(1).times - Tempfile.stub(:new).with("chef-rest").and_return(tempfile) - - redirect = Net::HTTPFound.new("1.1", "302", "bob is taking care of that one for me today") - redirect.add_field("location", url.path) - redirect.stub(:read_body) - - http_client.should_receive(:request).and_yield(redirect).and_return(redirect) - http_client.should_receive(:request).and_yield(http_response).and_return(http_response) - 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.stub(:read_body) - - block_called = false - http_client.stub(:request).and_yield(http_response).and_return(http_redirect, http_response) - rest.fetch("cookbooks/a_cookbook") do |tmpfile| - block_called = true - end - expect(block_called).to be_true - end - end - end - - context "when following redirects" do - let(:rest) do - Chef::REST.new(base_url) - end - - before do - Chef::Config[:node_name] = "webmonkey.example.com" - Chef::Config[:client_key] = CHEF_SPEC_DATA + "/ssl/private_key.pem" - 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) - end - - it "does not count redirects from previous calls against the redirect limit" do - total_redirects = 0 - redirected = lambda do - rest.follow_redirect do - total_redirects += 1 - redirected.call unless total_redirects >= 9 - end - end - expect {redirected.call}.not_to raise_error - total_redirects = 0 - expect {redirected.call}.not_to raise_error - end - - it "does not sign the redirected request when sign_on_redirect is false" do - rest.sign_on_redirect = false - rest.follow_redirect { expect(rest.sign_requests?).to be_false } - end - - it "resets sign_requests to the original value after following an unsigned redirect" do - rest.sign_on_redirect = false - expect(rest.sign_requests?).to be_true - - rest.follow_redirect { expect(rest.sign_requests?).to be_false } - expect(rest.sign_requests?).to be_true - end - - it "configures the redirect limit" do - total_redirects = 0 - redirected = lambda do - rest.follow_redirect do - total_redirects += 1 - redirected.call unless total_redirects >= 9 - end - end - expect {redirected.call}.not_to raise_error - - total_redirects = 0 - rest.redirect_limit = 3 - expect {redirected.call}.to raise_error(Chef::Exceptions::RedirectLimitExceeded) - end - - end -end diff --git a/spec/unit/role_spec.rb b/spec/unit/role_spec.rb deleted file mode 100644 index f3fa7e1868..0000000000 --- a/spec/unit/role_spec.rb +++ /dev/null @@ -1,357 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.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/role' - -describe Chef::Role do - before(:each) do - Chef::Platform.stub(:windows?) { false } - @role = Chef::Role.new - @role.name("ops_master") - end - - it "has a name" do - @role.name("ops_master").should == "ops_master" - end - - it "does not accept a name with spaces" do - lambda { @role.name "ops master" }.should raise_error(ArgumentError) - end - - it "does not accept non-String objects for the name" do - lambda { @role.name({}) }.should raise_error(ArgumentError) - end - - describe "when a run list is set" do - - before do - @role.run_list(%w{ nginx recipe[ree] role[base]}) - end - - - it "returns the run list" do - @role.run_list.should == %w{ nginx recipe[ree] role[base]} - end - - describe "and per-environment run lists are set" do - before do - @role.name("base") - @role.run_list(%w{ recipe[nagios::client] recipe[tims-acl::bork]}) - @role.env_run_list["prod"] = Chef::RunList.new(*(@role.run_list.to_a << "recipe[prod-base]")) - @role.env_run_list["dev"] = Chef::RunList.new - end - - it "uses the default run list as *the* run_list" do - @role.run_list.should == Chef::RunList.new("recipe[nagios::client]", "recipe[tims-acl::bork]") - end - - it "gives the default run list as the when getting the _default run list" do - @role.run_list_for("_default").should == @role.run_list - end - - it "gives an environment specific run list" do - @role.run_list_for("prod").should == Chef::RunList.new("recipe[nagios::client]", "recipe[tims-acl::bork]", "recipe[prod-base]") - end - - it "gives the default run list when no run list exists for the given environment" do - @role.run_list_for("qa").should == @role.run_list - end - - it "gives the environment specific run list even if it is empty" do - @role.run_list_for("dev").should == Chef::RunList.new - end - - it "env_run_lists can only be set with _default run list in it" do - long_exception_name = Chef::Exceptions::InvalidEnvironmentRunListSpecification - lambda {@role.env_run_lists({})}.should raise_error(long_exception_name) - end - - end - - - describe "using the old #recipes API" do - it "should let you set the recipe array" do - @role.recipes([ "one", "two" ]).should == [ "one", "two" ] - end - - it "should let you return the recipe array" do - @role.recipes([ "one", "two" ]) - @role.recipes.should == [ "one", "two" ] - end - - it "should not list roles in the recipe array" do - @role.run_list([ "one", "role[two]"]) - @role.recipes.should == [ "recipe[one]", "role[two]" ] - end - - end - - end - - - - describe "default_attributes" do - it "should let you set the default attributes hash explicitly" do - @role.default_attributes({ :one => 'two' }).should == { :one => 'two' } - end - - it "should let you return the default attributes hash" do - @role.default_attributes({ :one => 'two' }) - @role.default_attributes.should == { :one => 'two' } - end - - it "should throw an ArgumentError if we aren't a kind of hash" do - lambda { @role.default_attributes(Array.new) }.should raise_error(ArgumentError) - end - end - - describe "override_attributes" do - it "should let you set the override attributes hash explicitly" do - @role.override_attributes({ :one => 'two' }).should == { :one => 'two' } - end - - it "should let you return the override attributes hash" do - @role.override_attributes({ :one => 'two' }) - @role.override_attributes.should == { :one => 'two' } - end - - it "should throw an ArgumentError if we aren't a kind of hash" do - lambda { @role.override_attributes(Array.new) }.should raise_error(ArgumentError) - end - end - - 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' }) - - @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' }) - end - - it "should update all fields except for name" do - @role.update_from!(@example) - @role.name.should == "mars_volta" - @role.description.should == @example.description - @role.run_list.should == @example.run_list - @role.default_attributes.should == @example.default_attributes - @role.override_attributes.should == @example.override_attributes - end - end - - 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' }) - @serialized_role = Chef::JSONCompat.to_json(@role) - end - - it "should serialize to a json hash" do - Chef::JSONCompat.to_json(@role).should match(/^\{.+\}$/) - end - - it "includes the name in the JSON output" do - @serialized_role.should =~ /"name":"mars_volta"/ - end - - it "includes its description in the JSON" do - @serialized_role.should match(/"description":"Great band!"/) - end - - it "should include 'default_attributes'" do - @serialized_role.should =~ /"default_attributes":\{"el_groupo":"nuevo"\}/ - end - - it "should include 'override_attributes'" do - @serialized_role.should =~ /"override_attributes":\{"deloused":"in the comatorium"\}/ - end - - it "should include 'run_list'" do - #Activesupport messes with Chef json formatting - #This test should pass with and without activesupport - @serialized_role.should =~ /"run_list":\["recipe\[one\]","recipe\[two\]","role\[a\]"\]/ - end - - 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) - end - - it "includes the per-environment run lists" do - #Activesupport messes with Chef json formatting - #This test should pass with and without activesupport - @serialized_role["env_run_lists"]["production"].should == ['role[monitoring]', 'role[auditing]', 'role[apache]'] - @serialized_role["env_run_lists"]["dev"].should == ["role[nginx]"] - end - - it "does not include the default environment in the per-environment run lists" do - @serialized_role["env_run_lists"].should_not have_key("_default") - end - - 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)) - end - - it "should deserialize to a Chef::Role object" do - @deserial.should be_a_kind_of(Chef::Role) - end - - %w{ - name - description - default_attributes - override_attributes - run_list - }.each do |t| - it "should preserves the '#{t}' attribute from the JSON object" do - @deserial.send(t.to_sym).should == @role.send(t.to_sym) - end - end - end - - 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' - Chef::Config.stub(:cache_path).and_return(default_cache_path) - end - - it "should return a Chef::Role object from JSON" do - Dir.should_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.should_receive(:exists?).with(file_path).exactly(1).times.and_return(true) - IO.should_receive(:read).with(file_path).and_return('{"name": "ceiling_cat", "json_class": "Chef::Role" }') - @role.should be_a_kind_of(Chef::Role) - @role.class.from_disk("lolcat") - end - - it "should return a Chef::Role object from a Ruby DSL" do - Dir.should_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') - File.should_receive(:exists?).with(rb_path).exactly(2).times.and_return(true) - File.should_receive(:readable?).with(rb_path).exactly(1).times.and_return(true) - IO.should_receive(:read).with(rb_path).and_return(ROLE_DSL) - @role.should be_a_kind_of(Chef::Role) - @role.class.from_disk("lolcat") - end - - it "should prefer a Chef::Role Object from JSON over one from a Ruby DSL" do - Dir.should_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') - File.should_receive(:exists?).with(js_path).exactly(1).times.and_return(true) - File.should_not_receive(:exists?).with(rb_path) - IO.should_receive(:read).with(js_path).and_return('{"name": "ceiling_cat", "json_class": "Chef::Role" }') - @role.should be_a_kind_of(Chef::Role) - @role.class.from_disk("lolcat") - end - - it "should raise an exception if the file does not exist" do - Dir.should_receive(:glob).and_return(["#{Chef::Config[:role_path]}/meme.rb"]) - File.should_not_receive(:exists?) - lambda {@role.class.from_disk("lolcat")}.should raise_error(Chef::Exceptions::RoleNotFound) - end - - it "should raise an exception if two files exist with the same name" do - Dir.should_receive(:glob).and_return(["#{Chef::Config[:role_path]}/memes/lolcat.rb", "#{Chef::Config[:role_path]}/lolcat.rb"]) - File.should_not_receive(:exists?) - lambda {@role.class.from_disk("lolcat")}.should raise_error(Chef::Exceptions::DuplicateRole) - end - - it "should not raise an exception if two files exist with a similar name" do - Dir.should_receive(:glob).and_return(["#{Chef::Config[:role_path]}/memes/lolcat.rb", "#{Chef::Config[:role_path]}/super_lolcat.rb"]) - File.should_not_receive(:exists?) - lambda {@role.class.from_disk("lolcat")}.should_not raise_error(Chef::Exceptions::DuplicateRole) - end - end - - describe "when loading from disk and role_path is an array" do - - before(:each) do - Chef::Config[:role_path] = ['/path1', '/path/path2'] - end - - it "should return a Chef::Role object from JSON" do - Dir.should_receive(:glob).with(File.join('/path1', '**', '**')).exactly(1).times.and_return(['/path1/lolcat.json']) - File.should_receive(:exists?).with('/path1/lolcat.json').exactly(1).times.and_return(true) - IO.should_receive(:read).with('/path1/lolcat.json').and_return('{"name": "ceiling_cat", "json_class": "Chef::Role" }') - @role.should 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 - Dir.should_receive(:glob).with(File.join('/path1', '**', '**')).exactly(1).times.and_return([]) - Dir.should_receive(:glob).with(File.join('/path/path2', '**', '**')).exactly(1).times.and_return(['/path/path2/lolcat.json']) - File.should_receive(:exists?).with('/path/path2/lolcat.json').exactly(1).times.and_return(true) - IO.should_receive(:read).with('/path/path2/lolcat.json').and_return('{"name": "ceiling_cat", "json_class": "Chef::Role" }') - @role.should be_a_kind_of(Chef::Role) - @role.class.from_disk("lolcat") - end - - it "should return a Chef::Role object from a Ruby DSL" do - Dir.should_receive(:glob).with(File.join('/path1', '**', '**')).exactly(1).times.and_return(['/path1/lolcat.rb']) - File.should_receive(:exists?).with('/path1/lolcat.rb').exactly(2).times.and_return(true) - File.should_receive(:readable?).with('/path1/lolcat.rb').and_return(true) - IO.should_receive(:read).with('/path1/lolcat.rb').exactly(1).times.and_return(ROLE_DSL) - @role.should 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 - Dir.should_receive(:glob).with(File.join('/path1', '**', '**')).exactly(1).times.and_return([]) - Dir.should_receive(:glob).with(File.join('/path/path2', '**', '**')).exactly(1).times.and_return(['/path/path2/lolcat.rb']) - File.should_receive(:exists?).with('/path/path2/lolcat.rb').exactly(2).times.and_return(true) - File.should_receive(:readable?).with('/path/path2/lolcat.rb').and_return(true) - IO.should_receive(:read).with('/path/path2/lolcat.rb').exactly(1).times.and_return(ROLE_DSL) - @role.should be_a_kind_of(Chef::Role) - @role.class.from_disk("lolcat") - end - - it "should raise an exception if the file does not exist" do - Dir.should_receive(:glob).with(File.join('/path1', '**', '**')).exactly(1).times.and_return([]) - Dir.should_receive(:glob).with(File.join('/path/path2', '**', '**')).exactly(1).times.and_return([]) - lambda {@role.class.from_disk("lolcat")}.should raise_error(Chef::Exceptions::RoleNotFound) - end - - end -end diff --git a/spec/unit/run_context/cookbook_compiler_spec.rb b/spec/unit/run_context/cookbook_compiler_spec.rb deleted file mode 100644 index 5c50c3dd4b..0000000000 --- a/spec/unit/run_context/cookbook_compiler_spec.rb +++ /dev/null @@ -1,186 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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 'support/lib/library_load_order' - -# These tests rely on fixture data in spec/data/run_context/cookbooks. -# -# Dependencies (circular or not) are specified by `depends` directives in the -# metadata of these cookbooks. -# -# Side effects used to verify the behavior are implemented as code in the various file types. -# -describe Chef::RunContext::CookbookCompiler do - - let(:node) { Chef::Node.new } - - let(:events) { Chef::EventDispatch::Dispatcher.new } - - let(:cookbook_loader) do - cl = Chef::CookbookLoader.new(chef_repo_path) - cl.load_cookbooks - cl - end - - let(:run_context) { Chef::RunContext.new(node, cookbook_collection, events) } - - let(:chef_repo_path) { File.expand_path(File.join(CHEF_SPEC_DATA, "run_context", "cookbooks")) } - - 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(: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 - # "cookbook_name::attribute_file_name" to the node's `:attr_load_order` - # attribute when loaded. - - it "loads default.rb first, then other files in sort order" do - node.run_list("dependency1::default") - - compiler.compile_attributes - node[:attr_load_order].should == ["dependency1::default", "dependency1::aa_first", "dependency1::zz_last"] - end - - it "loads dependencies before loading the depending cookbook's attributes" do - # Also make sure that attributes aren't loaded twice if we have two - # recipes from the same cookbook in the run list - node.run_list("test-with-deps::default", "test-with-deps::server") - - compiler.compile_attributes - - # dependencies are stored in a hash so therefore unordered, but they should be loaded in sort order - node[:attr_load_order].should == ["dependency1::default", - "dependency1::aa_first", - "dependency1::zz_last", - "dependency2::default", - "test-with-deps::default"] - end - - it "does not follow infinite dependency loops" do - node.run_list("test-with-circular-deps::default") - - # Circular deps should not cause infinite loops - compiler.compile_attributes - - node[:attr_load_order].should == ["circular-dep2::default", "circular-dep1::default", "test-with-circular-deps::default"] - end - - it "loads attributes from cookbooks that don't have a default.rb attribute file" do - node.run_list("no-default-attr::default.rb") - - compiler.compile_attributes - - node[:attr_load_order].should == ["no-default-attr::server"] - end - end - - describe "loading libraries" do - before do - LibraryLoadOrder.reset! - end - - # One big test for everything. Individual behaviors are tested by the attribute code above. - it "loads libraries in run list order" do - node.run_list("test-with-deps::default", "test-with-circular-deps::default") - - compiler.compile_libraries - LibraryLoadOrder.load_order.should == ["dependency1", "dependency2", "test-with-deps", "circular-dep2", "circular-dep1", "test-with-circular-deps"] - end - end - - describe "loading LWRPs" do - before do - LibraryLoadOrder.reset! - end - - # One big test for everything. Individual behaviors are tested by the attribute code above. - it "loads LWRPs in run list order" do - node.run_list("test-with-deps::default", "test-with-circular-deps::default") - - compiler.compile_lwrps - LibraryLoadOrder.load_order.should == ["dependency1-provider", - "dependency1-resource", - "dependency2-provider", - "dependency2-resource", - "test-with-deps-provider", - "test-with-deps-resource", - "circular-dep2-provider", - "circular-dep2-resource", - "circular-dep1-provider", - "circular-dep1-resource", - "test-with-circular-deps-provider", - "test-with-circular-deps-resource"] - end - end - - describe "loading resource definitions" do - before do - LibraryLoadOrder.reset! - end - - # One big test for all load order concerns. Individual behaviors are tested - # by the attribute code above. - it "loads resource definitions in run list order" do - node.run_list("test-with-deps::default", "test-with-circular-deps::default") - - compiler.compile_resource_definitions - LibraryLoadOrder.load_order.should == ["dependency1-definition", - "dependency2-definition", - "test-with-deps-definition", - "circular-dep2-definition", - "circular-dep1-definition", - "test-with-circular-deps-definition"] - end - - end - - describe "loading recipes" do - # Tests for this behavior are in RunContext's tests - end - - describe "listing cookbook order" do - it "should return an array of cookbook names as symbols without duplicates" do - node.run_list("test-with-circular-deps::default", "circular-dep1::default", "circular-dep2::default") - - compiler.cookbook_order.should == [:"circular-dep2", - :"circular-dep1", - :"test-with-circular-deps"] - end - - it "determines if a cookbook is in the list of cookbooks reachable by dependency" do - node.run_list("test-with-deps::default", "test-with-deps::server") - compiler.cookbook_order.should == [:dependency1, :dependency2, :"test-with-deps"] - compiler.unreachable_cookbook?(:dependency1).should be_false - compiler.unreachable_cookbook?(:dependency2).should be_false - compiler.unreachable_cookbook?(:'test-with-deps').should be_false - compiler.unreachable_cookbook?(:'circular-dep1').should be_true - compiler.unreachable_cookbook?(:'circular-dep2').should be_true - end - - - end -end diff --git a/spec/unit/run_context_spec.rb b/spec/unit/run_context_spec.rb deleted file mode 100644 index 21ece2abaa..0000000000 --- a/spec/unit/run_context_spec.rb +++ /dev/null @@ -1,152 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: Tim Hinderliter (<tim@opscode.com>) -# Author:: Christopher Walters (<cw@opscode.com>) -# Copyright:: Copyright (c) 2008, 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. -# - -require 'spec_helper' -require 'support/lib/library_load_order' - -Chef::Log.level = :debug - -describe Chef::RunContext do - before(:each) do - @chef_repo_path = File.expand_path(File.join(CHEF_SPEC_DATA, "run_context", "cookbooks")) - cl = Chef::CookbookLoader.new(@chef_repo_path) - cl.load_cookbooks - @cookbook_collection = Chef::CookbookCollection.new(cl) - @node = Chef::Node.new - @node.run_list << "test" << "test::one" << "test::two" - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events) - end - - it "has a cookbook collection" do - @run_context.cookbook_collection.should == @cookbook_collection - end - - it "has a node" do - @run_context.node.should == @node - end - - describe "loading cookbooks for a run list" do - before do - - # Each invocation reloads LWRPs, which triggers constant redefinition - # warnings. In real usage this isn't an issue because of fork mode. - if Chef::Provider.const_defined?(:TestProvider) - Chef::Provider.send(:remove_const, :TestProvider) - end - - @node.run_list << "test" << "test::one" << "test::two" - @node.should_receive(:loaded_recipe).with(:test, "default") - @node.should_receive(:loaded_recipe).with(:test, "one") - @node.should_receive(:loaded_recipe).with(:test, "two") - @run_context.load(@node.run_list.expand('_default')) - end - - it "should load all the definitions in the cookbooks for this node" do - @run_context.definitions.should have_key(:new_cat) - @run_context.definitions.should have_key(:new_badger) - @run_context.definitions.should have_key(:new_dog) - end - - it "should load all the recipes specified for this node" do - @run_context.resource_collection[0].to_s.should == "cat[einstein]" - @run_context.resource_collection[1].to_s.should == "cat[loulou]" - @run_context.resource_collection[2].to_s.should == "cat[birthday]" - @run_context.resource_collection[3].to_s.should == "cat[peanut]" - @run_context.resource_collection[4].to_s.should == "cat[fat peanut]" - end - - it "loads all the attribute files in the cookbook collection" do - @run_context.loaded_fully_qualified_attribute?("test", "george").should be_true - @node[:george].should == "washington" - end - - it "registers attributes files as loaded so they won't be reloaded" do - # This test unfortunately is pretty tightly intertwined with the - # implementation of how nodes load attribute files, but is the only - # convenient way to test this behavior. - @node.should_not_receive(:from_file) - @node.include_attribute("test::george") - end - - it "raises an error when attempting to include_recipe from a cookbook not reachable by run list or dependencies" do - @node.should_receive(:loaded_recipe).with(:ancient, "aliens") - lambda do - @run_context.include_recipe("ancient::aliens") - # In CHEF-5120, this becomes a Chef::Exceptions::MissingCookbookDependency error: - end.should raise_error(Chef::Exceptions::CookbookNotFound) - end - - end - - describe "querying the contents of cookbooks" do - before do - @chef_repo_path = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks")) - cl = Chef::CookbookLoader.new(@chef_repo_path) - cl.load_cookbooks - @cookbook_collection = Chef::CookbookCollection.new(cl) - @node = Chef::Node.new - @node.set[:platform] = "ubuntu" - @node.set[:platform_version] = "13.04" - @node.name("testing") - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events) - end - - - it "queries whether a given cookbook has a specific template" do - @run_context.should have_template_in_cookbook("openldap", "test.erb") - @run_context.should_not have_template_in_cookbook("openldap", "missing.erb") - end - - it "errors when querying for a template in a not-available cookbook" do - expect do - @run_context.has_template_in_cookbook?("no-such-cookbook", "foo.erb") - end.to raise_error(Chef::Exceptions::CookbookNotFound) - end - - it "queries whether a given cookbook has a specific cookbook_file" do - @run_context.should have_cookbook_file_in_cookbook("java", "java.response") - @run_context.should_not have_cookbook_file_in_cookbook("java", "missing.txt") - end - - it "errors when querying for a cookbook_file in a not-available cookbook" do - expect do - @run_context.has_cookbook_file_in_cookbook?("no-such-cookbook", "foo.txt") - end.to raise_error(Chef::Exceptions::CookbookNotFound) - end - end - - describe "handling reboot requests" do - let(:expected) do - { :reason => "spec tests require a reboot" } - end - - it "stores and deletes the reboot request" do - @run_context.request_reboot(expected) - expect(@run_context.reboot_info).to eq(expected) - expect(@run_context.reboot_requested?).to be_true - - @run_context.cancel_reboot - expect(@run_context.reboot_info).to eq({}) - expect(@run_context.reboot_requested?).to be_false - 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 deleted file mode 100644 index 907e3d3985..0000000000 --- a/spec/unit/run_list/run_list_expansion_spec.rb +++ /dev/null @@ -1,129 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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. -# - -require 'spec_helper' - -describe Chef::RunList::RunListExpansion do - before do - @run_list = Chef::RunList.new - @run_list << 'recipe[lobster]' << 'role[rage]' << 'recipe[fist]' - @expansion = Chef::RunList::RunListExpansion.new("_default", @run_list.run_list_items) - end - - describe "before expanding the run list" do - it "has an array of run list items" do - @expansion.run_list_items.should == @run_list.run_list_items - end - - it "has default_attrs" do - @expansion.default_attrs.should == Mash.new - end - - it "has override attrs" do - @expansion.override_attrs.should == Mash.new - end - - it "it has an empty list of recipes" do - @expansion.should have(0).recipes - end - - it "has not applied its roles" do - @expansion.applied_role?('rage').should be_false - end - end - - describe "after applying a role with environment-specific run lists" do - before do - @rage_role = Chef::Role.new.tap do |r| - r.name("rage") - r.env_run_lists('_default' => [], "prod" => ["recipe[prod-only]"]) - end - @expansion = Chef::RunList::RunListExpansion.new("prod", @run_list.run_list_items) - @expansion.should_receive(:fetch_role).and_return(@rage_role) - @expansion.expand - end - - it "has the correct list of recipes for the given environment" do - @expansion.recipes.should == ["lobster", "prod-only", "fist"] - end - - end - - describe "after applying a role" do - before do - @expansion.stub(:fetch_role).and_return(Chef::Role.new) - @expansion.inflate_role('rage', "role[base]") - end - - it "tracks the applied role" do - @expansion.applied_role?('rage').should be_true - end - - it "does not inflate the role again" do - @expansion.inflate_role('rage', "role[base]").should be_false - 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'}) - @second_role = Chef::Role.new - @second_role.run_list('recipe[crabrevenge]') - @second_role.default_attributes({'foo' => 'boo'}) - @second_role.override_attributes({'baz' => 'bux'}) - @expansion.stub(:fetch_role).and_return(@first_role, @second_role) - @expansion.expand - end - - it "has the ordered list of recipes" do - @expansion.recipes.should == ['lobster', 'crabrevenge', 'fist'] - end - - it "has the merged attributes from the roles with outer roles overridding inner" do - @expansion.default_attrs.should == {'foo' => 'bar'} - @expansion.override_attrs.should == {'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 - @expansion.roles.should =~ ['rage', 'mollusk'] - end - - end - - describe "after expanding a run list with a non existant role" do - before do - @expansion.stub(:fetch_role) { @expansion.role_not_found('crabrevenge', "role[base]") } - @expansion.expand - end - - it "is invalid" do - @expansion.should be_invalid - @expansion.errors?.should be_true # aliases - end - - it "has a list of invalid role names" do - @expansion.errors.should include('crabrevenge') - end - - end - -end diff --git a/spec/unit/run_list/run_list_item_spec.rb b/spec/unit/run_list/run_list_item_spec.rb deleted file mode 100644 index 6b9de713da..0000000000 --- a/spec/unit/run_list/run_list_item_spec.rb +++ /dev/null @@ -1,117 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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. -# - -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 - lambda {Chef::RunList::RunListItem.new(:name => "tatft")}.should raise_error(ArgumentError) - end - - it "raises an exception when the hash doesn't have an :name key" do - lambda {Chef::RunList::RunListItem.new(:type => 'R') }.should 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') - item.to_s.should == 'fuuu[uuuu]' - end - - end - - describe "when creating an item from a string" do - it "parses a qualified recipe" do - item = Chef::RunList::RunListItem.new("recipe[rage]") - item.should be_a_recipe - item.should_not be_a_role - item.to_s.should == 'recipe[rage]' - item.name.should == 'rage' - end - - it "parses a qualified recipe with a version" do - item = Chef::RunList::RunListItem.new("recipe[rage@0.1.0]") - item.should be_a_recipe - item.should_not be_a_role - item.to_s.should == 'recipe[rage@0.1.0]' - item.name.should == 'rage' - item.version.should == '0.1.0' - end - - it "parses a qualified role" do - item = Chef::RunList::RunListItem.new("role[fist]") - item.should be_a_role - item.should_not be_a_recipe - item.to_s.should == 'role[fist]' - item.name.should == 'fist' - end - - it "parses an unqualified recipe" do - item = Chef::RunList::RunListItem.new("lobster") - item.should be_a_recipe - item.should_not be_a_role - item.to_s.should == 'recipe[lobster]' - item.name.should == 'lobster' - end - - it "raises an exception when the string has typo on the type part" do - lambda {Chef::RunList::RunListItem.new("Recipe[lobster]") }.should raise_error(ArgumentError) - end - - it "raises an exception when the string has extra space between the type and the name" do - lambda {Chef::RunList::RunListItem.new("recipe [lobster]") }.should raise_error(ArgumentError) - end - - it "raises an exception when the string does not close the bracket" do - lambda {Chef::RunList::RunListItem.new("recipe[lobster") }.should 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.should == 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.should_not == 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.should_not == 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.should_not == item2 - end - end - - describe "comparing to strings" do - it "is equal to a string if that string matches its to_s representation" do - Chef::RunList::RunListItem.new('recipe[lrf]').should == '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 deleted file mode 100644 index 5cef32c32b..0000000000 --- a/spec/unit/run_list/versioned_recipe_list_spec.rb +++ /dev/null @@ -1,123 +0,0 @@ -# -# Author:: Stephen Delano (<stephen@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. - -require 'spec_helper' - -describe Chef::RunList::VersionedRecipeList do - - describe "initialize" do - it "should create an empty array" do - l = Chef::RunList::VersionedRecipeList.new - l.should == [] - end - end - - describe "add_recipe" do - before(:each) do - @list = Chef::RunList::VersionedRecipeList.new - @list << "apt" - @list << "god" - @list << "apache2" - end - - it "should append the recipe to the end of the list" do - @list.add_recipe "rails" - @list.should == ["apt", "god", "apache2", "rails"] - end - - it "should not duplicate entries" do - @list.add_recipe "apt" - @list.should == ["apt", "god", "apache2"] - end - - it "should allow you to specify a version" do - @list.add_recipe "rails", "1.0.0" - @list.should == ["apt", "god", "apache2", "rails"] - @list.with_versions.should 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" - @list.should == ["apt", "god", "apache2"] - @list.with_versions.should 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" - @list.with_versions.should 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" - @list.with_versions.should 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" - lambda {@list.add_recipe "rails", "0.1.0"}.should 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"} - ] - @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 - @list.with_versions.should == @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[index][:name].should == 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 - end - - it "should return an array of hashes with :name and :version_constraint" do - @list.with_version_constraints.each do |x| - x.should have_key :name - x[:version_constraint].should_not be nil - end - end - end -end diff --git a/spec/unit/run_list_spec.rb b/spec/unit/run_list_spec.rb deleted file mode 100644 index 220e4ea4a6..0000000000 --- a/spec/unit/run_list_spec.rb +++ /dev/null @@ -1,312 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Author:: Seth Falcon (<seth@opscode.com>) -# Author:: Christopher Walters (<cw@opscode.com>) -# Copyright:: Copyright (c) 2008-2011 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/version_class' -require 'chef/version_constraint' - -describe Chef::RunList do - before(:each) do - @run_list = Chef::RunList.new - end - - describe "<<" do - it "should add a recipe to the run list and recipe list with the fully qualified name" do - @run_list << 'recipe[needy]' - @run_list.should include('recipe[needy]') - @run_list.recipes.should 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]" - @run_list.should include('role[woot]') - @run_list.roles.should include('woot') - end - - it "should accept recipes that are unqualified" do - @run_list << "needy" - @run_list.should include('recipe[needy]') - @run_list.recipes.include?('needy').should == true - end - - it "should not allow duplicates" do - @run_list << "needy" - @run_list << "needy" - @run_list.run_list.length.should == 1 - @run_list.recipes.length.should == 1 - end - - it "should allow two versions of a recipe" do - @run_list << "recipe[needy@0.2.0]" - @run_list << "recipe[needy@0.1.0]" - @run_list.run_list.length.should == 2 - @run_list.recipes.length.should == 2 - @run_list.recipes.include?('needy').should == true - end - - it "should not allow duplicate versions of a recipe" do - @run_list << "recipe[needy@0.2.0]" - @run_list << "recipe[needy@0.2.0]" - @run_list.run_list.length.should == 1 - @run_list.recipes.length.should == 1 - end - end - - describe "add" 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]' - @run_list.should include('recipe[needy]') - end - - it "should add a role to the run_list" do - @run_list.add 'role[needy]' - @run_list.should include('role[needy]') - end - end - - describe "==" do - it "should believe two RunLists are equal if they have the same members" do - @run_list << "foo" - r = Chef::RunList.new - r << "foo" - @run_list.should == r - end - - it "should believe a RunList is equal to an array named after it's members" do - @run_list << "foo" - @run_list << "baz" - @run_list.should == [ "foo", "baz" ] - end - end - - describe "empty?" do - it "should be emtpy if the run list has no members" do - @run_list.empty?.should == true - end - - it "should not be empty if the run list has members" do - @run_list << "chromeo" - @run_list.empty?.should == false - end - end - - describe "[]" do - it "should let you look up a member in the run list by position" do - @run_list << 'recipe[loulou]' - @run_list[0].should == '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]' - @run_list[0].should == 'recipe[loulou]' - end - - it "should properly expand a member of the run list given by position" do - @run_list[0] = 'loulou' - @run_list[0].should == 'recipe[loulou]' - end - end - - describe "each" do - it "should yield each member to your block" do - @run_list << "foo" - @run_list << "bar" - seen = Array.new - @run_list.each { |r| seen << r } - seen.should be_include("recipe[foo]") - seen.should be_include("recipe[bar]") - end - end - - describe "each_index" do - it "should yield each members index to your block" do - to_add = [ "recipe[foo]", "recipe[bar]", "recipe[baz]" ] - to_add.each { |i| @run_list << i } - @run_list.each_index { |i| @run_list[i].should == to_add[i] } - end - end - - describe "include?" do - it "should be true if the run list includes the item" do - @run_list << "foo" - @run_list.include?("foo") - end - end - - describe "reset" do - it "should reset the run_list based on the array you pass" do - @run_list << "chromeo" - list = %w{camp chairs snakes clowns} - @run_list.reset!(list) - list.each { |i| @run_list.should be_include(i) } - @run_list.include?("chromeo").should == false - end - end - - describe "when expanding the run list" do - before(:each) do - @role = Chef::Role.new - @role.name "stubby" - @role.run_list "one", "two" - @role.default_attributes :one => :two - @role.override_attributes :three => :four - - Chef::Role.stub(:load).and_return(@role) - @rest = double("Chef::REST", { :get_rest => @role, :url => "/" }) - Chef::REST.stub(:new).and_return(@rest) - - @run_list << "role[stubby]" - @run_list << "kitty" - end - - describe "from disk" do - it "should load the role from disk" do - Chef::Role.should_receive(:from_disk).with("stubby") - @run_list.expand("_default", "disk") - end - - it "should log a helpful error if the role is not available" do - Chef::Role.stub(:from_disk).and_raise(Chef::Exceptions::RoleNotFound) - Chef::Log.should_receive(:error).with("Role stubby (included by 'top level') is in the runlist but does not exist. Skipping expand.") - @run_list.expand("_default", "disk") - end - end - - describe "from the chef server" do - it "should load the role from the chef server" do - #@rest.should_receive(:get_rest).with("roles/stubby") - expansion = @run_list.expand("_default", "server") - expansion.recipes.should == ['one', 'two', 'kitty'] - end - - it "should default to expanding from the server" do - @rest.should_receive(:get_rest).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") - expansion.recipes.should == %w{one two five kitty} - end - - describe "and multiply nested roles" do - before do - @multiple_rest_requests = double("Chef::REST") - - @role.env_run_list["production"] << "role[prod-base]" - - @role_prod_base = Chef::Role.new - @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 - Chef::REST.stub(:new).and_return(@multiple_rest_requests) - @multiple_rest_requests.should_receive(:get_rest).with("roles/stubby").and_return(@role) - @multiple_rest_requests.should_receive(:get_rest).with("roles/prod-base").and_return(@role_prod_base) - @multiple_rest_requests.should_receive(:get_rest).with("roles/nested-deeper").and_return(@role_nested_deeper) - - expansion = @run_list.expand("production", "server") - expansion.recipes.should == %w{one two five prod-secret-sauce kitty} - end - - end - - end - - end - - it "should return the list of expanded recipes" do - expansion = @run_list.expand("_default") - expansion.recipes[0].should == "one" - expansion.recipes[1].should == "two" - end - - it "should return the list of default attributes" do - expansion = @run_list.expand("_default") - expansion.default_attrs[:one].should == :two - end - - it "should return the list of override attributes" do - expansion = @run_list.expand("_default") - expansion.override_attrs[:three].should == :four - end - - it "should recurse into a child role" do - dog = Chef::Role.new - dog.name "dog" - dog.default_attributes :seven => :nine - dog.run_list "three" - @role.run_list << "role[dog]" - Chef::Role.stub(:from_disk).with("stubby").and_return(@role) - Chef::Role.stub(:from_disk).with("dog").and_return(dog) - - expansion = @run_list.expand("_default", 'disk') - expansion.recipes[2].should == "three" - expansion.default_attrs[:seven].should == :nine - end - - it "should not recurse infinitely" do - dog = Chef::Role.new - dog.name "dog" - dog.default_attributes :seven => :nine - dog.run_list "role[dog]", "three" - @role.run_list << "role[dog]" - Chef::Role.stub(:from_disk).with("stubby").and_return(@role) - Chef::Role.should_receive(:from_disk).with("dog").once.and_return(dog) - - expansion = @run_list.expand("_default", 'disk') - expansion.recipes[2].should == "three" - expansion.recipes[3].should == "kitty" - expansion.default_attrs[:seven].should == :nine - end - end - - describe "when converting to an alternate representation" do - before do - @run_list << "recipe[nagios::client]" << "role[production]" << "recipe[apache2]" - end - - it "converts to an array of the string forms of its items" do - @run_list.to_a.should == ["recipe[nagios::client]", "role[production]", "recipe[apache2]"] - end - - it "converts to json by converting its array form" do - @run_list.to_json.should == ["recipe[nagios::client]", "role[production]", "recipe[apache2]"].to_json - end - - end - -end diff --git a/spec/unit/run_lock_spec.rb b/spec/unit/run_lock_spec.rb deleted file mode 100644 index 80140dfcce..0000000000 --- a/spec/unit/run_lock_spec.rb +++ /dev/null @@ -1,140 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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 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' - - describe "when first created" do - it "locates the lockfile in the file cache path by default" do - Chef::Config.stub(:cache_path).and_return(default_cache_path) - run_lock = Chef::RunLock.new(Chef::Config.lockfile) - run_lock.runlock_file.should == default_pid_location - end - - it "locates the lockfile in the user-configured path when set" do - Chef::Config.lockfile = "/tmp/chef-client-running.pid" - run_lock = Chef::RunLock.new(Chef::Config.lockfile) - run_lock.runlock_file.should == "/tmp/chef-client-running.pid" - end - end - - describe "acquire" do - let(:lockfile) { "/tmp/chef-client-running.pid" } - subject(:runlock) { Chef::RunLock.new(lockfile) } - - def stub_unblocked_run - runlock.stub(:test).and_return(true) - end - - def stub_blocked_run(duration) - runlock.stub(:test).and_return(false) - runlock.stub(:wait) { sleep(duration) } - runlock.stub(:runpid).and_return(666) # errors read blocking pid - end - - describe "when Chef::Config[:run_lock_timeout] is not set (set to default)" do - describe "and the lockfile is not locked by another client run" do - it "should not wait" do - stub_unblocked_run - Chef::RunLock.any_instance.should_not_receive(:wait) - runlock.acquire - end - end - - describe "and the lockfile is locked by another client run" do - it "should wait for the lock to be released" do - stub_blocked_run(0.001) - runlock.should_receive(:wait) - runlock.acquire - end - end - end - - describe "when Chef::Config[:run_lock_timeout] is set to 0" do - before(:each) do - @default_timeout = Chef::Config[:run_lock_timeout] - Chef::Config[:run_lock_timeout] = 0 - end - - after(:each) do - Chef::Config[:run_lock_timeout] = @default_timeout - end - - describe "and the lockfile is not locked by another client run" do - it "should acquire the lock" do - stub_unblocked_run - runlock.should_not_receive(:wait) - runlock.acquire - end - end - - describe "and the lockfile is locked by another client run" do - it "should raise Chef::Exceptions::RunLockTimeout" do - stub_blocked_run(0.001) - runlock.should_not_receive(:wait) - expect{ runlock.acquire }.to raise_error(Chef::Exceptions::RunLockTimeout) - end - end - end - - describe "when Chef::Config[:run_lock_timeout] is set to >0" do - before(:each) do - @default_timeout = Chef::Config[:run_lock_timeout] - @timeout = 0.1 - Chef::Config[:run_lock_timeout] = @timeout - end - - after(:each) do - Chef::Config[:run_lock_timeout] = @default_timeout - end - - describe "and the lockfile is not locked by another client run" do - it "should acquire the lock" do - stub_unblocked_run - runlock.should_not_receive(:wait) - runlock.acquire - end - end - - 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) - runlock.should_receive(:wait) - expect{ runlock.acquire }.not_to raise_error - end - end - - describe "and the lock is not released before the timeout expires" do - it "should raise a RunLockTimeout exception" do - stub_blocked_run(2.0) - runlock.should_receive(:wait) - expect{ runlock.acquire }.to raise_error(Chef::Exceptions::RunLockTimeout) - end - end - end - end - end - - # See also: spec/functional/run_lock_spec - -end diff --git a/spec/unit/run_status_spec.rb b/spec/unit/run_status_spec.rb deleted file mode 100644 index 6c85364871..0000000000 --- a/spec/unit/run_status_spec.rb +++ /dev/null @@ -1,145 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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. -# - - -require 'spec_helper' - -describe Chef::RunStatus do - before do - @node = Chef::Node.new - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, {}, @events) - @run_status = Chef::RunStatus.new(@node, @events) - end - - describe "before the run context has been set" do - it "converts to a hash" do - @run_status.to_hash - end - end - - describe "when the run context has been set" do - before do - @run_status.run_context = @run_context - end - - it "has a run context" do - @run_status.run_context.should equal(@run_context) - end - - it "provides access to the run context's node" do - @run_status.node.should equal(@node) - end - - it "converts to a hash" do - @run_status.to_hash[:node].should equal(@node) - @run_status.to_hash[:success].should be_true - end - - describe "after it has recorded timing information" do - before do - @start_time = Time.new - @end_time = @start_time + 23 - Time.stub(:now).and_return(@start_time, @end_time) - @run_status.start_clock - @run_status.stop_clock - end - - it "records the start time of the run" do - @run_status.start_time.should == @start_time - end - - it "records the end time of the run" do - @run_status.end_time.should == @end_time - end - - it "gives the elapsed time of the chef run" do - @run_status.elapsed_time.should == 23 - end - - it "includes timing information in its hash form" do - @run_status.to_hash[:start_time].should == @start_time - @run_status.to_hash[:end_time].should == @end_time - @run_status.to_hash[:elapsed_time].should == 23 - end - - end - - describe "with resources in the resource_collection" do - before do - @all_resources = [Chef::Resource::Cat.new("whiskers"), Chef::Resource::ZenMaster.new('dtz')] - @run_context.resource_collection.all_resources.replace(@all_resources) - end - - it "lists all resources" do - @run_status.all_resources.should == @all_resources - end - - it "has no updated resources" do - @run_status.updated_resources.should be_empty - end - - it "includes the list of all resources in its hash form" do - @run_status.to_hash[:all_resources].should == @all_resources - @run_status.to_hash[:updated_resources].should be_empty - end - - describe "and some have been updated" do - before do - @all_resources.first.updated = true - end - - it "lists the updated resources" do - @run_status.updated_resources.should == [@all_resources.first] - end - - it "includes the list of updated resources in its hash form" do - @run_status.to_hash[:updated_resources].should == [@all_resources.first] - end - end - end - - describe "when the run failed" do - before do - @exception = Exception.new("just testing") - @backtrace = caller - @exception.set_backtrace(@backtrace) - @run_status.exception = @exception - end - - it "stores the exception" do - @run_status.exception.should equal(@exception) - end - - it "stores the backtrace" do - @run_status.backtrace.should == @backtrace - end - - it "says the run was not successful" do - @run_status.success?.should be_false - @run_status.failed?.should be_true - end - - it "converts to a hash including the exception information" do - @run_status.to_hash[:success].should be_false - @run_status.to_hash[:exception].should == "Exception: just testing" - @run_status.to_hash[:backtrace].should == @backtrace - end - end - end -end diff --git a/spec/unit/runner_spec.rb b/spec/unit/runner_spec.rb deleted file mode 100644 index 68d8b0e011..0000000000 --- a/spec/unit/runner_spec.rb +++ /dev/null @@ -1,402 +0,0 @@ - -# Author:: Adam Jacob (<adam@opscode.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' - -class SnitchyProvider < Chef::Provider - def self.all_actions_called - @all_actions_called ||= [] - end - - def self.action_called(action) - all_actions_called << action - end - - def self.clear_action_record - @all_actions_called = nil - end - - def load_current_resource - true - end - - def action_first_action - @new_resource.updated_by_last_action(true) - self.class.action_called(:first) - end - - def action_second_action - @new_resource.updated_by_last_action(true) - self.class.action_called(:second) - end - - def action_third_action - @new_resource.updated_by_last_action(true) - self.class.action_called(:third) - end - -end - -class FailureResource < Chef::Resource - - attr_accessor :action - - def initialize(*args) - super - @action = :fail - end - - def provider - FailureProvider - end -end - -class FailureProvider < Chef::Provider - - class ChefClientFail < StandardError; end - - def load_current_resource - true - end - - def action_fail - raise ChefClientFail, "chef had an error of some sort" - end -end - -describe Chef::Runner do - - before(:each) do - @node = Chef::Node.new - @node.name "latte" - @node.automatic[:platform] = "mac_os_x" - @node.automatic[:platform_version] = "10.5.1" - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(@node, Chef::CookbookCollection.new({}), @events) - @first_resource = Chef::Resource::Cat.new("loulou1", @run_context) - @run_context.resource_collection << @first_resource - Chef::Platform.set( - :resource => :cat, - :provider => Chef::Provider::SnakeOil - ) - @runner = Chef::Runner.new(@run_context) - end - - it "should pass each resource in the collection to a provider" do - @run_context.resource_collection.should_receive(:execute_each_resource).once - @runner.converge - end - - it "should use the provider specified by the resource (if it has one)" do - provider = Chef::Provider::Easy.new(@run_context.resource_collection[0], @run_context) - # Expect provider to be called twice, because will fall back to old provider lookup - @run_context.resource_collection[0].should_receive(:provider).twice.and_return(Chef::Provider::Easy) - Chef::Provider::Easy.should_receive(:new).once.and_return(provider) - @runner.converge - end - - it "should use the platform provider if it has one" do - Chef::Platform.should_receive(:find_provider_for_node).once.and_return(Chef::Provider::SnakeOil) - @runner.converge - end - - it "should run the action for each resource" do - Chef::Platform.should_receive(:find_provider_for_node).once.and_return(Chef::Provider::SnakeOil) - provider = Chef::Provider::SnakeOil.new(@run_context.resource_collection[0], @run_context) - provider.should_receive(:action_sell).once.and_return(true) - Chef::Provider::SnakeOil.should_receive(:new).once.and_return(provider) - @runner.converge - end - - it "should raise exceptions as thrown by a provider" do - provider = Chef::Provider::SnakeOil.new(@run_context.resource_collection[0], @run_context) - Chef::Provider::SnakeOil.stub(:new).once.and_return(provider) - provider.stub(:action_sell).once.and_raise(ArgumentError) - lambda { @runner.converge }.should raise_error(ArgumentError) - end - - it "should not raise exceptions thrown by providers if the resource has ignore_failure set to true" do - @run_context.resource_collection[0].stub(:ignore_failure).and_return(true) - provider = Chef::Provider::SnakeOil.new(@run_context.resource_collection[0], @run_context) - Chef::Provider::SnakeOil.stub(:new).once.and_return(provider) - provider.stub(:action_sell).once.and_raise(ArgumentError) - lambda { @runner.converge }.should_not raise_error - end - - it "should retry with the specified delay if retries are specified" do - @first_resource.retries 3 - provider = Chef::Provider::SnakeOil.new(@run_context.resource_collection[0], @run_context) - Chef::Provider::SnakeOil.stub(:new).once.and_return(provider) - provider.stub(:action_sell).and_raise(ArgumentError) - @first_resource.should_receive(:sleep).with(2).exactly(3).times - lambda { @runner.converge }.should raise_error(ArgumentError) - end - - it "should execute immediate actions on changed resources" do - notifying_resource = Chef::Resource::Cat.new("peanut", @run_context) - notifying_resource.action = :purr # only action that will set updated on the resource - - @run_context.resource_collection << notifying_resource - @first_resource.action = :nothing # won't be updated unless notified by other resource - - notifying_resource.notifies(:purr, @first_resource, :immediately) - - @runner.converge - - @first_resource.should be_updated - end - - it "should follow a chain of actions" do - @first_resource.action = :nothing - - middle_resource = Chef::Resource::Cat.new("peanut", @run_context) - middle_resource.action = :nothing - @run_context.resource_collection << middle_resource - middle_resource.notifies(:purr, @first_resource, :immediately) - - last_resource = Chef::Resource::Cat.new("snuffles", @run_context) - last_resource.action = :purr - @run_context.resource_collection << last_resource - last_resource.notifies(:purr, middle_resource, :immediately) - - @runner.converge - - last_resource.should be_updated # by action(:purr) - middle_resource.should be_updated # by notification from last_resource - @first_resource.should be_updated # by notification from middle_resource - end - - it "should execute delayed actions on changed resources" do - @first_resource.action = :nothing - second_resource = Chef::Resource::Cat.new("peanut", @run_context) - second_resource.action = :purr - - @run_context.resource_collection << second_resource - second_resource.notifies(:purr, @first_resource, :delayed) - - @runner.converge - - @first_resource.should be_updated - end - - it "should execute delayed notifications when a failure occurs in the chef client run" do - @first_resource.action = :nothing - second_resource = Chef::Resource::Cat.new("peanut", @run_context) - second_resource.action = :purr - - @run_context.resource_collection << second_resource - second_resource.notifies(:purr, @first_resource, :delayed) - - third_resource = FailureResource.new("explode", @run_context) - @run_context.resource_collection << third_resource - - lambda {@runner.converge}.should raise_error(FailureProvider::ChefClientFail) - - @first_resource.should be_updated - end - - it "should execute delayed notifications when a failure occurs in a notification" do - @first_resource.action = :nothing - second_resource = Chef::Resource::Cat.new("peanut", @run_context) - second_resource.action = :purr - - @run_context.resource_collection << second_resource - - third_resource = FailureResource.new("explode", @run_context) - third_resource.action = :nothing - @run_context.resource_collection << third_resource - - second_resource.notifies(:fail, third_resource, :delayed) - second_resource.notifies(:purr, @first_resource, :delayed) - - lambda {@runner.converge}.should raise_error(FailureProvider::ChefClientFail) - - @first_resource.should be_updated - end - - it "should execute delayed notifications when a failure occurs in multiple notifications" do - @first_resource.action = :nothing - second_resource = Chef::Resource::Cat.new("peanut", @run_context) - second_resource.action = :purr - - @run_context.resource_collection << second_resource - - third_resource = FailureResource.new("explode", @run_context) - third_resource.action = :nothing - @run_context.resource_collection << third_resource - - fourth_resource = FailureResource.new("explode again", @run_context) - fourth_resource.action = :nothing - @run_context.resource_collection << fourth_resource - - second_resource.notifies(:fail, third_resource, :delayed) - second_resource.notifies(:fail, fourth_resource, :delayed) - second_resource.notifies(:purr, @first_resource, :delayed) - - exception = nil - begin - @runner.converge - rescue => e - exception = e - end - exception.should be_a(Chef::Exceptions::MultipleFailures) - - 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 -E - exception.message.should == expected_message - - @first_resource.should be_updated - end - - it "does not duplicate delayed notifications" do - SnitchyProvider.clear_action_record - - Chef::Platform.set( - :resource => :cat, - :provider => SnitchyProvider - ) - - @first_resource.action = :nothing - - second_resource = Chef::Resource::Cat.new("peanut", @run_context) - second_resource.action = :first_action - @run_context.resource_collection << second_resource - - third_resource = Chef::Resource::Cat.new("snickers", @run_context) - third_resource.action = :first_action - @run_context.resource_collection << third_resource - - second_resource.notifies(:second_action, @first_resource, :delayed) - second_resource.notifies(:third_action, @first_resource, :delayed) - - third_resource.notifies(:second_action, @first_resource, :delayed) - third_resource.notifies(:third_action, @first_resource, :delayed) - - @runner.converge - # resources 2 and 3 call :first_action in the course of normal resource - # execution, and schedule delayed actions :second and :third on the first - # resource. The duplicate actions should "collapse" to a single notification - # and order should be preserved. - SnitchyProvider.all_actions_called.should == [:first, :first, :second, :third] - end - - it "executes delayed notifications in the order they were declared" do - SnitchyProvider.clear_action_record - - Chef::Platform.set( - :resource => :cat, - :provider => SnitchyProvider - ) - - @first_resource.action = :nothing - - second_resource = Chef::Resource::Cat.new("peanut", @run_context) - second_resource.action = :first_action - @run_context.resource_collection << second_resource - - third_resource = Chef::Resource::Cat.new("snickers", @run_context) - third_resource.action = :first_action - @run_context.resource_collection << third_resource - - second_resource.notifies(:second_action, @first_resource, :delayed) - second_resource.notifies(:second_action, @first_resource, :delayed) - - third_resource.notifies(:third_action, @first_resource, :delayed) - third_resource.notifies(:third_action, @first_resource, :delayed) - - @runner.converge - SnitchyProvider.all_actions_called.should == [:first, :first, :second, :third] - end - - it "does not fire notifications if the resource was not updated by the last action executed" do - # REGRESSION TEST FOR CHEF-1452 - SnitchyProvider.clear_action_record - - Chef::Platform.set( - :resource => :cat, - :provider => SnitchyProvider - ) - - @first_resource.action = :first_action - - second_resource = Chef::Resource::Cat.new("peanut", @run_context) - second_resource.action = :nothing - @run_context.resource_collection << second_resource - - third_resource = Chef::Resource::Cat.new("snickers", @run_context) - third_resource.action = :nothing - @run_context.resource_collection << third_resource - - @first_resource.notifies(:second_action, second_resource, :immediately) - second_resource.notifies(:third_action, third_resource, :immediately) - - @runner.converge - - # All of the resources should only fire once: - SnitchyProvider.all_actions_called.should == [:first, :second, :third] - - # all of the resources should be marked as updated for reporting purposes - @first_resource.should be_updated - second_resource.should be_updated - third_resource.should be_updated - end - - it "should check a resource's only_if and not_if if notified by another resource" do - @first_resource.action = :buy - - only_if_called_times = 0 - @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} - - second_resource = Chef::Resource::Cat.new("carmel", @run_context) - @run_context.resource_collection << second_resource - second_resource.notifies(:purr, @first_resource, :delayed) - second_resource.action = :purr - - # hits only_if first time when the resource is run in order, second on notify - @runner.converge - - only_if_called_times.should == 2 - not_if_called_times.should == 2 - end - - it "should resolve resource references in notifications when resources are defined lazily" do - @first_resource.action = :nothing - - lazy_resources = lambda { - last_resource = Chef::Resource::Cat.new("peanut", @run_context) - @run_context.resource_collection << last_resource - last_resource.notifies(:purr, @first_resource.to_s, :delayed) - last_resource.action = :purr - } - second_resource = Chef::Resource::RubyBlock.new("myblock", @run_context) - @run_context.resource_collection << second_resource - second_resource.block { lazy_resources.call } - - @runner.converge - - @first_resource.should be_updated - end - -end - diff --git a/spec/unit/scan_access_control_spec.rb b/spec/unit/scan_access_control_spec.rb deleted file mode 100644 index 48f820ff85..0000000000 --- a/spec/unit/scan_access_control_spec.rb +++ /dev/null @@ -1,184 +0,0 @@ -# Author:: Daniel DeLeo (<dan@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 File.expand_path("../../spec_helper", __FILE__) -require 'chef/scan_access_control' - -describe Chef::ScanAccessControl do - - before do - @new_resource = Chef::Resource::File.new("/tmp/foo/bar/baz/link") - @real_file = "/tmp/foo/bar/real/file" - @current_resource = Chef::Resource::File.new(@new_resource.path) - @scanner = Chef::ScanAccessControl.new(@new_resource, @current_resource) - end - - describe "when the fs entity does not exist" do - - before do - @new_resource.tap do |f| - f.owner("root") - f.group("root") - f.mode('0755') - end - @scanner.set_all! - end - - it "does not set any fields on the current resource" do - @current_resource.owner.should be_nil - @current_resource.group.should be_nil - @current_resource.mode.should be_nil - end - - end - - describe "when the fs entity exists" do - - before do - @stat = double("File::Stat for #{@new_resource.path}", :uid => 0, :gid => 0, :mode => 00100644) - File.should_receive(:realpath).with(@new_resource.path).and_return(@real_file) - File.should_receive(:stat).with(@real_file).and_return(@stat) - File.should_receive(:exist?).with(@new_resource.path).and_return(true) - end - - describe "when new_resource does not specify mode, user or group" do - # these tests are necessary for minitest-chef-handler to use as an API, see CHEF-3235 - before do - @scanner.set_all! - end - - it "sets the mode of the current resource to the current mode as a String" do - @current_resource.mode.should == "0644" - end - - context "on unix", :unix_only do - it "sets the group of the current resource to the current group as a String" do - @current_resource.group.should == Etc.getgrgid(0).name - end - - it "sets the owner of the current resource to the current owner as a String" do - @current_resource.user.should == "root" - end - end - - context "on windows", :windows_only do - it "sets the group of the current resource to the current group as a String" do - @current_resource.group.should == 0 - end - - it "sets the owner of the current resource to the current owner as a String" do - @current_resource.user.should == 0 - end - end - end - - describe "when new_resource specifies the mode with a string" do - before do - @new_resource.mode("0755") - @scanner.set_all! - end - - it "sets the mode of the current resource to the file's current mode as a string" do - @current_resource.mode.should == "0644" - end - end - - describe "when new_resource specified the mode with an integer" do - before do - @new_resource.mode(00755) - @scanner.set_all! - end - - it "sets the mode of the current resource to the current mode as a String" do - @current_resource.mode.should == "0644" - end - - end - - describe "when new_resource specifies the user with a UID" do - - before do - @new_resource.user(0) - @scanner.set_all! - end - - it "sets the owner of current_resource to the UID of the current owner" do - @current_resource.user.should == 0 - end - end - - describe "when new_resource specifies the user with a username" do - - before do - @new_resource.user("root") - end - - it "sets the owner of current_resource to the username of the current owner" do - @root_passwd = double("Struct::Passwd for uid 0", :name => "root") - Etc.should_receive(:getpwuid).with(0).and_return(@root_passwd) - @scanner.set_all! - - @current_resource.user.should == "root" - end - - describe "and there is no passwd entry for the user" do - it "sets the owner of the current_resource to the UID" do - Etc.should_receive(:getpwuid).with(0).and_raise(ArgumentError) - @scanner.set_all! - @current_resource.user.should == 0 - end - end - end - - describe "when new_resource specifies the group with a GID" do - - before do - @new_resource.group(0) - @scanner.set_all! - end - - it "sets the group of the current_resource to the gid of the current owner" do - @current_resource.group.should == 0 - end - - end - - describe "when new_resource specifies the group with a group name" do - before do - @new_resource.group("wheel") - end - - it "sets the group of the current resource to the group name" do - @group_entry = double("Struct::Group for wheel", :name => "wheel") - Etc.should_receive(:getgrgid).with(0).and_return(@group_entry) - @scanner.set_all! - - @current_resource.group.should == "wheel" - end - - describe "and there is no group entry for the group" do - it "sets the current_resource's group to the GID" do - Etc.should_receive(:getgrgid).with(0).and_raise(ArgumentError) - @scanner.set_all! - @current_resource.group.should == 0 - end - end - - end - end -end - diff --git a/spec/unit/search/query_spec.rb b/spec/unit/search/query_spec.rb deleted file mode 100644 index c7388a6234..0000000000 --- a/spec/unit/search/query_spec.rb +++ /dev/null @@ -1,255 +0,0 @@ -# -# Author:: Adam Jacob (<adam@opscode.com>) -# Copyright:: Copyright (c) 2009,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. -# - -require 'spec_helper' -require 'chef/search/query' - -describe Chef::Search::Query do - let(:rest) { double("Chef::REST") } - let(:query) { Chef::Search::Query.new } - - shared_context "filtered search" do - let(:query_string) { "search/node?q=platform:rhel&sort=X_CHEF_id_CHEF_X%20asc&start=0&rows=1000" } - let(:server_url) { "https://api.opscode.com/organizations/opscode/nodes" } - let(:args) { { filter_key => filter_hash } } - let(:filter_hash) { - { - 'env' => [ 'chef_environment' ], - 'ruby_plat' => [ 'languages', 'ruby', 'platform' ] - } - } - let(:response) { - { - "rows" => [ - { "url" => "#{server_url}/my-name-is-node", - "data" => { - "env" => "elysium", - "ruby_plat" => "nudibranch" - } - }, - { "url" => "#{server_url}/my-name-is-jonas", - "data" => { - "env" => "hades", - "ruby_plat" => "i386-mingw32" - } - }, - { "url" => "#{server_url}/my-name-is-flipper", - "data" => { - "env" => "elysium", - "ruby_plat" => "centos" - } - }, - { "url" => "#{server_url}/my-name-is-butters", - "data" => { - "env" => "moon", - "ruby_plat" => "solaris2", - } - } - ], - "start" => 0, - "total" => 4 - } - } - end - - before(:each) do - Chef::REST.stub(:new).and_return(rest) - rest.stub(:get_rest).and_return(response) - end - - describe "search" do - let(:response) { { - "rows" => [ - { "name" => "my-name-is-node", - "chef_environment" => "elysium", - "platform" => "rhel", - "automatic" => { - "languages" => { - "ruby" => { - "platform" => "nudibranch", - "version" => "1.9.3", - "target" => "ming-the-merciless" - } - } - } - }, - { "name" => "my-name-is-jonas", - "chef_environment" => "hades", - "platform" => "rhel", - "automatic" => { - "languages" => { - "ruby" => { - "platform" => "i386-mingw32", - "version" => "1.9.3", - "target" => "bilbo" - } - } - } - }, - { "name" => "my-name-is-flipper", - "chef_environment" => "elysium", - "platform" => "rhel", - "automatic" => { - "languages" => { - "ruby" => { - "platform" => "centos", - "version" => "2.0.0", - "target" => "uno" - } - } - } - }, - { "name" => "my-name-is-butters", - "chef_environment" => "moon", - "platform" => "rhel", - "automatic" => { - "languages" => { - "ruby" => { - "platform" => "solaris2", - "version" => "2.1.2", - "target" => "random" - } - } - } - }, - ], - "start" => 0, - "total" => 4 - } } - - it "should accept a type as the first argument" do - lambda { query.search("node") }.should_not raise_error - lambda { query.search(:node) }.should_not raise_error - lambda { query.search(Hash.new) }.should raise_error(Chef::Exceptions::InvalidSearchQuery, /(Hash)/) - end - - it "should query for every object of a type by default" do - rest.should_receive(:get_rest).with("search/node?q=*:*&sort=X_CHEF_id_CHEF_X%20asc&start=0&rows=1000").and_return(response) - query.search(:node) - end - - it "should allow a custom query" do - rest.should_receive(:get_rest).with("search/node?q=platform:rhel&sort=X_CHEF_id_CHEF_X%20asc&start=0&rows=1000").and_return(response) - query.search(:node, "platform:rhel") - end - - it "should let you set a sort order" do - rest.should_receive(:get_rest).with("search/node?q=platform:rhel&sort=id%20desc&start=0&rows=1000").and_return(response) - query.search(:node, "platform:rhel", "id desc") - end - - it "should let you set a starting object" do - rest.should_receive(:get_rest).with("search/node?q=platform:rhel&sort=id%20desc&start=2&rows=1000").and_return(response) - query.search(:node, "platform:rhel", "id desc", 2) - end - - it "should let you set how many rows to return" do - rest.should_receive(:get_rest).with("search/node?q=platform:rhel&sort=id%20desc&start=2&rows=40").and_return(response) - query.search(:node, "platform:rhel", "id desc", 2, 40) - end - - it "should throw an exception if you pass to many options" do - lambda { query.search(:node, "platform:rhel", "id desc", 2, 40, "wrong") } - .should raise_error(Chef::Exceptions::InvalidSearchQuery, "Too many arguments! (4 for <= 3)") - end - - it "should return the raw rows, start, and total if no block is passed" do - rows, start, total = query.search(:node) - rows.should equal(response["rows"]) - start.should equal(response["start"]) - total.should equal(response["total"]) - end - - it "should call a block for each object in the response" do - @call_me = double("blocky") - response["rows"].each { |r| @call_me.should_receive(:do).with(r) } - query.search(:node) { |r| @call_me.do(r) } - end - - it "should page through the responses" do - @call_me = double("blocky") - response["rows"].each { |r| @call_me.should_receive(:do).with(r) } - query.search(:node, "*:*", nil, 0, 1) { |r| @call_me.do(r) } - end - - context "when :filter_result is provided as a result" do - include_context "filtered search" do - let(:filter_key) { :filter_result } - - before(:each) do - rest.should_receive(:post_rest).with(query_string, args[filter_key]).and_return(response) - end - - it "should return start" do - start = query.search(:node, "platform:rhel", args)[1] - start.should == response['start'] - end - - it "should return total" do - total = query.search(:node, "platform:rhel", args)[2] - total.should == response['total'] - end - - it "should return rows with the filter applied" do - results = query.search(:node, "platform:rhel", args)[0] - - results.each_with_index do |result, idx| - expected = response["rows"][idx] - - result.should have_key("url") - result["url"].should == expected["url"] - - result.should have_key("data") - filter_hash.keys.each do |filter_key| - result["data"].should have_key(filter_key) - result["data"][filter_key].should == expected["data"][filter_key] - end - end - end - - end - end - end - - describe "#partial_search" do - include_context "filtered search" do - let(:filter_key) { :keys } - - it "should emit a deprecation warning" do - # partial_search calls search, so we'll stub search to return empty - query.stub(:search).and_return( [ [], 0, 0 ] ) - Chef::Log.should_receive(:warn).with("DEPRECATED: The 'partial_search' api is deprecated, please use the search api with 'filter_result'") - query.partial_search(:node, "platform:rhel", args) - end - - it "should return an array of filtered hashes" do - rest.should_receive(:post_rest).with(query_string, args[filter_key]).and_return(response) - results = query.partial_search(:node, "platform:rhel", args) - - results.each_with_index do |result, idx| - expected = response["rows"][idx] - - filter_hash.keys.each do |filter_key| - result.should have_key(filter_key) - result[filter_key].should == expected["data"][filter_key] - end - end - end - end - end -end diff --git a/spec/unit/shell/model_wrapper_spec.rb b/spec/unit/shell/model_wrapper_spec.rb deleted file mode 100644 index eae3b2b581..0000000000 --- a/spec/unit/shell/model_wrapper_spec.rb +++ /dev/null @@ -1,97 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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. -# - -require 'spec_helper' -require 'ostruct' - -describe Shell::ModelWrapper do - before do - @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") - @wrapper = Shell::ModelWrapper.new(@model, :client) - end - - it "uses the explicit model symbol" do - @wrapper.model_symbol.should == :client - end - end - - it "determines the model symbol from the class name" do - @wrapper.model_symbol.should == :node - end - - describe "when listing objects" do - before do - @node_1 = Chef::Node.new - @node_1.name("sammich") - @node_2 = Chef::Node.new - @node_2.name("yummy") - @server_response = {:node_1 => @node_1, :node_2 => @node_2} - @wrapper = Shell::ModelWrapper.new(Chef::Node) - Chef::Node.stub(:list).and_return(@server_response) - end - - it "lists fully inflated objects without the resource IDs" do - @wrapper.all.should have(2).nodes - @wrapper.all.should include(@node_1, @node_2) - end - - it "maps the listed nodes when given a block" do - @wrapper.all {|n| n.name }.sort.reverse.should == %w{yummy sammich} - end - end - - describe "when searching for objects" do - before do - @node_1 = Chef::Node.new - @node_1.name("sammich") - @node_2 = Chef::Node.new - @node_2.name("yummy") - @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... - @searcher = double("Chef::Search::Query #{__FILE__}:#{__LINE__}") - Chef::Search::Query.stub(:new).and_return(@searcher) - end - - it "falls back to listing the objects when the 'query' is :all" do - Chef::Node.stub(:list).and_return(@server_response) - @wrapper.find(:all).should include(@node_1, @node_2) - end - - it "searches for objects using the given query string" do - @searcher.should_receive(:search).with(:node, 'name:app*').and_yield(@node_1).and_yield(@node_2) - @wrapper.find("name:app*").should include(@node_1, @node_2) - end - - it "creates a 'AND'-joined query string from a HASH" do - # Hash order woes - @searcher.should_receive(:search).with(:node, 'name:app* AND name:app*').and_yield(@node_1).and_yield(@node_2) - @wrapper.find(:name=>"app*",'name'=>"app*").should 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 deleted file mode 100644 index c24acbca3e..0000000000 --- a/spec/unit/shell/shell_ext_spec.rb +++ /dev/null @@ -1,153 +0,0 @@ -# Author:: Daniel DeLeo (<dan@kallistec.com>) -# Copyright:: Copyright (c) 2009 Daniel DeLeo -# 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. -# - -require 'spec_helper' - -describe Shell::Extensions do - describe "extending object for top level methods" do - - before do - @shell_client = TestableShellSession.instance - Shell.stub(:session).and_return(@shell_client) - @job_manager = TestJobManager.new - @root_context = Object.new - @root_context.instance_eval(&ObjectTestHarness) - Shell::Extensions.extend_context_object(@root_context) - @root_context.conf = double("irbconf") - end - - it "finds a subsession in irb for an object" do - target_context_obj = Chef::Node.new - - irb_context = double("context", :main => target_context_obj) - irb_session = double("irb session", :context => irb_context) - @job_manager.jobs = [[:thread, irb_session]] - @root_context.stub(:jobs).and_return(@job_manager) - @root_context.ensure_session_select_defined - @root_context.jobs.select_shell_session(target_context_obj).should == irb_session - @root_context.jobs.select_shell_session(:idontexist).should be_nil - end - - it "finds, then switches to a session" do - @job_manager.jobs = [] - @root_context.stub(:ensure_session_select_defined) - @root_context.stub(:jobs).and_return(@job_manager) - @job_manager.should_receive(:select_shell_session).and_return(:the_shell_session) - @job_manager.should_receive(:switch).with(:the_shell_session) - @root_context.find_or_create_session_for(:foo) - end - - it "creates a new session if an existing one isn't found" do - @job_manager.jobs = [] - @root_context.stub(:jobs).and_return(@job_manager) - @job_manager.stub(:select_shell_session).and_return(nil) - @root_context.should_receive(:irb).with(:foo) - @root_context.find_or_create_session_for(:foo) - end - - it "switches to recipe context" do - @root_context.should respond_to(:recipe_mode) - @shell_client.recipe = :monkeyTime - @root_context.should_receive(:find_or_create_session_for).with(:monkeyTime) - @root_context.recipe_mode - end - - it "switches to attribute context" do - @root_context.should respond_to(:attributes_mode) - @shell_client.node = "monkeyNodeTime" - @root_context.should_receive(:find_or_create_session_for).with("monkeyNodeTime") - @root_context.attributes_mode - end - - it "has a help command" do - @root_context.should respond_to(:help) - end - - it "turns irb tracing on and off" do - @root_context.should respond_to(:trace) - @root_context.conf.should_receive(:use_tracer=).with(true) - @root_context.stub(:tracing?) - @root_context.tracing :on - end - - it "says if tracing is on or off" do - @root_context.conf.stub(:use_tracer).and_return(true) - @root_context.should_receive(:puts).with("tracing is on") - @root_context.tracing? - end - - it "prints node attributes" do - node = double("node", :attribute => {:foo => :bar}) - @shell_client.node = node - @root_context.should_receive(:pp).with({:foo => :bar}) - @root_context.ohai - @root_context.should_receive(:pp).with(:bar) - @root_context.ohai(:foo) - end - - it "resets the recipe and reloads ohai data" do - @shell_client.should_receive(:reset!) - @root_context.reset - end - - it "turns irb echo on and off" do - @root_context.conf.should_receive(:echo=).with(true) - @root_context.echo :on - end - - it "says if echo is on or off" do - @root_context.conf.stub(:echo).and_return(true) - @root_context.should_receive(:puts).with("echo is on") - @root_context.echo? - end - - it "gives access to the stepable iterator" do - Shell::StandAloneSession.instance.stub(:reset!) - Shell.session.stub(:rebuild_context) - events = Chef::EventDispatch::Dispatcher.new - run_context = Chef::RunContext.new(Chef::Node.new, {}, events) - run_context.resource_collection.instance_variable_set(:@iterator, :the_iterator) - Shell.session.run_context = run_context - @root_context.chef_run.should == :the_iterator - end - - it "lists directory contents" do - entries = %w{. .. someFile} - Dir.should_receive(:entries).with("/tmp").and_return(entries) - @root_context.ls "/tmp" - end - - end - - describe "extending the recipe object" do - - before do - @events = Chef::EventDispatch::Dispatcher.new - @run_context = Chef::RunContext.new(Chef::Node.new, {}, @events) - @recipe_object = Chef::Recipe.new(nil, nil, @run_context) - Shell::Extensions.extend_context_recipe(@recipe_object) - end - - it "gives a list of the resources" do - resource = @recipe_object.file("foo") - @recipe_object.should_receive(:pp).with(["file[foo]"]) - @recipe_object.resources - end - - end -end diff --git a/spec/unit/shell/shell_session_spec.rb b/spec/unit/shell/shell_session_spec.rb deleted file mode 100644 index f49c9fc805..0000000000 --- a/spec/unit/shell/shell_session_spec.rb +++ /dev/null @@ -1,196 +0,0 @@ -# Author:: Daniel DeLeo (<dan@kallistec.com>) -# Copyright:: Copyright (c) 2009 Daniel DeLeo -# 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 "ostruct" - - -class TestableShellSession < Shell::ShellSession - - def rebuild_node - nil - end - - def rebuild_collection - nil - end - - def loading - nil - end - - def loading_complete - nil - end - -end - -describe Shell::ShellSession do - - it "is a singleton object" do - Shell::ShellSession.should include(Singleton) - end - -end - -describe Shell::ClientSession do - before do - Chef::Config[:shell_config] = { :override_runlist => [Chef::RunList::RunListItem.new('shell::override')] } - @chef_rest = double("Chef::REST") - @session = Shell::ClientSession.instance - @node = Chef::Node.build("foo") - @session.node = @node - @client = double("Chef::Client.new", - :run_ohai => true, - :load_node => true, - :build_node => true, - :register => true, - :sync_cookbooks => {}) - end - - it "builds the node's run_context with the proper environment" do - @session.instance_variable_set(:@client, @client) - @expansion = Chef::RunList::RunListExpansion.new(@node.chef_environment, []) - - @node.run_list.should_receive(:expand).with(@node.chef_environment).and_return(@expansion) - Chef::REST.should_receive(:new).with(Chef::Config[:chef_server_url]).and_return(@chef_rest) - @session.rebuild_context - end - - it "passes the shell CLI args to the client" do - Chef::Client.should_receive(:new).with(nil, Chef::Config[:shell_config]).and_return(@client) - @session.send(:rebuild_node) - end - -end - -describe Shell::StandAloneSession do - before do - 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 - @run_context = @session.run_context = Chef::RunContext.new(@node, {}, @events) - @recipe = @session.recipe = Chef::Recipe.new(nil, nil, @run_context) - Shell::Extensions.extend_context_recipe(@recipe) - end - - it "has a run_context" do - @session.run_context.should equal(@run_context) - end - - it "returns a collection based on it's standalone recipe file" do - @session.resource_collection.should == @recipe.run_context.resource_collection - end - - it "gives nil for the definitions (for now)" do - @session.definitions.should be_nil - end - - it "gives nil for the cookbook_loader" do - @session.cookbook_loader.should be_nil - end - - it "runs chef with the standalone recipe" do - @session.stub(:node_built?).and_return(true) - Chef::Log.stub(:level) - chef_runner = double("Chef::Runner.new", :converge => :converged) - # pre-heat resource collection cache - @session.resource_collection - - Chef::Runner.should_receive(:new).with(@session.recipe.run_context).and_return(chef_runner) - @recipe.run_chef.should == :converged - end - - it "passes the shell CLI args to the client" do - @client = double("Chef::Client.new", - :run_ohai => true, - :load_node => true, - :build_node => true, - :register => true, - :sync_cookbooks => {}) - Chef::Client.should_receive(:new).with(nil, Chef::Config[:shell_config]).and_return(@client) - @session.send(:rebuild_node) - end - -end - -describe Shell::SoloSession do - before do - 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 - @events = Chef::EventDispatch::Dispatcher.new - @run_context = @session.run_context = Chef::RunContext.new(@node, {}, @events) - @session.node = @node - @recipe = @session.recipe = Chef::Recipe.new(nil, nil, @run_context) - Shell::Extensions.extend_context_recipe(@recipe) - end - - after do - Chef::Config[:shell_solo] = nil - end - - it "returns a collection based on it's compilation object and the extra recipe provided by chef-shell" do - @session.stub(:node_built?).and_return(true) - kitteh = Chef::Resource::Cat.new("keyboard") - @recipe.run_context.resource_collection << kitteh - @session.resource_collection.should include(kitteh) - end - - it "returns definitions from its compilation object" do - @session.definitions.should == @run_context.definitions - 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.besnard_lakes.should == "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 - - it "generates its resource collection from the compiled cookbooks and the ad hoc recipe" do - @session.stub(:node_built?).and_return(true) - kitteh_cat = Chef::Resource::Cat.new("kitteh") - @run_context.resource_collection << kitteh_cat - keyboard_cat = Chef::Resource::Cat.new("keyboard_cat") - @recipe.run_context.resource_collection << keyboard_cat - #@session.rebuild_collection - @session.resource_collection.should include(kitteh_cat, keyboard_cat) - end - - it "runs chef with a resource collection from the compiled cookbooks" do - @session.stub(:node_built?).and_return(true) - Chef::Log.stub(:level) - chef_runner = double("Chef::Runner.new", :converge => :converged) - Chef::Runner.should_receive(:new).with(an_instance_of(Chef::RunContext)).and_return(chef_runner) - - @recipe.run_chef.should == :converged - end - - it "passes the shell CLI args to the client" do - @client = double("Chef::Client.new", - :run_ohai => true, - :load_node => true, - :build_node => true, - :register => true, - :sync_cookbooks => {}) - Chef::Client.should_receive(:new).with(nil, Chef::Config[:shell_config]).and_return(@client) - @session.send(:rebuild_node) - end - -end diff --git a/spec/unit/shell_out_spec.rb b/spec/unit/shell_out_spec.rb deleted file mode 100644 index 1330dd16de..0000000000 --- a/spec/unit/shell_out_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -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 - Chef::Log.should_receive(:warn).with("Chef::ShellOut is deprecated, please use Mixlib::ShellOut") - Chef::Log.should_receive(:warn).with(/Called from\:/) - Chef::ShellOut.new("pwd") - end -end - -describe "Chef::Exceptions::ShellCommandFailed deprecation notices" do - - it "logs a warning when referencing the constant Chef::Exceptions::ShellCommandFailed" do - Chef::Log.should_receive(:warn).with("Chef::Exceptions::ShellCommandFailed is deprecated, use Mixlib::ShellOut::ShellCommandFailed") - Chef::Log.should_receive(:warn).with(/Called from\:/) - Chef::Exceptions::ShellCommandFailed - end -end diff --git a/spec/unit/shell_spec.rb b/spec/unit/shell_spec.rb deleted file mode 100644 index bf638e1c3a..0000000000 --- a/spec/unit/shell_spec.rb +++ /dev/null @@ -1,160 +0,0 @@ -# Author:: Daniel DeLeo (<dan@kallistec.com>) -# Copyright:: Copyright (c) 2009 Daniel DeLeo -# 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 "ostruct" - -ObjectTestHarness = Proc.new do - extend Shell::Extensions::ObjectCoreExtensions - - def conf=(new_conf) - @conf = new_conf - end - - def conf - @conf - end - - desc "rspecin'" - def rspec_method - end -end - -class TestJobManager - attr_accessor :jobs -end - -describe Shell do - - before do - Shell.irb_conf = {} - Shell::ShellSession.instance.stub(:reset!) - end - - describe "reporting its status" do - - it "alway says it is running" do - Shell.should be_running - end - - end - - describe "configuring IRB" do - it "configures irb history" do - Shell.configure_irb - Shell.irb_conf[:HISTORY_FILE].should == "~/.chef/chef_shell_history" - Shell.irb_conf[:SAVE_HISTORY].should == 1000 - end - - it "has a prompt like ``chef > '' in the default context" do - Shell.configure_irb - - conf = OpenStruct.new - conf.main = Object.new - conf.main.instance_eval(&ObjectTestHarness) - Shell.irb_conf[:IRB_RC].call(conf) - conf.prompt_c.should == "chef > " - conf.return_format.should == " => %s \n" - conf.prompt_i.should == "chef > " - conf.prompt_n.should == "chef ?> " - conf.prompt_s.should == "chef%l> " - conf.use_tracer.should == false - end - - it "has a prompt like ``chef:recipe > '' in recipe context" do - Shell.configure_irb - - conf = OpenStruct.new - events = Chef::EventDispatch::Dispatcher.new - conf.main = Chef::Recipe.new(nil,nil,Chef::RunContext.new(Chef::Node.new, {}, events)) - Shell.irb_conf[:IRB_RC].call(conf) - conf.prompt_c.should == "chef:recipe > " - conf.prompt_i.should == "chef:recipe > " - conf.prompt_n.should == "chef:recipe ?> " - conf.prompt_s.should == "chef:recipe%l> " - end - - it "has a prompt like ``chef:attributes > '' in attributes/node context" do - Shell.configure_irb - - conf = OpenStruct.new - conf.main = Chef::Node.new - Shell.irb_conf[:IRB_RC].call(conf) - conf.prompt_c.should == "chef:attributes > " - conf.prompt_i.should == "chef:attributes > " - conf.prompt_n.should == "chef:attributes ?> " - conf.prompt_s.should == "chef:attributes%l> " - end - - end - - describe "convenience macros for creating the chef object" do - - before do - @chef_object = Object.new - @chef_object.instance_eval(&ObjectTestHarness) - end - - it "creates help text for methods with descriptions" do - @chef_object.help_descriptions.should == [Shell::Extensions::Help.new("rspec_method", "rspecin'", nil)] - end - - it "adds help text when a new method is described then defined" do - describe_define =<<-EVAL - desc "foo2the Bar" - def baz - end - EVAL - @chef_object.instance_eval describe_define - @chef_object.help_descriptions.should == [Shell::Extensions::Help.new("rspec_method", "rspecin'"), - Shell::Extensions::Help.new("baz", "foo2the Bar")] - end - - it "adds help text for subcommands" do - describe_define =<<-EVAL - subcommands :baz_obj_command => "something you can do with baz.baz_obj_command" - def baz - end - EVAL - @chef_object.instance_eval describe_define - expected_help_text_fragments = [Shell::Extensions::Help.new("rspec_method", "rspecin'")] - expected_help_text_fragments << Shell::Extensions::Help.new("baz.baz_obj_command", "something you can do with baz.baz_obj_command") - @chef_object.help_descriptions.should == expected_help_text_fragments - end - - it "doesn't add previous subcommand help to commands defined afterward" do - describe_define =<<-EVAL - desc "swingFromTree" - def monkey_time - end - - def super_monkey_time - end - - EVAL - @chef_object.instance_eval describe_define - @chef_object.help_descriptions.should have(2).descriptions - @chef_object.help_descriptions.select {|h| h.cmd == "super_monkey_time" }.should be_empty - end - - it "creates a help banner with the command descriptions" do - @chef_object.help_banner.should match(/^\|\ Command[\s]+\|\ Description[\s]*$/) - @chef_object.help_banner.should match(/^\|\ rspec_method[\s]+\|\ rspecin\'[\s]*$/) - end - end - -end diff --git a/spec/unit/user_spec.rb b/spec/unit/user_spec.rb deleted file mode 100644 index 08bde33d7b..0000000000 --- a/spec/unit/user_spec.rb +++ /dev/null @@ -1,267 +0,0 @@ -# -# Author:: Steven Danna (steve@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/user' -require 'tempfile' - -describe Chef::User do - before(:each) do - @user = Chef::User.new - end - - describe "initialize" do - it "should be a Chef::User" do - @user.should be_a_kind_of(Chef::User) - end - end - - describe "name" do - it "should let you set the name to a string" do - @user.name("ops_master").should == "ops_master" - end - - it "should return the current name" do - @user.name "ops_master" - @user.name.should == "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 - lambda { @user.name "Bar" }.should raise_error(ArgumentError) - # slashes - lambda { @user.name "foo/bar" }.should raise_error(ArgumentError) - # ? - lambda { @user.name "foo?" }.should raise_error(ArgumentError) - # & - lambda { @user.name "foo&" }.should raise_error(ArgumentError) - end - - - it "should not accept spaces" do - lambda { @user.name "ops master" }.should raise_error(ArgumentError) - end - - it "should throw an ArgumentError if you feed it anything but a string" do - lambda { @user.name Hash.new }.should raise_error(ArgumentError) - end - end - - describe "admin" do - it "should let you set the admin bit" do - @user.admin(true).should == true - end - - it "should return the current admin value" do - @user.admin true - @user.admin.should == true - end - - it "should default to false" do - @user.admin.should == false - end - - it "should throw an ArgumentError if you feed it anything but true or false" do - lambda { @user.name Hash.new }.should raise_error(ArgumentError) - end - end - - describe "public_key" do - it "should let you set the public key" do - @user.public_key("super public").should == "super public" - end - - it "should return the current public key" do - @user.public_key("super public") - @user.public_key.should == "super public" - end - - it "should throw an ArgumentError if you feed it something lame" do - lambda { @user.public_key Hash.new }.should raise_error(ArgumentError) - end - end - - describe "private_key" do - it "should let you set the private key" do - @user.private_key("super private").should == "super private" - end - - it "should return the private key" do - @user.private_key("super private") - @user.private_key.should == "super private" - end - - it "should throw an ArgumentError if you feed it something lame" do - lambda { @user.private_key Hash.new }.should raise_error(ArgumentError) - end - end - - describe "when serializing to JSON" do - before(:each) do - @user.name("black") - @user.public_key("crowes") - @json = @user.to_json - end - - it "serializes as a JSON object" do - @json.should match(/^\{.+\}$/) - end - - it "includes the name value" do - @json.should include(%q{"name":"black"}) - end - - it "includes the public key value" do - @json.should include(%{"public_key":"crowes"}) - end - - it "includes the 'admin' flag" do - @json.should include(%q{"admin":false}) - end - - it "includes the private key when present" do - @user.private_key("monkeypants") - @user.to_json.should include(%q{"private_key":"monkeypants"}) - end - - it "does not include the private key if not present" do - @json.should_not include("private_key") - end - - it "includes the password if present" do - @user.password "password" - @user.to_json.should include(%q{"password":"password"}) - end - - it "does not include the password if not present" do - @json.should_not include("password") - end - end - - describe "when deserializing from JSON" do - before(:each) do - user = { "name" => "mr_spinks", - "public_key" => "turtles", - "private_key" => "pandas", - "password" => "password", - "admin" => true } - @user = Chef::User.from_json(user.to_json) - end - - it "should deserialize to a Chef::User object" do - @user.should be_a_kind_of(Chef::User) - end - - it "preserves the name" do - @user.name.should == "mr_spinks" - end - - it "preserves the public key" do - @user.public_key.should == "turtles" - end - - it "preserves the admin status" do - @user.admin.should be_true - end - - it "includes the private key if present" do - @user.private_key.should == "pandas" - end - - it "includes the password if present" do - @user.password.should == "password" - end - - end - - describe "API Interactions" do - before (:each) do - @user = Chef::User.new - @user.name "foobar" - @http_client = double("Chef::REST mock") - Chef::REST.stub(: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" }} ] - Chef::User.stub(:load).with("admin").and_return(@user) - @osc_inflated_response = { "admin" => @user } - end - - it "lists all clients on an OSC server" do - @http_client.stub(:get_rest).with("users").and_return(@osc_response) - Chef::User.list.should == @osc_response - end - - it "inflate all clients on an OSC server" do - @http_client.stub(:get_rest).with("users").and_return(@osc_response) - Chef::User.list(true).should == @osc_inflated_response - end - - it "lists all clients on an OHC/OPC server" do - @http_client.stub(:get_rest).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. - Chef::User.list.should == @osc_response - end - - it "inflate all clients on an OHC/OPC server" do - @http_client.stub(:get_rest).with("users").and_return(@ohc_response) - Chef::User.list(true).should == @osc_inflated_response - end - end - - describe "create" do - it "creates a new user via the API" do - @user.password "password" - @http_client.should_receive(:post_rest).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 - @http_client.should_receive(:get_rest).with("users/foobar").and_return({"name" => "foobar", "admin" => true, "public_key" => "pubkey"}) - user = Chef::User.load("foobar") - user.name.should == "foobar" - user.admin.should == true - user.public_key.should == "pubkey" - end - end - - describe "update" do - it "updates an existing user on via the API" do - @http_client.should_receive(:put_rest).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 - @http_client.should_receive(:delete_rest).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 deleted file mode 100644 index 617886cede..0000000000 --- a/spec/unit/util/backup_spec.rb +++ /dev/null @@ -1,142 +0,0 @@ -# -# Author:: Lamont Granquist (<lamont@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' -require 'tmpdir' - -describe Chef::Util::Backup do - - let (:tempfile) do - Tempfile.new("chef-util-backup-spec-test") - end - - before(:each) do - @new_resource = double("new_resource") - @new_resource.should_receive(:path).at_least(:once).and_return(tempfile.path) - @backup = Chef::Util::Backup.new(@new_resource) - end - - it "should store the resource passed to new as new_resource" do - @backup.new_resource.should eql(@new_resource) - end - - describe "for cases when we don't want to back anything up" do - - before(:each) do - @backup.should_not_receive(:do_backup) - end - - it "should not attempt to backup a file if :backup is false" do - @new_resource.should_receive(:backup).at_least(:once).and_return(false) - @backup.backup! - end - - it "should not attempt to backup a file if :backup == 0" do - @new_resource.should_receive(:backup).at_least(:once).and_return(0) - @backup.backup! - end - - it "should not attempt to backup a file if it does not exist" do - @new_resource.should_receive(:backup).at_least(:once).and_return(1) - File.should_receive(:exist?).with(tempfile.path).at_least(:once).and_return(false) - @backup.backup! - end - - end - - describe "for cases when we want to back things up" do - before(:each) do - @backup.should_receive(:do_backup) - end - - describe "when the number of backups is specified as 1" do - before(:each) do - @new_resource.should_receive(:backup).at_least(:once).and_return(1) - end - - it "should not delete anything if this is the only backup" do - @backup.should_receive(:sorted_backup_files).and_return(['a']) - @backup.should_not_receive(:delete_backup) - @backup.backup! - end - - it "should keep only 1 backup copy" do - @backup.should_receive(:sorted_backup_files).and_return(['a', 'b', 'c']) - @backup.should_receive(:delete_backup).with('b') - @backup.should_receive(:delete_backup).with('c') - @backup.backup! - end - end - - describe "when the number of backups is specified as 2" do - before(:each) do - @new_resource.should_receive(:backup).at_least(:once).and_return(2) - end - - it "should not delete anything if we only have one other backup" do - @backup.should_receive(:sorted_backup_files).and_return(['a', 'b']) - @backup.should_not_receive(:delete_backup) - @backup.backup! - end - - it "should keep only 2 backup copies" do - @backup.should_receive(:sorted_backup_files).and_return(['a', 'b', 'c', 'd']) - @backup.should_receive(:delete_backup).with('c') - @backup.should_receive(:delete_backup).with('d') - @backup.backup! - end - end - end - - describe "backup_filename" do - it "should return a timestamped path" do - @backup.should_receive(:path).and_return('/a/b/c.txt') - @backup.send(:backup_filename).should =~ %r|^/a/b/c.txt.chef-\d{14}.\d{6}$| - end - it "should strip the drive letter off for windows" do - @backup.should_receive(:path).and_return('c:\a\b\c.txt') - @backup.send(:backup_filename).should =~ %r|^\\a\\b\\c.txt.chef-\d{14}.\d{6}$| - end - it "should strip the drive letter off for windows (with forwardslashes)" do - @backup.should_receive(:path).and_return('c:/a/b/c.txt') - @backup.send(:backup_filename).should =~ %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 - @backup.should_receive(:path).and_return('/a/b/c.txt') - Chef::Config[:file_backup_path] = nil - @backup.send(:backup_path).should =~ %r|^/a/b/c.txt.chef-\d{14}.\d{6}$| - end - - it "uses the configured Chef::Config[:file_backup_path]" do - @backup.should_receive(:path).and_return('/a/b/c.txt') - Chef::Config[:file_backup_path] = '/backupdir' - @backup.send(:backup_path).should =~ %r|^/backupdir[\\/]+a/b/c.txt.chef-\d{14}.\d{6}$| - end - - it "uses the configured Chef::Config[:file_backup_path] and strips the drive on windows" do - @backup.should_receive(:path).and_return('c:\\a\\b\\c.txt') - Chef::Config[:file_backup_path] = 'c:\backupdir' - @backup.send(:backup_path).should =~ %r|^c:\\backupdir[\\/]+a\\b\\c.txt.chef-\d{14}.\d{6}$| - end - end - -end diff --git a/spec/unit/util/diff_spec.rb b/spec/unit/util/diff_spec.rb deleted file mode 100644 index 947ce1d5aa..0000000000 --- a/spec/unit/util/diff_spec.rb +++ /dev/null @@ -1,579 +0,0 @@ -# -# Author:: Lamont Granquist (<lamont@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' -require 'tmpdir' - -shared_context "using file paths with spaces" do - let!(:old_tempfile) { Tempfile.new("chef-util diff-spec") } - let!(:new_tempfile) { Tempfile.new("chef-util diff-spec") } -end - -shared_context "using file paths without spaces" do - let!(:old_tempfile) { Tempfile.new("chef-util-diff-spec") } - let!(:new_tempfile) { Tempfile.new("chef-util-diff-spec") } -end - -shared_examples_for "a diff util" do - it "should return a Chef::Util::Diff" do - expect(differ).to be_a_kind_of(Chef::Util::Diff) - end - - it "produces a diff even if the old_file does not exist" do - old_tempfile.close - old_tempfile.unlink - expect(differ.for_output).to eql(["(no diff)"]) - end - - it "produces a diff even if the new_file does not exist" do - new_tempfile.close - new_tempfile.unlink - expect(differ.for_output).to eql(["(no diff)"]) - end - - describe "when the two files exist with no content" do - it "calling for_output should return the error message" do - expect(differ.for_output).to eql(["(no diff)"]) - end - - it "calling for_reporting should be nil" do - expect(differ.for_reporting).to be_nil - end - end - - describe "when diffs are disabled" do - before do - Chef::Config[:diff_disabled] = true - end - - after do - Chef::Config[:diff_disabled] = false - end - - it "calling for_output should return the error message" do - expect(differ.for_output).to eql( [ "(diff output suppressed by config)" ] ) - end - - it "calling for_reporting should be nil" do - expect(differ.for_reporting).to be_nil - end - end - - describe "when the old_file has binary content" do - before do - old_tempfile.write("\x01\xff") - old_tempfile.close - end - - it "calling for_output should return the error message" do - expect(differ.for_output).to eql( [ "(current file is binary, diff output suppressed)" ] ) - end - - it "calling for_reporting should be nil" do - expect(differ.for_reporting).to be_nil - end - end - - describe "when the new_file has binary content" do - before do - new_tempfile.write("\x01\xff") - new_tempfile.close - end - - it "calling for_output should return the error message" do - expect(differ.for_output).to eql( [ "(new content is binary, diff output suppressed)" ]) - end - - it "calling for_reporting should be nil" do - expect(differ.for_reporting).to be_nil - end - end - - describe "when the default external encoding is UTF-8", :ruby_gte_19_only do - - before do - @saved_default_external = Encoding.default_external - Encoding.default_external = Encoding::UTF_8 - end - - after do - Encoding.default_external = @saved_default_external - end - - describe "when a file has ASCII text" do - before do - new_tempfile.write(plain_ascii) - new_tempfile.close - end - it "calling for_output should return a valid diff" do - differ.for_output.join("\\n").should match(/\A--- .*\\n\+\+\+ .*\\n@@/m) - end - it "calling for_reporting should return a utf-8 string" do - expect(differ.for_reporting.encoding).to equal(Encoding::UTF_8) - end - end - - describe "when a file has UTF-8 text" do - before do - new_tempfile.write(utf_8) - new_tempfile.close - end - it "calling for_output should return a valid diff" do - differ.for_output.join("\\n").should match(/\A--- .*\\n\+\+\+ .*\\n@@/m) - end - it "calling for_reporting should return a utf-8 string" do - expect(differ.for_reporting.encoding).to equal(Encoding::UTF_8) - end - end - - describe "when a file has Latin-1 text" do - before do - new_tempfile.write(latin_1) - new_tempfile.close - end - it "calling for_output should complain that the content is binary" do - expect(differ.for_output).to eql( [ "(new content is binary, diff output suppressed)" ]) - end - it "calling for_reporting should be nil" do - expect(differ.for_reporting).to be_nil - end - end - - describe "when a file has Shift-JIS text" do - before do - new_tempfile.write(shift_jis) - new_tempfile.close - end - it "calling for_output should complain that the content is binary" do - expect(differ.for_output).to eql( [ "(new content is binary, diff output suppressed)" ]) - end - it "calling for_reporting should be nil" do - expect(differ.for_reporting).to be_nil - end - end - - end - - describe "when the default external encoding is Latin-1", :ruby_gte_19_only do - - before do - @saved_default_external = Encoding.default_external - Encoding.default_external = Encoding::ISO_8859_1 - end - - after do - Encoding.default_external = @saved_default_external - end - - describe "when a file has ASCII text" do - before do - new_tempfile.write(plain_ascii) - new_tempfile.close - end - it "calling for_output should return a valid diff" do - differ.for_output.join("\\n").should match(/\A--- .*\\n\+\+\+ .*\\n@@/m) - end - it "calling for_reporting should return a utf-8 string" do - expect(differ.for_reporting.encoding).to equal(Encoding::UTF_8) - end - end - - describe "when a file has UTF-8 text" do - before do - new_tempfile.write(utf_8) - new_tempfile.close - end - it "calling for_output should complain that the content is binary" do - expect(differ.for_output).to eql( [ "(new content is binary, diff output suppressed)" ]) - end - it "calling for_reporting should be nil" do - expect(differ.for_reporting).to be_nil - end - end - - describe "when a file has Latin-1 text" do - before do - new_tempfile.write(latin_1) - new_tempfile.close - end - it "calling for_output should return a valid diff" do - differ.for_output.join("\\n").should match(/\A--- .*\\n\+\+\+ .*\\n@@/m) - end - it "calling for_reporting should return a utf-8 string" do - expect(differ.for_reporting.encoding).to equal(Encoding::UTF_8) - end - end - - describe "when a file has Shift-JIS text" do - before do - new_tempfile.write(shift_jis) - new_tempfile.close - end - it "calling for_output should complain that the content is binary" do - expect(differ.for_output).to eql( [ "(new content is binary, diff output suppressed)" ]) - end - it "calling for_reporting should be nil" do - expect(differ.for_reporting).to be_nil - end - end - - end - describe "when the default external encoding is Shift_JIS", :ruby_gte_19_only do - - before do - @saved_default_external = Encoding.default_external - Encoding.default_external = Encoding::Shift_JIS - end - - after do - Encoding.default_external = @saved_default_external - end - - describe "when a file has ASCII text" do - before do - new_tempfile.write(plain_ascii) - new_tempfile.close - end - it "calling for_output should return a valid diff" do - differ.for_output.join("\\n").should match(/\A--- .*\\n\+\+\+ .*\\n@@/m) - end - it "calling for_reporting should return a utf-8 string" do - expect(differ.for_reporting.encoding).to equal(Encoding::UTF_8) - end - end - - describe "when a file has UTF-8 text" do - before do - new_tempfile.write(utf_8) - new_tempfile.close - end - it "calling for_output should complain that the content is binary" do - expect(differ.for_output).to eql( [ "(new content is binary, diff output suppressed)" ]) - end - it "calling for_reporting should be nil" do - expect(differ.for_reporting).to be_nil - end - end - - describe "when a file has Latin-1 text" do - before do - new_tempfile.write(latin_1) - new_tempfile.close - end - it "calling for_output should complain that the content is binary" do - expect(differ.for_output).to eql( [ "(new content is binary, diff output suppressed)" ]) - end - it "calling for_reporting should be nil" do - expect(differ.for_reporting).to be_nil - end - end - - describe "when a file has Shift-JIS text" do - before do - new_tempfile.write(shift_jis) - new_tempfile.close - end - it "calling for_output should return a valid diff" do - differ.for_output.join("\\n").should match(/\A--- .*\\n\+\+\+ .*\\n@@/m) - end - it "calling for_reporting should return a utf-8 string" do - expect(differ.for_reporting.encoding).to equal(Encoding::UTF_8) - end - end - - end - - describe "when testing the diff_filesize_threshold" do - before do - @diff_filesize_threshold_saved = Chef::Config[:diff_filesize_threshold] - Chef::Config[:diff_filesize_threshold] = 10 - end - - after do - Chef::Config[:diff_filesize_threshold] = @diff_filesize_threshold_saved - end - - describe "when the old_file goes over the threshold" do - before do - old_tempfile.write("But thats what you get when Wu-Tang raised you") - old_tempfile.close - end - - it "calling for_output should return the error message" do - expect(differ.for_output).to eql( [ "(file sizes exceed 10 bytes, diff output suppressed)" ]) - end - - it "calling for_reporting should be nil" do - expect(differ.for_reporting).to be_nil - end - end - - describe "when the new_file goes over the threshold" do - before do - new_tempfile.write("But thats what you get when Wu-Tang raised you") - new_tempfile.close - end - - it "calling for_output should return the error message" do - expect(differ.for_output).to eql( [ "(file sizes exceed 10 bytes, diff output suppressed)" ]) - end - - it "calling for_reporting should be nil" do - expect(differ.for_reporting).to be_nil - end - end - end - - describe "when generating a valid diff" do - before do - old_tempfile.write("foo") - old_tempfile.close - new_tempfile.write("bar") - new_tempfile.close - end - - it "calling for_output should return a unified diff" do - differ.for_output.size.should eql(5) - differ.for_output.join("\\n").should match(/\A--- .*\\n\+\+\+ .*\\n@@/m) - end - - it "calling for_reporting should return a unified diff" do - differ.for_reporting.should match(/\A--- .*\\n\+\+\+ .*\\n@@/m) - end - - describe "when the diff output is too long" do - - before do - @diff_output_threshold_saved = Chef::Config[:diff_output_threshold] - Chef::Config[:diff_output_threshold] = 10 - end - - after do - Chef::Config[:diff_output_threshold] = @diff_output_threshold_saved - end - - it "calling for_output should return the error message" do - expect(differ.for_output).to eql(["(long diff of over 10 characters, diff output suppressed)"]) - end - - it "calling for_reporting should be nil" do - expect(differ.for_reporting).to be_nil - end - end - end - - describe "when checking if files are binary or text" do - - it "should identify zero-length files as text" do - Tempfile.open("chef-util-diff-spec") do |file| - file.close - differ.send(:is_binary?, file.path).should be_false - end - end - - it "should identify text files as text" do - Tempfile.open("chef-util-diff-spec") do |file| - file.write(plain_ascii) - file.close - differ.send(:is_binary?, file.path).should be_false - end - end - - it "should identify a null-terminated string files as binary" do - Tempfile.open("chef-util-diff-spec") do |file| - file.write("This is a binary file.\0") - file.close - differ.send(:is_binary?, file.path).should be_true - end - end - - it "should identify null-teriminated multi-line string files as binary" do - Tempfile.open("chef-util-diff-spec") do |file| - file.write("This is a binary file.\nNo Really\nit is\0") - file.close - differ.send(:is_binary?, file.path).should be_true - end - end - - describe "when the default external encoding is UTF-8", :ruby_gte_19_only do - - before do - @saved_default_external = Encoding.default_external - Encoding.default_external = Encoding::UTF_8 - end - - after do - Encoding.default_external = @saved_default_external - end - - it "should identify normal ASCII as text" do - Tempfile.open("chef-util-diff-spec") do |file| - file.write(plain_ascii) - file.close - differ.send(:is_binary?, file.path).should be_false - end - end - - it "should identify UTF-8 as text" do - Tempfile.open("chef-util-diff-spec") do |file| - file.write(utf_8) - file.close - differ.send(:is_binary?, file.path).should be_false - end - end - - it "should identify Latin-1 that is invalid UTF-8 as binary" do - Tempfile.open("chef-util-diff-spec") do |file| - file.write(latin_1) - file.close - differ.send(:is_binary?, file.path).should be_true - end - end - - it "should identify Shift-JIS that is invalid UTF-8 as binary" do - Tempfile.open("chef-util-diff-spec") do |file| - file.write(shift_jis) - file.close - differ.send(:is_binary?, file.path).should be_true - end - end - - end - - describe "when the default external encoding is Latin-1", :ruby_gte_19_only do - - before do - @saved_default_external = Encoding.default_external - Encoding.default_external = Encoding::ISO_8859_1 - end - - after do - Encoding.default_external = @saved_default_external - end - - it "should identify normal ASCII as text" do - Tempfile.open("chef-util-diff-spec") do |file| - file.write(plain_ascii) - file.close - differ.send(:is_binary?, file.path).should be_false - end - end - - it "should identify UTF-8 that is invalid Latin-1 as binary" do - Tempfile.open("chef-util-diff-spec") do |file| - file.write(utf_8) - file.close - differ.send(:is_binary?, file.path).should be_true - end - end - - it "should identify Latin-1 as text" do - Tempfile.open("chef-util-diff-spec") do |file| - file.write(latin_1) - file.close - differ.send(:is_binary?, file.path).should be_false - end - end - - it "should identify Shift-JIS that is invalid Latin-1 as binary" do - Tempfile.open("chef-util-diff-spec") do |file| - file.write(shift_jis) - file.close - differ.send(:is_binary?, file.path).should be_true - end - end - end - - describe "when the default external encoding is Shift-JIS", :ruby_gte_19_only do - - before do - @saved_default_external = Encoding.default_external - Encoding.default_external = Encoding::Shift_JIS - end - - after do - Encoding.default_external = @saved_default_external - end - - it "should identify normal ASCII as text" do - Tempfile.open("chef-util-diff-spec") do |file| - file.write(plain_ascii) - file.close - differ.send(:is_binary?, file.path).should be_false - end - end - it "should identify UTF-8 that is invalid Shift-JIS as binary" do - Tempfile.open("chef-util-diff-spec") do |file| - file.write(utf_8) - file.close - differ.send(:is_binary?, file.path).should be_true - end - end - - it "should identify Latin-1 that is invalid Shift-JIS as binary" do - Tempfile.open("chef-util-diff-spec") do |file| - file.write(latin_1) - file.close - differ.send(:is_binary?, file.path).should be_true - end - end - - it "should identify Shift-JIS as text" do - Tempfile.open("chef-util-diff-spec") do |file| - file.write(shift_jis) - file.close - differ.send(:is_binary?, file.path).should be_false - end - end - - end - end - -end - -describe Chef::Util::Diff, :uses_diff => true do - let!(:old_file) { old_tempfile.path } - let!(:new_file) { new_tempfile.path } - - 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(: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 - differ = Chef::Util::Diff.new - differ.diff(old_file, new_file) - differ - end - - describe "when file path has spaces" do - include_context "using file paths with spaces" - - 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 deleted file mode 100644 index 03f3ffe25c..0000000000 --- a/spec/unit/util/dsc/configuration_generator_spec.rb +++ /dev/null @@ -1,171 +0,0 @@ -# -# Author:: Jay Mundrawala <jmundrawala@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 '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') - end - - describe '#validate_configuration_name!' 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 - conf_man.send(:validate_configuration_name!, "hello") - end - - it 'should not raise an error if no special characters are used except _' do - conf_man.send(:validate_configuration_name!, "hello_world") - end - - %w{! @ # $ % ^ & * & * ( ) - = + \{ \} . ? < > \\ /}.each do |sym| - it "raises an Argument error if it configuration name contains #{sym}" do - expect { - conf_man.send(:validate_configuration_name!, "Hello#{sym}") - }.to raise_error(ArgumentError) - end - end - 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') - merged.should include(:flag) - merged[:flag].should eql('a') - merged.should include(:outputpath) - end - - it 'should raise an ArgumentError if you try to override outputpath' do - expect { - 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 - expect { - 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') - merged.should 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') - merged.should include(:flag) - merged[:flag].should eql('a') - merged.should include(:outputpath) - end - - it 'should raise an ArgumentError if you try to override outputpath' do - expect { - 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 - expect { - 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') - merged.should 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') - merged.should include(:outputpath) - merged.length.should 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') - merged.should include(:outputpath) - merged.length.should eql(1) - end - end - - # What should happen if configuration flags contains duplicates? - # flagA => 'a', flaga => 'a' - # or - # flagA => 'a', flaga => 'b' - # - end - - describe '#write_document_generation_script' do - let(:file_like_object) { double("file like object") } - - 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("++") - end - allow(file_like_object).to receive(:write) - conf_man.send(:write_document_generation_script, 'file', 'hello') - expect(file_like_object).to have_received(:write) - end - end - - describe "#find_configuration_document" do - it "should find the mof file" do - # These tests seem way too implementation specific. Unfortunatly, File and Dir - # need to be mocked because they are OS specific - allow(File).to receive(:join) do |a, b| - [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') - end - - it "should return nil if the mof file is not found" do - allow(File).to receive(:join) do |a, b| - [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 - end - end - - describe "#configuration_code" do - it "should build dsc" do - dsc = conf_man.send(:configuration_code, 'archive{}', 'hello') - found_configuration = false - 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 - end - expect(found_configuration).to be_true - 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 deleted file mode 100644 index 23a3dbd3ec..0000000000 --- a/spec/unit/util/dsc/lcm_output_parser_spec.rb +++ /dev/null @@ -1,169 +0,0 @@ -# -# Author:: Bryan McLellan <btm@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/dsc/lcm_output_parser' - -describe Chef::Util::DSC::LocalConfigurationManager::Parser do - context 'empty input parameter' do - it 'returns an empty array for a 0 length string' do - Chef::Util::DSC::LocalConfigurationManager::Parser::parse('').should be_empty - end - - it 'returns an empty array for a nil input' do - Chef::Util::DSC::LocalConfigurationManager::Parser::parse('').should be_empty - end - end - - context 'correctly formatted output from lcm' do - it 'returns an empty array for a log with no resources' do - str = <<EOF -logtype: [machinename]: LCM: [ Start Set ] -logtype: [machinename]: LCM: [ End Set ] -EOF - Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str).should be_empty - end - - 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] -logtype: [machinename]: LCM: [ End Resource ] [name] -logtype: [machinename]: LCM: [ End Set ] -EOF - resources = Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str) - resources.length.should eq(1) - resources[0].name.should eq('[name]') - end - - 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] -logtype: [machinename]: LCM: [ Start Set ] [name] -logtype: [machinename]: LCM: [ End Set ] [name] -logtype: [machinename]: LCM: [ End Resource ] [name] -logtype: [machinename]: LCM: [ End Set ] -EOF - resources = Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str) - resources[0].changes_state?.should be_true - end - - 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] -logtype: [machinename]: LCM: [ Start Set ] [name] -logtype: [machinename]: [message] -logtype: [machinename]: LCM: [ End Set ] [name] -logtype: [machinename]: LCM: [ End Resource ] [name] -logtype: [machinename]: LCM: [ End Set ] -EOF - resources = Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str) - resources[0].change_log.should match_array(["[name]","[message]","[name]"]) - end - - it 'should return false for changes_state?' do - str = <<EOF -logtype: [machinename]: LCM: [ Start Set ] -logtype: [machinename]: LCM: [ Start Resource ] [name] -logtype: [machinename]: LCM: [ Skip Set ] [name] -logtype: [machinename]: LCM: [ End Resource ] [name] -logtype: [machinename]: LCM: [ End Set ] -EOF - resources = Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str) - resources[0].changes_state?.should be_false - end - - 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] -logtype: [machinename]: LCM: [ Skip Set ] [name] -logtype: [machinename]: LCM: [ End Resource ] [name] -logtype: [machinename]: LCM: [ End Set ] -EOF - resources = Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str) - resources[0].change_log.should be_empty - 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 - str = <<-EOF -logtype: [machinename]: LCM: [ Start Set ] -logtype: [machinename]: LCM: [ Start Resource ] [name] -logtype: [machinename]: LCM: [ Start Test ] -logtype: [machinename]: LCM: [ End Test ] -logtype: [machinename]: LCM: [ Skip Set ] -logtype: [machinename]: LCM: [ End Resource ] -logtype: [machinename]: LCM: [ Start Resource ] [name2] -logtype: [machinename]: LCM: [ Start Test ] -logtype: [machinename]: LCM: [ End Test ] -logtype: [machinename]: LCM: [ Start Set ] -logtype: [machinename]: LCM: [ End Set ] -logtype: [machinename]: LCM: [ End Set ] -EOF - - resources = Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str) - resources[0].changes_state?.should be_false - resources[1].changes_state?.should be_true - end - - 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] -logtype: [machinename]: LCM: [ Start Test ] -logtype: [machinename]: LCM: [ End Test ] -logtype: [machinename]: LCM: [ Skip Set ] -logtype: [machinename]: LCM: [ Start Resource ] [name2] -logtype: [machinename]: LCM: [ Start Test ] -logtype: [machinename]: LCM: [ End Test ] -logtype: [machinename]: LCM: [ Start Set ] -logtype: [machinename]: LCM: [ End Set ] -logtype: [machinename]: LCM: [ End Resource ] -logtype: [machinename]: LCM: [ End Set ] -EOF - - resources = Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str) - resources[0].changes_state?.should be_false - resources[1].changes_state?.should be_true - end - - 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] -logtype: [machinename]: LCM: [ Start Test ] -logtype: [machinename]: LCM: [ End Test ] -logtype: [machinename]: LCM: [ Start Resource ] [name2] -logtype: [machinename]: LCM: [ Start Test ] -logtype: [machinename]: LCM: [ End Test ] -logtype: [machinename]: LCM: [ Start Set ] -logtype: [machinename]: LCM: [ End Set ] -logtype: [machinename]: LCM: [ End Resource ] -logtype: [machinename]: LCM: [ End Set ] -EOF - resources = Chef::Util::DSC::LocalConfigurationManager::Parser::parse(str) - resources[0].changes_state?.should be_true - resources[0].name.should eql('[name]') - resources[1].changes_state?.should be_true - resources[1].name.should 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 deleted file mode 100644 index fb6664bd40..0000000000 --- a/spec/unit/util/dsc/local_configuration_manager_spec.rb +++ /dev/null @@ -1,134 +0,0 @@ -# -# Author:: Adam Edwards <adamed@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 'chef' -require 'chef/util/dsc/local_configuration_manager' - -describe Chef::Util::DSC::LocalConfigurationManager do - - let(:lcm) { Chef::Util::DSC::LocalConfigurationManager.new(nil, 'tmp') } - - let(:normal_lcm_output) { <<-EOH -logtype: [machinename]: LCM: [ Start Set ] -logtype: [machinename]: LCM: [ Start Resource ] [name] -logtype: [machinename]: LCM: [ End Resource ] [name] -logtype: [machinename]: LCM: [ End Set ] -EOH - } - - let(:no_whatif_lcm_output) { <<-EOH -Start-DscConfiguration : A parameter cannot be found that matches parameter name 'whatif'. -At line:1 char:123 -+ run-somecommand -whatif -+ ~~~~~~~~ - + CategoryInfo : InvalidArgument: (:) [Start-DscConfiguration], ParameterBindingException - + FullyQualifiedErrorId : NamedParameterNotFound,SomeCompany.SomeAssembly.Commands.RunSomeCommand -EOH - } - - let(:dsc_resource_import_failure_output) { <<-EOH -PowerShell provider MSFT_xWebsite failed to execute Test-TargetResource functionality with error message: Please ensure that WebAdministration module is installed. + CategoryInfo : InvalidOperation: (:) [], CimException + FullyQualifiedErrorId : ProviderOperationExecutionFailure + PSComputerName : . PowerShell provider MSFT_xWebsite failed to execute Test-TargetResource functionality with error message: Please ensure that WebAdministration module is installed. + CategoryInfo : InvalidOperation: (:) [], CimException + FullyQualifiedErrorId : ProviderOperationExecutionFailure + PSComputerName : . The SendConfigurationApply function did not succeed. + CategoryInfo : NotSpecified: (root/Microsoft/...gurationManager:String) [], CimException + FullyQualifiedErrorId : MI RESULT 1 + PSComputerName : . -EOH - } - - let(:lcm_status) { - 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 - before(:each) do - allow(lcm).to receive(:run_configuration_cmdlet).and_return(lcm_status) - end - context 'that returns successfully' do - before(:each) do - allow(lcm).to receive(:run_configuration_cmdlet).and_return(lcm_status) - end - - let(:lcm_standard_output) { normal_lcm_output } - 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') - 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) { '' } - let(:lcm_standard_error) { no_whatif_lcm_output } - let(:lcm_cmdlet_success) { false } - - it 'should should return a (possibly empty) array of ResourceInfo instances' do - expect(Chef::Log).to receive(:warn) - test_configuration_result = nil - 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) { '' } - 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 - expect(Chef::Log).to receive(:warn) - expect(lcm).to receive(:output_has_dsc_module_failure?).and_call_original - test_configuration_result = nil - expect {test_configuration_result = lcm.test_configuration('config')}.not_to raise_error - end - - it 'should return a (possibly empty) array of ResourceInfo instances' do - expect(Chef::Log).to receive(:warn) - test_configuration_result = nil - 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 PowerShell cmdlet error that cannot be handled' do - let(:lcm_standard_output) { 'some output' } - let(:lcm_standard_error) { 'Abort, Retry, Fail?' } - let(:lcm_cmdlet_success) { false } - - it 'should raise a Chef::Exceptions::PowershellCmdletException' do - expect(Chef::Log).not_to receive(:warn) - expect(lcm).to receive(:output_has_dsc_module_failure?).and_call_original - expect {lcm.test_configuration('config')}.to raise_error(Chef::Exceptions::PowershellCmdletException) - end - end - end - - it 'should identify a correctly formatted error message as a resource import failure' do - expect(lcm.send(:output_has_dsc_module_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(:output_has_dsc_module_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(:output_has_dsc_module_failure?, dsc_resource_import_failure_output.gsub('CimException', 'ArgumentException'))).to be(false) - end - end -end - diff --git a/spec/unit/util/editor_spec.rb b/spec/unit/util/editor_spec.rb deleted file mode 100644 index 06370f7de0..0000000000 --- a/spec/unit/util/editor_spec.rb +++ /dev/null @@ -1,152 +0,0 @@ -require 'spec_helper' -require 'chef/util/editor' - -describe Chef::Util::Editor do - describe '#initialize' 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 - array = Array.new - editor = described_class.new(array) - expect(editor.lines).to_not be(array) - end - end - - subject(:editor) { described_class.new(input_lines) } - 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') } - - it('returns the number of added lines') { should be == 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') } - - it('returns the number of added lines') { should be == 2 } - it 'adds a line after each match' do - execute - 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 - end - end - - describe '#append_line_if_missing' do - context 'when there is no match' do - subject(:execute) { editor.append_line_if_missing('missing', 'new') } - - it('returns the number of added lines') { should be == 1 } - it 'adds a line to the end' do - execute - 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') } - - it('returns the number of added lines') { should be == 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 - end - end - - describe '#remove_lines' do - context 'when there is no match' do - subject(:execute) { editor.remove_lines('missing') } - - it('returns the number of removed lines') { should be == 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') } - - it('returns the number of removed lines') { should be == 2 } - it 'removes the matching lines' do - execute - expect(editor.lines).to be == ['one', 'three'] - end - end - - 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') } - - it('returns the number of changed lines') { should be == 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') } - - it('returns the number of changed lines') { should be == 2 } - it 'replaces the matching portions' do - execute - 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'] - end - end - - describe '#replace_lines' do - context 'when there is no match' do - subject(:execute) { editor.replace_lines('missing', 'new') } - - it('returns the number of changed lines') { should be == 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') } - - it('returns the number of replaced lines') { should be == 2 } - it 'replaces the matching line' do - execute - 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'] - end - end -end diff --git a/spec/unit/util/file_edit_spec.rb b/spec/unit/util/file_edit_spec.rb deleted file mode 100644 index 139b29d9ce..0000000000 --- a/spec/unit/util/file_edit_spec.rb +++ /dev/null @@ -1,224 +0,0 @@ -# -# Author:: Nuo Yan (<nuo@opscode.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 'tempfile' - -describe Chef::Util::FileEdit do - - let(:starting_content) do - <<-EOF -127.0.0.1 localhost -255.255.255.255 broadcasthost -::1 localhost -fe80::1%lo0 localhost - EOF - end - - let(:localhost_replaced) do - <<-EOF -127.0.0.1 replacement -255.255.255.255 broadcasthost -::1 replacement -fe80::1%lo0 replacement - EOF - end - - let(:localhost_line_replaced) do - <<-EOF -replacement line -255.255.255.255 broadcasthost -replacement line -replacement line - EOF - end - - let(:localhost_deleted) do - # sensitive to deliberate trailing whitespace - "127.0.0.1 \n255.255.255.255 broadcasthost\n::1 \nfe80::1%lo0 \n" - end - - let(:localhost_line_deleted) do - <<-EOF -255.255.255.255 broadcasthost - EOF - end - - let(:append_after_all_localhost) do - <<-EOF -127.0.0.1 localhost -new line inserted -255.255.255.255 broadcasthost -::1 localhost -new line inserted -fe80::1%lo0 localhost -new line inserted - EOF - end - - let(:append_after_content) do - <<-EOF -127.0.0.1 localhost -255.255.255.255 broadcasthost -::1 localhost -fe80::1%lo0 localhost -new line inserted - EOF - end - - let(:append_twice) do - <<-EOF -127.0.0.1 localhost -255.255.255.255 broadcasthost -::1 localhost -fe80::1%lo0 localhost -once -twice - EOF - end - - let(:target_file) do - f = Tempfile.open('file_edit_spec') - f.write(starting_content) - f.close - f - end - - let(:fedit) { Chef::Util::FileEdit.new(target_file.path) } - - after(:each) do - target_file.close! - end - - describe "initialiize" do - it "should create a new Chef::Util::FileEdit object" do - expect(fedit).to be_instance_of(Chef::Util::FileEdit) - end - - it "should throw an exception if the input file does not exist" do - expect{Chef::Util::FileEdit.new("nonexistfile")}.to raise_error(ArgumentError) - end - - # CHEF-5018: people have monkey patched this and it has accidentally been broken - it "should read the contents into memory as an array" do - expect(fedit.send(:editor).lines).to be_instance_of(Array) - end - end - - describe "when the file is blank" do - let(:hosts_content) { "" } - - it "should not throw an exception" do - expect{ fedit }.not_to raise_error - end - end - - def edited_file_contents - IO.read(target_file.path) - end - - describe "search_file_replace" do - it "should accept regex passed in as a string (not Regexp object) and replace the match if there is one" do - fedit.search_file_replace("localhost", "replacement") - fedit.unwritten_changes?.should be_true - fedit.write_file - expect(edited_file_contents).to eq(localhost_replaced) - end - - it "should accept regex passed in as a Regexp object and replace the match if there is one" do - fedit.search_file_replace(/localhost/, "replacement") - fedit.unwritten_changes?.should be_true - fedit.write_file - expect(edited_file_contents).to eq(localhost_replaced) - end - - it "should do nothing if there isn't a match" do - fedit.search_file_replace(/pattern/, "replacement") - fedit.unwritten_changes?.should be_false - fedit.write_file - expect(edited_file_contents).to eq(starting_content) - end - end - - describe "search_file_replace_line" do - it "should search for match and replace the whole line" do - fedit.search_file_replace_line(/localhost/, "replacement line") - fedit.unwritten_changes?.should be_true - fedit.write_file - expect(edited_file_contents).to eq(localhost_line_replaced) - end - end - - describe "search_file_delete" do - it "should search for match and delete the match" do - fedit.search_file_delete(/localhost/) - fedit.unwritten_changes?.should be_true - fedit.write_file - expect(edited_file_contents).to eq(localhost_deleted) - end - end - - describe "search_file_delete_line" do - it "should search for match and delete the matching line" do - fedit.search_file_delete_line(/localhost/) - fedit.unwritten_changes?.should be_true - fedit.write_file - expect(edited_file_contents).to eq(localhost_line_deleted) - end - end - - describe "insert_line_after_match" do - it "should search for match and insert the given line after the matching line" do - fedit.insert_line_after_match(/localhost/, "new line inserted") - fedit.unwritten_changes?.should be_true - fedit.write_file - expect(edited_file_contents).to eq(append_after_all_localhost) - end - end - - describe "insert_line_if_no_match" do - it "should search for match and insert the given line if no line match" do - fedit.insert_line_if_no_match(/pattern/, "new line inserted") - fedit.unwritten_changes?.should be_true - fedit.write_file - expect(edited_file_contents).to eq(append_after_content) - end - - it "should do nothing if there is a match" do - fedit.insert_line_if_no_match(/localhost/, "replacement") - fedit.unwritten_changes?.should be_false - fedit.write_file - expect(edited_file_contents).to eq(starting_content) - end - - it "should work more than once" do - fedit.insert_line_if_no_match(/missing/, "once") - fedit.insert_line_if_no_match(/missing/, "twice") - fedit.write_file - expect(edited_file_contents).to eq(append_twice) - end - end - - describe "file_edited" do - it "should return true if a file got edited" do - fedit.insert_line_if_no_match(/pattern/, "new line inserted") - fedit.write_file - expect(fedit.file_edited?).to be_true - end - 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 1d97efc607..0000000000 --- a/spec/unit/util/path_helper_spec.rb +++ /dev/null @@ -1,241 +0,0 @@ -# -# Author:: Bryan McLellan <btm@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 - Chef::Platform.stub(: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 - PathHelper.join(is_windows ? 'C:\\foo\\' : "/foo/", "bar", "baz").should == 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 - PathHelper.join(is_windows ? 'C:\\foo\\' : "/foo/", "bar/", "/baz").should == expected - end - - it "joins components that don't end in separators" do - expected = PathHelper.cleanpath("/foo/bar/baz") - expected = "C:#{expected}" if is_windows - PathHelper.join(is_windows ? 'C:\\foo' : "/foo", "bar", "baz").should == expected - end - - it "joins starting with '' resolve to absolute paths" do - PathHelper.join('', 'a', 'b').should == "#{PathHelper.path_separator}a#{PathHelper.path_separator}b" - end - - it "joins ending with '' add a / to the end" do - PathHelper.join('a', 'b', '').should == "a#{PathHelper.path_separator}b#{PathHelper.path_separator}" - end - - if is_windows - it "joins components on Windows when some end with unix separators" do - PathHelper.join('C:\\foo/', "bar", "baz").should == 'C:\\foo\\bar\\baz' - end - end - end - - if is_windows - it "path_separator is \\" do - PathHelper.path_separator.should == '\\' - end - else - it "path_separator is /" do - PathHelper.path_separator.should == '/' - end - end - - if is_windows - it "cleanpath changes slashes into backslashes and leaves backslashes alone" do - PathHelper.cleanpath('/a/b\\c/d/').should == '\\a\\b\\c\\d' - end - it "cleanpath does not remove leading double backslash" do - PathHelper.cleanpath('\\\\a/b\\c/d/').should == '\\\\a\\b\\c\\d' - end - else - it "cleanpath removes extra slashes alone" do - PathHelper.cleanpath('/a///b/c/d/').should == '/a/b/c/d' - end - end - - describe "dirname" do - it "dirname('abc') is '.'" do - PathHelper.dirname('abc').should == '.' - end - it "dirname('/') is '/'" do - PathHelper.dirname(PathHelper.path_separator).should == PathHelper.path_separator - end - it "dirname('a/b/c') is 'a/b'" do - PathHelper.dirname(PathHelper.join('a', 'b', 'c')).should == PathHelper.join('a', 'b') - end - it "dirname('a/b/c/') is 'a/b'" do - PathHelper.dirname(PathHelper.join('a', 'b', 'c', '')).should == PathHelper.join('a', 'b') - end - it "dirname('/a/b/c') is '/a/b'" do - PathHelper.dirname(PathHelper.join('', 'a', 'b', 'c')).should == PathHelper.join('', 'a', 'b') - end - end - end - end - - describe "validate_path" do - context "on windows" do - before(:each) do - # pass by default - Chef::Platform.stub(:windows?).and_return(true) - PathHelper.stub(:printable?).and_return(true) - PathHelper.stub(: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 - PathHelper.stub(: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 - PathHelper.stub(: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_true - 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_false - 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_false - 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_true - end - - it "returns true when given 'abc' in unicode" do - expect(PathHelper.printable?("\u0061\u0062\u0063")).to be_true - end - - it "returns true when given japanese unicode" do - expect(PathHelper.printable?("\uff86\uff87\uff88")).to be_true - end - - it "returns false if the string contains a non-printable character" do - expect(PathHelper.printable?("\my files\work\notes.txt")).to be_false - 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_false - 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 - context "ruby is at least 1.9", :ruby_gte_19_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 - - context "ruby is less than 1.9", :ruby_18_only do - it "returns a canonical path" do - expect { PathHelper.canonical_path("/etc//apache.d/sites-enabled/../sites-available/default") }.to raise_error(NotImplementedError) - end - end - end - end - - describe "paths_eql?" do - it "returns true if the paths are the same" do - PathHelper.stub(:canonical_path).with("bandit").and_return("c:/bandit/bandit") - PathHelper.stub(:canonical_path).with("../bandit/bandit").and_return("c:/bandit/bandit") - expect(PathHelper.paths_eql?("bandit", "../bandit/bandit")).to be_true - end - - it "returns false if the paths are different" do - PathHelper.stub(:canonical_path).with("bandit").and_return("c:/Bo/Bandit") - PathHelper.stub(:canonical_path).with("../bandit/bandit").and_return("c:/bandit/bandit") - expect(PathHelper.paths_eql?("bandit", "../bandit/bandit")).to be_false - 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 -end diff --git a/spec/unit/util/powershell/cmdlet_spec.rb b/spec/unit/util/powershell/cmdlet_spec.rb deleted file mode 100644 index a964f607c8..0000000000 --- a/spec/unit/util/powershell/cmdlet_spec.rb +++ /dev/null @@ -1,106 +0,0 @@ -# -# Author:: Jay Mundrawala <jdm@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 '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') - end - - describe '#validate_switch_name!' 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 - @cmdlet.send(:validate_switch_name!, "hello") - end - - it 'should not raise an error if no special characters are used except _' do - @cmdlet.send(:validate_switch_name!, "hello_world") - end - - %w{! @ # $ % ^ & * & * ( ) - = + \{ \} . ? < > \\ /}.each do |sym| - it "raises an Argument error if it configuration name contains #{sym}" do - expect { - @cmdlet.send(:validate_switch_name!, "Hello#{sym}") - }.to raise_error(ArgumentError) - end - end - end - - describe '#escape_parameter_value' do - # Is this list really complete? - %w{` " # '}.each do |c| - it "escapse #{c}" do - @cmdlet.send(:escape_parameter_value, "stuff #{c}").should eql("stuff `#{c}") - end - end - - it 'does not do anything to a string without special characters' do - @cmdlet.send(:escape_parameter_value, 'stuff').should eql('stuff') - end - end - - describe '#escape_string_parameter_value' do - it "surrounds a string with ''" do - @cmdlet.send(:escape_string_parameter_value, 'stuff').should eql("'stuff'") - end - end - - describe '#command_switches_string' do - it 'raises an ArgumentError if the key is not a symbol' do - expect { - @cmdlet.send(:command_switches_string, {'foo' => 'bar'}) - }.to raise_error(ArgumentError) - end - - it 'does not allow invalid switch names' do - expect { - @cmdlet.send(:command_switches_string, {:foo! => 'bar'}) - }.to raise_error(ArgumentError) - end - - it 'ignores switches with a false value' do - @cmdlet.send(:command_switches_string, {foo: false}).should eql('') - end - - it 'should correctly handle a value type of string' do - @cmdlet.send(:command_switches_string, {foo: 'bar'}).should eql("-foo 'bar'") - end - - it 'should correctly handle a value type of string even when it is 0 length' do - @cmdlet.send(:command_switches_string, {foo: ''}).should eql("-foo ''") - end - - it 'should not quote integers' do - @cmdlet.send(:command_switches_string, {foo: 1}).should eql("-foo 1") - end - - it 'should not quote floats' do - @cmdlet.send(:command_switches_string, {foo: 1.0}).should eql("-foo 1.0") - end - - it 'has just the switch when the value is true' do - @cmdlet.send(:command_switches_string, {foo: true}).should eql("-foo") - end - end -end diff --git a/spec/unit/util/selinux_spec.rb b/spec/unit/util/selinux_spec.rb deleted file mode 100644 index 53faba3db3..0000000000 --- a/spec/unit/util/selinux_spec.rb +++ /dev/null @@ -1,172 +0,0 @@ -# -# Author:: Serdar Sutay (<serdar@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::Util::Selinux do - class TestClass - include Chef::Util::Selinux - - def self.reset_state - @@selinux_enabled = nil - @@restorecon_path = nil - @@selinuxenabled_path = nil - end - end - - before do - TestClass.reset_state - @test_instance = TestClass.new - end - - after(:each) do - TestClass.reset_state - 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.each do |bin_path| - selinux_path = File.join(bin_path, "selinuxenabled") - File.should_receive(:executable?).with(selinux_path).and_return(false) - end - - @test_instance.selinux_enabled?.should be_false - end - - describe "when selinuxenabled binary exists" do - before do - @selinux_enabled_path = File.join("/sbin", "selinuxenabled") - File.stub(:executable?) do |file_path| - file_path.end_with?("selinuxenabled").should be_true - file_path == @selinux_enabled_path - end - end - - describe "when selinux is enabled" do - before do - cmd_result = double("Cmd Result", :exitstatus => 0) - @test_instance.should_receive(:shell_out!).once.with(@selinux_enabled_path, {:returns=>[0, 1]}).and_return(cmd_result) - end - - it "should report selinux is enabled" do - @test_instance.selinux_enabled?.should be_true - # should check the file system only once for multiple calls - @test_instance.selinux_enabled?.should be_true - end - end - - describe "when selinux is disabled" do - before do - cmd_result = double("Cmd Result", :exitstatus => 1) - @test_instance.should_receive(:shell_out!).once.with(@selinux_enabled_path, {:returns=>[0, 1]}).and_return(cmd_result) - end - - it "should report selinux is disabled" do - @test_instance.selinux_enabled?.should be_false - # should check the file system only once for multiple calls - @test_instance.selinux_enabled?.should be_false - end - end - - describe "when selinux gives an unexpected status" do - before do - cmd_result = double("Cmd Result", :exitstatus => 101) - @test_instance.should_receive(:shell_out!).once.with(@selinux_enabled_path, {:returns=>[0, 1]}).and_return(cmd_result) - end - - it "should throw an error" do - lambda {@test_instance.selinux_enabled?}.should raise_error(RuntimeError) - end - end - end - - describe "when selinuxenabled binary doesn't exist" do - before do - File.stub(:executable?) do |file_path| - file_path.end_with?("selinuxenabled").should be_true - false - end - end - - it "should report selinux is disabled" do - @test_instance.selinux_enabled?.should be_false - # should check the file system only once for multiple calls - File.should_not_receive(:executable?) - @test_instance.selinux_enabled?.should be_false - end - end - - describe "when restorecon binary exists on the system" do - let (:path) { "/path/to/awesome directory" } - - before do - @restorecon_enabled_path = File.join("/sbin", "restorecon") - File.stub(:executable?) do |file_path| - file_path.end_with?("restorecon").should be_true - file_path == @restorecon_enabled_path - end - end - - it "should call restorecon non-recursive by default" do - restorecon_command = "#{@restorecon_enabled_path} -R \"#{path}\"" - @test_instance.should_receive(:shell_out!).twice.with(restorecon_command) - @test_instance.restore_security_context(path) - File.should_not_receive(:executable?) - @test_instance.restore_security_context(path) - end - - it "should call restorecon recursive when recursive is set" do - restorecon_command = "#{@restorecon_enabled_path} -R -r \"#{path}\"" - @test_instance.should_receive(:shell_out!).twice.with(restorecon_command) - @test_instance.restore_security_context(path, true) - File.should_not_receive(:executable?) - @test_instance.restore_security_context(path, true) - end - - it "should call restorecon non-recursive when recursive is not set" do - restorecon_command = "#{@restorecon_enabled_path} -R \"#{path}\"" - @test_instance.should_receive(:shell_out!).twice.with(restorecon_command) - @test_instance.restore_security_context(path) - File.should_not_receive(:executable?) - @test_instance.restore_security_context(path) - end - - describe "when restorecon doesn't exist on the system" do - before do - File.stub(:executable?) do |file_path| - file_path.end_with?("restorecon").should be_true - false - end - end - - it "should log a warning message" do - log = [ ] - Chef::Log.stub(:warn) do |message| - log << message - end - - @test_instance.restore_security_context(path) - log.should_not be_empty - File.should_not_receive(:executable?) - @test_instance.restore_security_context(path) - end - end - end -end diff --git a/spec/unit/util/threaded_job_queue_spec.rb b/spec/unit/util/threaded_job_queue_spec.rb deleted file mode 100644 index a199937639..0000000000 --- a/spec/unit/util/threaded_job_queue_spec.rb +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright:: Copyright (c) 2014 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' - -class WorkerThreadError < StandardError -end - -describe Chef::Util::ThreadedJobQueue do - let(:queue) { Chef::Util::ThreadedJobQueue.new } - - it "should pass mutex to jobs with an arity of 1" do - job = double() - job.should_receive(:arity).at_least(:once).and_return(1) - job.should_receive(:call).exactly(5).times.with(an_instance_of(Mutex)) - - 5.times { queue << job } - queue.process - end - - it "should pass nothing to jobs with an arity of 0" do - job = double() - job.should_receive(:arity).at_least(:once).and_return(0) - job.should_receive(:call).exactly(5).times.with(no_args) - - 5.times { queue << job } - queue.process - end - - it "should use specified number of threads" do - Thread.should_receive(:new).exactly(7).times.and_call_original - queue.process(7) - end - - it "should propagate exceptions to the main thread" do - queue << lambda { raise WorkerThreadError } - lambda { queue.process }.should raise_error(WorkerThreadError) - end -end diff --git a/spec/unit/version/platform_spec.rb b/spec/unit/version/platform_spec.rb deleted file mode 100644 index 69f42e58b2..0000000000 --- a/spec/unit/version/platform_spec.rb +++ /dev/null @@ -1,61 +0,0 @@ -# Author:: Xabier de Zuazo (<xabier@onddo.com>) -# Copyright:: Copyright (c) 2013 Onddo Labs, SL. -# 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/version/platform' - -describe Chef::Version::Platform do - - it "is a subclass of Chef::Version" do - v = Chef::Version::Platform.new('1.1') - v.should be_an_instance_of(Chef::Version::Platform) - v.should be_a_kind_of(Chef::Version) - end - - it "should transform 1 to 1.0.0" do - Chef::Version::Platform.new("1").to_s.should == "1.0.0" - 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.each do |v| - it "should accept '#{v}'" do - Chef::Version::Platform.new v - end - end - end - - describe "when given bogus input" do - bad_versions = ["1.2.3.4", "1.2.a4", "a", "1.2 3", "1.2 a", - "1 2 3", "1-2-3", "1_2_3", "1.2_3", "1.2-3"] - the_error = Chef::Exceptions::InvalidPlatformVersion - bad_versions.each do |v| - it "should raise #{the_error} when given '#{v}'" do - lambda { Chef::Version::Platform.new v }.should raise_error(the_error) - end - end - end - - describe "<=>" do - - it "should equate versions 1 and 1.0.0" do - Chef::Version::Platform.new("1").should == Chef::Version::Platform.new("1.0.0") - end - - end - -end - diff --git a/spec/unit/version_class_spec.rb b/spec/unit/version_class_spec.rb deleted file mode 100644 index b0fcfbb3fb..0000000000 --- a/spec/unit/version_class_spec.rb +++ /dev/null @@ -1,172 +0,0 @@ -# -# Author:: Seth Falcon (<seth@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. - -require 'spec_helper' -require 'chef/version_class' - -describe Chef::Version do - before do - @v0 = Chef::Version.new "0.0.0" - @v123 = Chef::Version.new "1.2.3" - end - - it "should turn itself into a string" do - @v0.to_s.should == "0.0.0" - @v123.to_s.should == "1.2.3" - end - - it "should make a round trip with its string representation" do - a = Chef::Version.new(@v123.to_s) - a.should == @v123 - end - - it "should transform 1.2 to 1.2.0" do - Chef::Version.new("1.2").to_s.should == "1.2.0" - end - - it "should transform 01.002.0003 to 1.2.3" do - a = Chef::Version.new "01.002.0003" - a.should == @v123 - 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.each do |v| - it "should accept '#{v}'" do - Chef::Version.new v - end - end - end - - describe "when given bogus input" do - bad_versions = ["1.2.3.4", "1.2.a4", "1", "a", "1.2 3", "1.2 a", - "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| - it "should raise #{the_error} when given '#{v}'" do - lambda { Chef::Version.new v }.should raise_error(the_error) - end - end - end - - describe "<=>" do - - it "should equate versions 1.2 and 1.2.0" do - Chef::Version.new("1.2").should == Chef::Version.new("1.2.0") - end - - it "should equate version 1.04 and 1.4" do - Chef::Version.new("1.04").should == Chef::Version.new("1.4") - end - - it "should treat versions as numbers in the right way" do - Chef::Version.new("2.0").should be < Chef::Version.new("11.0") - end - - it "should sort based on the version number" do - examples = [ - # smaller, larger - ["1.0", "2.0"], - ["1.2.3", "1.2.4"], - ["1.2.3", "1.3.0"], - ["1.2.3", "1.3"], - ["1.2.3", "2.1.1"], - ["1.2.3", "2.1"], - ["1.2", "1.2.4"], - ["1.2", "1.3.0"], - ["1.2", "1.3"], - ["1.2", "2.1.1"], - ["1.2", "2.1"] - ] - examples.each do |smaller, larger| - sm = Chef::Version.new(smaller) - lg = Chef::Version.new(larger) - sm.should be < lg - lg.should be > sm - sm.should_not == lg - end - end - - it "should sort an array of versions" 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.should == %w{0.0.0 0.0.1 0.1.0 0.1.1 1.0.0 1.1.0 1.1.1} - end - - it "should sort an array of versions, part 2" do - a = %w{9.8.7 1.0.0 1.2.3 4.4.6 4.5.6 0.8.6 4.5.5 5.9.8 3.5.7}.map do |s| - Chef::Version.new(s) - end - got = a.sort.map { |v| v.to_s } - got.should == %w{0.8.6 1.0.0 1.2.3 3.5.7 4.4.6 4.5.5 4.5.6 5.9.8 9.8.7} - end - - describe "comparison examples" do - [ - [ "0.0.0", :>, "0.0.0", false ], - [ "0.0.0", :>=, "0.0.0", true ], - [ "0.0.0", :==, "0.0.0", true ], - [ "0.0.0", :<=, "0.0.0", true ], - [ "0.0.0", :<, "0.0.0", false ], - [ "0.0.0", :>, "0.0.1", false ], - [ "0.0.0", :>=, "0.0.1", false ], - [ "0.0.0", :==, "0.0.1", false ], - [ "0.0.0", :<=, "0.0.1", true ], - [ "0.0.0", :<, "0.0.1", true ], - [ "0.0.1", :>, "0.0.1", false ], - [ "0.0.1", :>=, "0.0.1", true ], - [ "0.0.1", :==, "0.0.1", true ], - [ "0.0.1", :<=, "0.0.1", true ], - [ "0.0.1", :<, "0.0.1", false ], - [ "0.1.0", :>, "0.1.0", false ], - [ "0.1.0", :>=, "0.1.0", true ], - [ "0.1.0", :==, "0.1.0", true ], - [ "0.1.0", :<=, "0.1.0", true ], - [ "0.1.0", :<, "0.1.0", false ], - [ "0.1.1", :>, "0.1.1", false ], - [ "0.1.1", :>=, "0.1.1", true ], - [ "0.1.1", :==, "0.1.1", true ], - [ "0.1.1", :<=, "0.1.1", true ], - [ "0.1.1", :<, "0.1.1", false ], - [ "1.0.0", :>, "1.0.0", false ], - [ "1.0.0", :>=, "1.0.0", true ], - [ "1.0.0", :==, "1.0.0", true ], - [ "1.0.0", :<=, "1.0.0", true ], - [ "1.0.0", :<, "1.0.0", false ], - [ "1.0.0", :>, "0.0.1", true ], - [ "1.0.0", :>=, "1.9.2", false ], - [ "1.0.0", :==, "9.7.2", false ], - [ "1.0.0", :<=, "1.9.1", true ], - [ "1.0.0", :<, "1.9.0", true ], - [ "1.2.2", :>, "1.2.1", true ], - [ "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 ] - ].each do |spec| - it "(#{spec.first(3).join(' ')}) should be #{spec[3]}" do - got = Chef::Version.new(spec[0]).send(spec[1], - Chef::Version.new(spec[2])) - got.should == spec[3] - end - end - end - end -end - diff --git a/spec/unit/version_constraint/platform_spec.rb b/spec/unit/version_constraint/platform_spec.rb deleted file mode 100644 index a3599aeb96..0000000000 --- a/spec/unit/version_constraint/platform_spec.rb +++ /dev/null @@ -1,46 +0,0 @@ -# Author:: Xabier de Zuazo (<xabier@onddo.com>) -# Copyright:: Copyright (c) 2013 Onddo Labs, SL. -# 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/version_constraint/platform' - -describe Chef::VersionConstraint::Platform do - - it "is a subclass of Chef::VersionConstraint" do - v = Chef::VersionConstraint::Platform.new - v.should be_an_instance_of(Chef::VersionConstraint::Platform) - v.should be_a_kind_of(Chef::VersionConstraint) - end - - it "should work with Chef::Version::Platform classes" do - vc = Chef::VersionConstraint::Platform.new("1.0") - vc.version.should be_an_instance_of(Chef::Version::Platform) - end - - describe "include?" do - - it "pessimistic ~> x" do - vc = Chef::VersionConstraint::Platform.new "~> 1" - vc.should include "1.3.3" - vc.should include "1.4" - - vc.should_not include "2.2" - vc.should_not include "0.3.0" - end - - end -end - diff --git a/spec/unit/version_constraint_spec.rb b/spec/unit/version_constraint_spec.rb deleted file mode 100644 index dfa4740d51..0000000000 --- a/spec/unit/version_constraint_spec.rb +++ /dev/null @@ -1,179 +0,0 @@ -# -# Author:: Seth Falcon (<seth@opscode.com>) -# Copyright:: Copyright 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. - -require 'spec_helper' -require 'chef/version_constraint' - -describe Chef::VersionConstraint do - describe "validation" do - bad_version = [">= 1.2.z", "> 1.2.3 < 5.0", "> 1.2.3, < 5.0"] - bad_op = ["> >", ">$ 1.2.3", "! 3.4"] - o_error = Chef::Exceptions::InvalidVersionConstraint - v_error = Chef::Exceptions::InvalidCookbookVersion - bad_version.each do |s| - it "should raise #{v_error} when given #{s}" do - lambda { Chef::VersionConstraint.new s }.should raise_error(v_error) - end - end - bad_op.each do |s| - it "should raise #{o_error} when given #{s}" do - lambda { Chef::VersionConstraint.new s }.should raise_error(o_error) - end - end - - it "should interpret a lone version number as implicit = OP" do - vc = Chef::VersionConstraint.new("1.2.3") - vc.to_s.should == "= 1.2.3" - end - - it "should allow initialization with [] for back compatibility" do - Chef::VersionConstraint.new([]) == Chef::VersionConstraint.new - end - - it "should allow initialization with ['1.2.3'] for back compatibility" do - Chef::VersionConstraint.new(["1.2"]) == Chef::VersionConstraint.new("1.2") - end - - end - - it "should default to >= 0.0.0" do - vc = Chef::VersionConstraint.new - vc.to_s.should == ">= 0.0.0" - end - - it "should default to >= 0.0.0 when initialized with nil" do - Chef::VersionConstraint.new(nil).to_s.should == ">= 0.0.0" - end - - it "should work with Chef::Version classes" do - vc = Chef::VersionConstraint.new("1.0") - vc.version.should be_an_instance_of(Chef::Version) - end - - it "should allow ops without space separator" do - Chef::VersionConstraint.new("=1.2.3").should eql(Chef::VersionConstraint.new("= 1.2.3")) - Chef::VersionConstraint.new(">1.2.3").should eql(Chef::VersionConstraint.new("> 1.2.3")) - Chef::VersionConstraint.new("<1.2.3").should eql(Chef::VersionConstraint.new("< 1.2.3")) - Chef::VersionConstraint.new(">=1.2.3").should eql(Chef::VersionConstraint.new(">= 1.2.3")) - Chef::VersionConstraint.new("<=1.2.3").should eql(Chef::VersionConstraint.new("<= 1.2.3")) - end - - it "should allow ops with multiple spaces" do - Chef::VersionConstraint.new("= 1.2.3").should eql(Chef::VersionConstraint.new("= 1.2.3")) - end - - describe "include?" do - describe "handles various input data types" do - before do - @vc = Chef::VersionConstraint.new "> 1.2.3" - end - it "String" do - @vc.should include "1.4" - end - it "Chef::Version" do - @vc.should include Chef::Version.new("1.4") - end - it "Chef::CookbookVersion" do - cv = Chef::CookbookVersion.new("alice", '/tmp/blah.txt') - cv.version = "1.4" - @vc.should include cv - end - end - - it "strictly less than" do - vc = Chef::VersionConstraint.new "< 1.2.3" - vc.should_not include "1.3.0" - vc.should_not include "1.2.3" - vc.should include "1.2.2" - end - - it "strictly greater than" do - vc = Chef::VersionConstraint.new "> 1.2.3" - vc.should include "1.3.0" - vc.should_not include "1.2.3" - vc.should_not include "1.2.2" - end - - it "less than or equal to" do - vc = Chef::VersionConstraint.new "<= 1.2.3" - vc.should_not include "1.3.0" - vc.should include "1.2.3" - vc.should include "1.2.2" - end - - it "greater than or equal to" do - vc = Chef::VersionConstraint.new ">= 1.2.3" - vc.should include "1.3.0" - vc.should include "1.2.3" - vc.should_not include "1.2.2" - end - - it "equal to" do - vc = Chef::VersionConstraint.new "= 1.2.3" - vc.should_not include "1.3.0" - vc.should include "1.2.3" - vc.should_not include "0.3.0" - end - - it "pessimistic ~> x.y.z" do - vc = Chef::VersionConstraint.new "~> 1.2.3" - vc.should include "1.2.3" - vc.should include "1.2.4" - - vc.should_not include "1.2.2" - vc.should_not include "1.3.0" - vc.should_not include "2.0.0" - end - - it "pessimistic ~> x.y" do - vc = Chef::VersionConstraint.new "~> 1.2" - vc.should include "1.3.3" - vc.should include "1.4" - - vc.should_not include "2.2" - vc.should_not include "0.3.0" - end - end - - describe 'to_s' do - it 'shows a patch-level if one is given' do - vc = Chef::VersionConstraint.new '~> 1.2.0' - - vc.to_s.should == '~> 1.2.0' - end - - it 'shows no patch-level if one is not given' do - vc = Chef::VersionConstraint.new '~> 1.2' - - vc.to_s.should == '~> 1.2' - end - end - - describe 'inspect' do - it 'shows a patch-level if one is given' do - vc = Chef::VersionConstraint.new '~> 1.2.0' - - vc.inspect.should == '(~> 1.2.0)' - end - - it 'shows no patch-level if one is not given' do - vc = Chef::VersionConstraint.new '~> 1.2' - - vc.inspect.should == '(~> 1.2)' - end - end -end diff --git a/spec/unit/windows_service_spec.rb b/spec/unit/windows_service_spec.rb deleted file mode 100644 index ba3d2980df..0000000000 --- a/spec/unit/windows_service_spec.rb +++ /dev/null @@ -1,54 +0,0 @@ -# -# Author:: Mukta Aphale (<mukta.aphale@clogeny.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' -if Chef::Platform.windows? - 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"} - before do - instance.stub(:parse_options) - shell_out_result.stub(:stdout) - shell_out_result.stub(:stderr) - end - it "runs chef-client in new process" do - instance.should_receive(:configure_chef).twice - instance.service_init - instance.should_receive(:run_chef_client).and_call_original - instance.should_receive(:shell_out).and_return(shell_out_result) - instance.stub(:running?).and_return(true, false) - instance.instance_variable_get(:@service_signal).stub(:wait) - instance.stub(:state).and_return(4) - instance.service_main - end - it "passes config params to new process" do - Chef::Config.merge!({:log_location => tempfile.path, :config_file => "test_config_file", :log_level => :info}) - instance.should_receive(:configure_chef).twice - instance.service_init - instance.stub(:running?).and_return(true, false) - instance.instance_variable_get(:@service_signal).stub(:wait) - instance.stub(:state).and_return(4) - instance.should_receive(:run_chef_client).and_call_original - instance.should_receive(:shell_out).with("chef-client --no-fork -c test_config_file -L #{tempfile.path}").and_return(shell_out_result) - instance.service_main - tempfile.unlink - 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 de108ff6d7..0000000000 --- a/spec/unit/workstation_config_loader_spec.rb +++ /dev/null @@ -1,283 +0,0 @@ -# -# Author:: Daniel DeLeo (<dan@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 - env["HOME"] = home - 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 - - Dir.stub(: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 explict 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 |