summaryrefslogtreecommitdiff
path: root/spec/unit/shell
diff options
context:
space:
mode:
authorSeth Chisamore <schisamo@opscode.com>2012-10-30 10:39:35 -0400
committerSeth Chisamore <schisamo@opscode.com>2012-10-30 10:39:35 -0400
commit24dc69a9a97e82a6e4207de68d6dcc664178249b (patch)
tree19bb289c9f88b4bbab066bc56b95d6d222fd5c35 /spec/unit/shell
parent9348c1c9c80ee757354d624b7dc1b78ebc7605c4 (diff)
downloadchef-24dc69a9a97e82a6e4207de68d6dcc664178249b.tar.gz
[OC-3564] move core Chef to the repo root \o/ \m/
The opscode/chef repository now only contains the core Chef library code used by chef-client, knife and chef-solo!
Diffstat (limited to 'spec/unit/shell')
-rw-r--r--spec/unit/shell/model_wrapper_spec.rb97
-rw-r--r--spec/unit/shell/shell_ext_spec.rb153
-rw-r--r--spec/unit/shell/shell_session_spec.rb141
3 files changed, 391 insertions, 0 deletions
diff --git a/spec/unit/shell/model_wrapper_spec.rb b/spec/unit/shell/model_wrapper_spec.rb
new file mode 100644
index 0000000000..35dc591edc
--- /dev/null
+++ b/spec/unit/shell/model_wrapper_spec.rb
@@ -0,0 +1,97 @@
+#
+# 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 = mock("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
new file mode 100644
index 0000000000..22e9ae674b
--- /dev/null
+++ b/spec/unit/shell/shell_ext_spec.rb
@@ -0,0 +1,153 @@
+# 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 = mock("irbconf")
+ end
+
+ it "finds a subsession in irb for an object" do
+ target_context_obj = Chef::Node.new
+
+ irb_context = mock("context", :main => target_context_obj)
+ irb_session = mock("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 = mock("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
new file mode 100644
index 0000000000..3d4081e583
--- /dev/null
+++ b/spec/unit/shell/shell_session_spec.rb
@@ -0,0 +1,141 @@
+# 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::StandAloneSession do
+ before do
+ @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 = mock("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
+
+end
+
+describe Shell::SoloSession do
+ before do
+ 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 it's 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 it's 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 = mock("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
+
+end