diff options
author | danielsdeleo <dan@opscode.com> | 2014-02-20 12:37:26 -0800 |
---|---|---|
committer | danielsdeleo <dan@opscode.com> | 2014-02-20 12:37:26 -0800 |
commit | a4c7d9154afcdb760ff867cbb98118e5cf4089cd (patch) | |
tree | f77e83dede0291c980e349987bf286beeff6abcd | |
parent | 364aa72ced08c7d23382b20912e35b2e02a54fb3 (diff) | |
parent | 0b3498ffb09504225b1019a4a530256407a3e67e (diff) | |
download | chef-a4c7d9154afcdb760ff867cbb98118e5cf4089cd.tar.gz |
Merge branch 'CHEF-5032'
Resolves https://tickets.opscode.com/browse/CHEF-5032
-rw-r--r-- | lib/chef/application.rb | 3 | ||||
-rw-r--r-- | lib/chef/application/client.rb | 12 | ||||
-rw-r--r-- | lib/chef/client.rb | 20 | ||||
-rw-r--r-- | lib/chef/node.rb | 2 | ||||
-rw-r--r-- | spec/integration/client/client_spec.rb | 14 | ||||
-rw-r--r-- | spec/unit/client_spec.rb | 544 |
6 files changed, 355 insertions, 240 deletions
diff --git a/lib/chef/application.rb b/lib/chef/application.rb index 04e88de2ce..601bbd91f1 100644 --- a/lib/chef/application.rb +++ b/lib/chef/application.rb @@ -208,7 +208,8 @@ class Chef::Application @chef_client = Chef::Client.new( @chef_client_json, :override_runlist => config[:override_runlist], - :specific_recipes => specific_recipes + :specific_recipes => specific_recipes, + :runlist => config[:runlist] ) @chef_client_json = nil diff --git a/lib/chef/application/client.rb b/lib/chef/application/client.rb index de644b5f31..e14266d82a 100644 --- a/lib/chef/application/client.rb +++ b/lib/chef/application/client.rb @@ -170,7 +170,7 @@ class Chef::Application::Client < Chef::Application option :override_runlist, :short => "-o RunlistItem,RunlistItem...", :long => "--override-runlist RunlistItem,RunlistItem...", - :description => "Replace current run list with specified items", + :description => "Replace current run list with specified items for a single run", :proc => lambda{|items| items = items.split(',') items.compact.map{|item| @@ -178,6 +178,16 @@ class Chef::Application::Client < Chef::Application } } + option :runlist, + :short => "-r RunlistItem,RunlistItem...", + :long => "--runlist RunlistItem,RunlistItem...", + :description => "Permanently replace current run list with specified items", + :proc => lambda{|items| + items = items.split(',') + items.compact.map{|item| + Chef::RunList::RunListItem.new(item) + } + } option :why_run, :short => '-W', :long => '--why-run', diff --git a/lib/chef/client.rb b/lib/chef/client.rb index 638047331a..aa03f043c2 100644 --- a/lib/chef/client.rb +++ b/lib/chef/client.rb @@ -55,6 +55,16 @@ class Chef class Client include Chef::Mixin::PathSanity + # IO stream that will be used as 'STDOUT' for formatters. Formatters are + # configured during `initialize`, so this provides a convenience for + # setting alternative IO stream during tests. + STDOUT_FD = STDOUT + + # IO stream that will be used as 'STDERR' for formatters. Formatters are + # configured during `initialize`, so this provides a convenience for + # setting alternative IO stream during tests. + STDERR_FD = STDERR + # Clears all notifications for client run status events. # Primarily for testing purposes. def self.clear_notifications @@ -129,15 +139,13 @@ class Chef attr_accessor :rest attr_accessor :runner - #-- - # TODO: timh/cw: 5-19-2010: json_attribs should be moved to RunContext? attr_reader :json_attribs attr_reader :run_status attr_reader :events # Creates a new Chef::Client. def initialize(json_attribs=nil, args={}) - @json_attribs = json_attribs + @json_attribs = json_attribs || {} @node = nil @run_status = nil @runner = nil @@ -149,12 +157,16 @@ class Chef @events = EventDispatch::Dispatcher.new(*event_handlers) @override_runlist = args.delete(:override_runlist) @specific_recipes = args.delete(:specific_recipes) + + if new_runlist = args.delete(:runlist) + @json_attribs["run_list"] = new_runlist + end end def configure_formatters formatters_for_run.map do |formatter_name, output_path| if output_path.nil? - Chef::Formatters.new(formatter_name, STDOUT, STDERR) + Chef::Formatters.new(formatter_name, STDOUT_FD, STDERR_FD) else io = File.open(output_path, "a+") io.sync = true diff --git a/lib/chef/node.rb b/lib/chef/node.rb index 69e5e05b01..a7fc033080 100644 --- a/lib/chef/node.rb +++ b/lib/chef/node.rb @@ -312,7 +312,7 @@ class Chef if attrs.key?("recipes") || attrs.key?("run_list") raise Chef::Exceptions::AmbiguousRunlistSpecification, "please set the node's run list using the 'run_list' attribute only." end - Chef::Log.info("Setting the run_list to #{new_run_list.inspect} from JSON") + Chef::Log.info("Setting the run_list to #{new_run_list.inspect} from CLI options") run_list(new_run_list) end attrs diff --git a/spec/integration/client/client_spec.rb b/spec/integration/client/client_spec.rb index bca9ed4854..6357f1e2c0 100644 --- a/spec/integration/client/client_spec.rb +++ b/spec/integration/client/client_spec.rb @@ -215,5 +215,19 @@ 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/unit/client_spec.rb b/spec/unit/client_spec.rb index bd80d39237..e4143d7653 100644 --- a/spec/unit/client_spec.rb +++ b/spec/unit/client_spec.rb @@ -24,29 +24,52 @@ require 'chef/run_context' require 'chef/rest' require 'rbconfig' -shared_examples_for Chef::Client do +describe Chef::Client do + + let(:hostname) { "hostname" } + let(:fqdn) { "hostname.example.org" } + + let(:ohai_data) do + { :fqdn => fqdn, + :hostname => hostname, + :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 - @hostname = "hostname" - @fqdn = "hostname.example.org" - Chef::Config[:node_name] = @fqdn - ohai_data = { :fqdn => @fqdn, - :hostname => @hostname, - :platform => 'example-platform', - :platform_version => 'example-platform-1.0', - :data => {} } - ohai_data.stub(:all_plugins).and_return(true) - ohai_data.stub(:data).and_return(ohai_data) - Ohai::System.stub(:new).and_return(ohai_data) - - @node = Chef::Node.new - @node.name(@fqdn) - @node.chef_environment("_default") - - @client = Chef::Client.new - @client.node = @node + #Chef::Config[:node_name] = fqdn + Ohai::System.stub(:new).and_return(ohai_system) end describe "authentication protocol selection" do @@ -58,7 +81,7 @@ shared_examples_for Chef::Client 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 + client.node_name Chef::Config[:authentication_protocol_version].should == "1.0" end end @@ -67,7 +90,7 @@ shared_examples_for Chef::Client 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 + client.node_name Chef::Config[:authentication_protocol_version].should == "1.1" end end @@ -75,9 +98,6 @@ shared_examples_for Chef::Client do describe "configuring output formatters" do context "when no formatter has been configured" do - before do - @client = Chef::Client.new - end context "and STDOUT is a TTY" do before do @@ -85,7 +105,7 @@ shared_examples_for Chef::Client do end it "configures the :doc formatter" do - @client.formatters_for_run.should == [[:doc]] + client.formatters_for_run.should == [[:doc]] end context "and force_logger is set" do @@ -95,7 +115,7 @@ shared_examples_for Chef::Client do it "configures the :null formatter" do Chef::Config[:force_logger].should be_true - @client.formatters_for_run.should == [[:null]] + client.formatters_for_run.should == [[:null]] end end @@ -108,7 +128,7 @@ shared_examples_for Chef::Client do end it "configures the :null formatter" do - @client.formatters_for_run.should == [[:null]] + client.formatters_for_run.should == [[:null]] end context "and force_formatter is set" do @@ -116,7 +136,7 @@ shared_examples_for Chef::Client do Chef::Config[:force_formatter] = true end it "it configures the :doc formatter" do - @client.formatters_for_run.should == [[:doc]] + client.formatters_for_run.should == [[:doc]] end end end @@ -126,16 +146,15 @@ shared_examples_for Chef::Client do context "when a formatter is configured" do context "with no output path" do before do - @client = Chef::Client.new Chef::Config.add_formatter(:min) end it "does not configure a default formatter" do - @client.formatters_for_run.should == [[:min, nil]] + client.formatters_for_run.should == [[:min, nil]] end it "configures the formatter for STDOUT/STDERR" do - configured_formatters = @client.configure_formatters + configured_formatters = client.configure_formatters min_formatter = configured_formatters[0] min_formatter.output.out.should == STDOUT min_formatter.output.err.should == STDERR @@ -144,7 +163,6 @@ shared_examples_for Chef::Client do context "with an output path" do before do - @client = Chef::Client.new @tmpout = Tempfile.open("rspec-for-client-formatter-selection-#{Process.pid}") Chef::Config.add_formatter(:min, @tmpout.path) end @@ -155,7 +173,7 @@ shared_examples_for Chef::Client do end it "configures the formatter for the file path" do - configured_formatters = @client.configure_formatters + 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 @@ -165,94 +183,216 @@ shared_examples_for Chef::Client do end end - describe "run" do - - it "should identify the node and run ohai, then register the client" do - mock_chef_rest_for_node = double("Chef::REST (node)") - mock_chef_rest_for_cookbook_sync = double("Chef::REST (cookbook sync)") - mock_chef_rest_for_node_save = double("Chef::REST (node save)") - mock_chef_runner = double("Chef::Runner") - - # --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(false) - - # Client.register will register with the validation client name. - Chef::ApiClient::Registration.any_instance.should_receive(:run) - # 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(mock_chef_rest_for_node) - - # --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) - - # --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) - # --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(mock_chef_rest_for_cookbook_sync) - mock_chef_rest_for_cookbook_sync.should_receive(:post).with("environments/_default/cookbook_versions", {:run_list => []}).and_return({}) - - # --Client#converge - Chef::Runner.should_receive(:new).and_return(mock_chef_runner) - mock_chef_runner.should_receive(:converge).and_return(true) - - # --Client#save_updated_node - Chef::REST.should_receive(:new).with(Chef::Config[:chef_server_url]).and_return(mock_chef_rest_for_node_save) - mock_chef_rest_for_node_save.should_receive(:put_rest).with("nodes/#{@fqdn}", @node).and_return(true) - - 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) + 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") } - if(Chef::Config[:client_fork] && !windows?) - require 'stringio' - if(Chef::Config[:pipe_node]) - pipe_sim = StringIO.new - pipe_sim.should_receive(:close).exactly(4).and_return(nil) - res = '' - pipe_sim.should_receive(:puts) do |string| - res.replace(string) - end - pipe_sim.should_receive(:gets).and_return(res) - IO.should_receive(:pipe).and_return([pipe_sim, pipe_sim]) - IO.should_receive(:select).and_return(true) + 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 - proc_ret = Class.new.new - proc_ret.should_receive(:success?).and_return(true) - Process.should_receive(:waitpid2).and_return([1, proc_ret]) - @client.should_receive(:exit).and_return(nil) - @client.should_receive(:fork) do |&block| - block.call + 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 + # --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).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 + + 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 running chef-client with forking enabled", :unix_only do + include_examples "a successful client run" do + let(:process_status) do + double("Process::Status") + end + + let(:enable_fork) { true } + + before do + Process.should_receive(:waitpid2).and_return([1, process_status]) + + process_status.should_receive(:success?).and_return(true) + client.should_receive(:exit).and_return(nil) + client.should_receive(:fork).and_yield + end + end + + 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} } - # This is what we're testing. - @client.run + 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 - if(!Chef::Config[:client_fork] || Chef::Config[:pipe_node]) - @node.automatic_attrs[:platform].should == "example-platform" - @node.automatic_attrs[:platform_version].should == "example-platform-1.0" 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) @@ -261,64 +401,64 @@ shared_examples_for Chef::Client do 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) + client = Chef::Client.new + client.stub(:load_node).and_raise(Exception) @run_lock.should_receive(:release) if(Chef::Config[:client_fork] && !windows?) - @client.should_receive(:fork) do |&block| + client.should_receive(:fork) do |&block| block.call end end - lambda { @client.run }.should raise_error(Exception) + 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 + 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 - @client.run_started - notified.should be_true + 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 - 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_started + notified.should be_true + end - @client.run_completed_successfully - notified.should be_true + 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 - 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_completed_successfully + notified.should be_true + end - @client.run_failed - notified.should be_true + 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]" + 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" @@ -330,37 +470,33 @@ shared_examples_for Chef::Client do Chef::REST.should_receive(:new).and_return(mock_chef_rest) # check pre-conditions. - @node[:roles].should be_nil - @node[:recipes].should be_nil + node[:roles].should be_nil + node[:recipes].should be_nil - @client.policy_builder.stub(:node).and_return(@node) + client.policy_builder.stub(:node).and_return(node) # chefspec and possibly others use the return value of this method - @client.build_node.should == @node + 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") + 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 end describe "windows_admin_check" do - before do - @client = Chef::Client.new - end - 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 + client.should_not_receive(:has_admin_privileges?) + client.do_windows_admin_check end end @@ -370,91 +506,46 @@ shared_examples_for Chef::Client do end it "should be called" do - @client.should_receive(:has_admin_privileges?) - @client.do_windows_admin_check + 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) + 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 + 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_error + 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) + 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 + 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_error + client.do_windows_admin_check # should not raise end end end end end - describe "when a run list override is provided" do - before do - @node = Chef::Node.new - @node.name(@fqdn) - @node.chef_environment("_default") - @node.automatic_attrs[:platform] = "example-platform" - @node.automatic_attrs[:platform_version] = "example-platform-1.0" - end - - it "should permit spaces in overriding run list" do - @client = Chef::Client.new(nil, :override_runlist => 'role[a], role[b]') - end - - it "should override the run list and skip the final node save" do - @client = Chef::Client.new(nil, :override_runlist => 'role[test_role]') - @client.node = @node - - @node.run_list << "role[role_containing_cookbook1]" - - override_role = Chef::Role.new - override_role.name 'test_role' - override_role.run_list << 'cookbook1' - - original_runlist = @node.run_list.dup - - mock_chef_rest = double("Chef::REST") - mock_chef_rest.should_receive(:get_rest).with("roles/test_role").and_return(override_role) - Chef::REST.should_receive(:new).and_return(mock_chef_rest) - - @node.should_not_receive(:save) - - @client.policy_builder.stub(:node).and_return(@node) - @client.policy_builder.build_node - - @node[:roles].should_not be_nil - @node[:roles].should eql(['test_role']) - @node[:recipes].should eql(['cookbook1']) - - @client.save_updated_node - - @node.run_list.should == original_runlist - - end - end - describe "assert_cookbook_path_not_empty" do before do Chef::Config[:solo] = true @@ -463,7 +554,7 @@ shared_examples_for Chef::Client do 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) + 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 @@ -471,16 +562,3 @@ shared_examples_for Chef::Client do end -describe Chef::Client do - Chef::Config[:client_fork] = false - it_behaves_like Chef::Client -end - -describe "Chef::Client Forked" do - before do - Chef::Config[:client_fork] = true - end - - it_behaves_like Chef::Client - -end |