summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authordanielsdeleo <dan@opscode.com>2013-06-20 13:14:50 -0700
committerdanielsdeleo <dan@opscode.com>2013-06-20 13:22:16 -0700
commit1f316fcbd885f579d1b7e89efe6621bf2b759959 (patch)
tree3e0befa94701e57ea142f6b912523d7d63cc1273 /spec
parentc82904d42d9962ae420fcf33f812e5da6d3521b6 (diff)
downloadchef-1f316fcbd885f579d1b7e89efe6621bf2b759959.tar.gz
Pass useradd commands as argv array instead of sh command.
- Fixes CHEF-4204 - Useradd provider commands converted from single string to argv array. This bypasses use of bin/sh command interpretation, so there is no need to escape shell-significant characters (e.g., quotes, etc.). - Un-pending-ize useradd functional tests for arguments to useradd with single quote characters. - Update useradd unit tests to expect command as argv splatted arrays. - Extract useradd unit tests to a shared example group. - deduplicate test code between solaris and useradd unit tests using shared example group.
Diffstat (limited to 'spec')
-rw-r--r--spec/functional/resource/user_spec.rb5
-rw-r--r--spec/support/shared/unit/provider/useradd_based_user_provider.rb408
-rw-r--r--spec/unit/provider/user/solaris_spec.rb390
-rw-r--r--spec/unit/provider/user/useradd_spec.rb360
4 files changed, 467 insertions, 696 deletions
diff --git a/spec/functional/resource/user_spec.rb b/spec/functional/resource/user_spec.rb
index 786ca97acb..e53a6f25d7 100644
--- a/spec/functional/resource/user_spec.rb
+++ b/spec/functional/resource/user_spec.rb
@@ -66,7 +66,7 @@ describe Chef::Resource::User, :unix_only, :requires_root do
after do
begin
pw_entry # will raise if the user doesn't exist
- shell_out!("userdel -f -r #{username}")
+ shell_out!("userdel", "-f", "-r", username)
rescue UserNotFound
# nothing to remove
end
@@ -134,7 +134,6 @@ describe Chef::Resource::User, :unix_only, :requires_root do
# default algorithm for the definition of the user's home directory.
context "and the username contains a single quote" do
- let(:skip) { "single quotes not properly escaped ATM" }
let(:username) { "t'bilisi" }
it "ensures the user exists" do
@@ -178,11 +177,9 @@ describe Chef::Resource::User, :unix_only, :requires_root do
end
context "to a string containing an apostrophe `'`" do
- let(:skip) { "single quotes not properly escaped ATM" }
let(:comment) { "don't go" }
it "ensures the comment is set" do
- pending "not working yet"
pw_entry.gecos.should == comment
end
end
diff --git a/spec/support/shared/unit/provider/useradd_based_user_provider.rb b/spec/support/shared/unit/provider/useradd_based_user_provider.rb
new file mode 100644
index 0000000000..da4f358d47
--- /dev/null
+++ b/spec/support/shared/unit/provider/useradd_based_user_provider.rb
@@ -0,0 +1,408 @@
+#
+# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Daniel DeLeo (<dan@opscode.com>)
+# Copyright:: Copyright (c) 2008, 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.
+#
+
+shared_examples_for "a useradd-based user provider" do |supported_useradd_options|
+ 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)
+ @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.system false
+ @new_resource.manage_home false
+ @new_resource.non_unique false
+ @current_resource = Chef::Resource::User.new("adam", @run_context)
+ @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"
+ @current_resource.system false
+ @current_resource.manage_home false
+ @current_resource.non_unique false
+ @current_resource.supports({:manage_home => false, :non_unique => false})
+ @provider = described_class.new(@new_resource, @run_context)
+ @provider.current_resource = @current_resource
+ end
+
+ describe "when setting option" do
+
+ supported_useradd_options.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.universal_options
+ end
+
+ it "should set the option for #{attribute} if the new resources #{attribute} is not nil" do
+ @new_resource.stub!(attribute).and_return("hola")
+ @provider.universal_options.should eql([option, 'hola'])
+ end
+
+ it "should set the option for #{attribute} if the new resources #{attribute} is not nil, without homedir management" do
+ @new_resource.stub!(:supports).and_return({:manage_home => false,
+ :non_unique => false})
+ @new_resource.stub!(attribute).and_return("hola")
+ @provider.universal_options.should eql([option, 'hola'])
+ end
+
+ it "should set the option for #{attribute} if the new resources #{attribute} is not nil, without homedir management (using real attributes)" do
+ @new_resource.stub!(:manage_home).and_return(false)
+ @new_resource.stub!(:non_unique).and_return(false)
+ @new_resource.stub!(attribute).and_return("hola")
+ @provider.universal_options.should eql([option, 'hola'])
+ end
+ end
+
+ it "should combine all the possible options" do
+ combined_opts = []
+ supported_useradd_options.sort{ |a,b| a[0] <=> b[0] }.each do |attribute, option|
+ @new_resource.stub!(attribute).and_return("hola")
+ combined_opts << option << 'hola'
+ end
+ @provider.universal_options.should eql(combined_opts)
+ end
+
+ describe "when we want to create a system user" do
+ before do
+ @new_resource.manage_home(true)
+ @new_resource.non_unique(false)
+ end
+
+ it "should set useradd -r" do
+ @new_resource.system(true)
+ @provider.useradd_options.should == [ "-r" ]
+ end
+ end
+
+ describe "when the resource has a different home directory and supports home directory management" do
+ before do
+ @new_resource.stub!(:home).and_return("/wowaweea")
+ @new_resource.stub!(:supports).and_return({:manage_home => true,
+ :non_unique => false})
+ end
+
+ it "should set -m -d /homedir" do
+ @provider.universal_options.should == %w[-m -d /wowaweea]
+ @provider.useradd_options.should == []
+ end
+ end
+
+ describe "when the resource has a different home directory and supports home directory management (using real attributes)" do
+ before do
+ @new_resource.stub!(:home).and_return("/wowaweea")
+ @new_resource.stub!(:manage_home).and_return(true)
+ @new_resource.stub!(:non_unique).and_return(false)
+ end
+
+ it "should set -m -d /homedir" do
+ @provider.universal_options.should eql(%w[-m -d /wowaweea])
+ @provider.useradd_options.should == []
+ end
+ end
+
+ describe "when the resource supports non_unique ids" do
+ before do
+ @new_resource.stub!(:supports).and_return({:manage_home => false,
+ :non_unique => true})
+ end
+
+ it "should set -m -o" do
+ @provider.universal_options.should eql([ "-o" ])
+ end
+ end
+
+ describe "when the resource supports non_unique ids (using real attributes)" do
+ before do
+ @new_resource.stub!(:manage_home).and_return(false)
+ @new_resource.stub!(:non_unique).and_return(true)
+ end
+
+ it "should set -m -o" do
+ @provider.universal_options.should eql([ "-o" ])
+ end
+ end
+ end
+
+ describe "when creating a user" do
+ before(:each) do
+ @current_resource = Chef::Resource::User.new(@new_resource.name, @run_context)
+ @current_resource.username(@new_resource.username)
+ @provider.current_resource = @current_resource
+ @provider.new_resource.manage_home true
+ @provider.new_resource.home "/Users/mud"
+ @provider.new_resource.gid '23'
+ end
+
+ it "runs useradd with the computed command options" do
+ command = ["useradd",
+ "-c", 'Adam Jacob',
+ "-g", '23' ]
+ command.concat(["-p", 'abracadabra']) if supported_useradd_options.key?("password")
+ command.concat([ "-s", '/usr/bin/zsh',
+ "-u", '1000',
+ "-m",
+ "-d", '/Users/mud',
+ "adam" ])
+ @provider.should_receive(:shell_out!).with(*command).and_return(true)
+ @provider.create_user
+ end
+
+ describe "and home is not specified for new system user resource" do
+
+ before do
+ @provider.new_resource.system true
+ # there is no public API to set attribute's value to nil
+ @provider.new_resource.instance_variable_set("@home", nil)
+ end
+
+ it "should not include -m or -d in the command options" do
+ command = ["useradd",
+ "-c", 'Adam Jacob',
+ "-g", '23']
+ command.concat(["-p", 'abracadabra']) if supported_useradd_options.key?("password")
+ command.concat([ "-s", '/usr/bin/zsh',
+ "-u", '1000',
+ "-r",
+ "adam" ])
+ @provider.should_receive(:shell_out!).with(*command).and_return(true)
+ @provider.create_user
+ end
+
+ end
+
+ end
+
+ describe "when managing a user" do
+ before(:each) do
+ @provider.new_resource.manage_home true
+ @provider.new_resource.home "/Users/mud"
+ @provider.new_resource.gid '23'
+ end
+
+ # CHEF-3423, -m must come before the username
+ it "runs usermod with the computed command options" do
+ command = ["usermod",
+ "-g", '23',
+ "-m",
+ "-d", '/Users/mud',
+ "adam" ]
+ @provider.should_receive(:shell_out!).with(*command).and_return(true)
+ @provider.manage_user
+ end
+
+ it "does not set the -r option to usermod" do
+ @new_resource.system(true)
+ command = ["usermod",
+ "-g", '23',
+ "-m",
+ "-d", '/Users/mud',
+ "adam" ]
+ @provider.should_receive(:shell_out!).with(*command).and_return(true)
+ @provider.manage_user
+ end
+
+ it "CHEF-3429: does not set -m if we aren't changing the home directory" do
+ @provider.should_receive(:updating_home?).and_return(false)
+ command = ["usermod",
+ "-g", '23',
+ "adam" ]
+ @provider.should_receive(:shell_out!).with(*command).and_return(true)
+ @provider.manage_user
+ end
+ end
+
+ describe "when removing a user" do
+
+ it "should run userdel with the new resources user name" do
+ @provider.should_receive(:shell_out!).with("userdel", @new_resource.username).and_return(true)
+ @provider.remove_user
+ end
+
+ it "should run userdel with the new resources user name and -r if manage_home is true" do
+ @new_resource.supports({ :manage_home => true,
+ :non_unique => false})
+ @provider.should_receive(:shell_out!).with("userdel", "-r", @new_resource.username).and_return(true)
+ @provider.remove_user
+ end
+
+ it "should run userdel with the new resources user name if non_unique is true" do
+ @new_resource.supports({ :manage_home => false,
+ :non_unique => true})
+ @provider.should_receive(:shell_out!).with("userdel", @new_resource.username).and_return(true)
+ @provider.remove_user
+ end
+ end
+
+ describe "when checking the lock" do
+ # lazy initialize so we can modify stdout and stderr strings
+ let(:passwd_s_status) do
+ mock("Mixlib::ShellOut command", :exitstatus => 0, :stdout => @stdout, :stderr => @stderr)
+ end
+
+ before(:each) do
+ # @node = Chef::Node.new
+ # @new_resource = mock("Chef::Resource::User",
+ # :nil_object => true,
+ # :username => "adam"
+ # )
+ #@provider = Chef::Provider::User::Useradd.new(@node, @new_resource)
+ @stdout = "root P 09/02/2008 0 99999 7 -1"
+ @stderr = ""
+ end
+
+ it "should return false if status begins with P" do
+ @provider.should_receive(:shell_out!).
+ with("passwd", "-S", @new_resource.username, {:returns=>[0, 1]}).
+ and_return(passwd_s_status)
+ @provider.check_lock.should eql(false)
+ end
+
+ it "should return false if status begins with N" do
+ @stdout = "root N"
+ @provider.should_receive(:shell_out!).
+ with("passwd", "-S", @new_resource.username, {:returns=>[0, 1]}).
+ and_return(passwd_s_status)
+ @provider.check_lock.should eql(false)
+ end
+
+ it "should return true if status begins with L" do
+ @stdout = "root L"
+ @provider.should_receive(:shell_out!).
+ with("passwd", "-S", @new_resource.username, {:returns=>[0, 1]}).
+ and_return(passwd_s_status)
+ @provider.check_lock.should eql(true)
+ end
+
+ it "should raise a Chef::Exceptions::User if passwd -S fails on anything other than redhat/centos" do
+ @node.automatic_attrs[:platform] = 'ubuntu'
+ @provider.should_receive(:shell_out!).
+ with("passwd", "-S", @new_resource.username, {:returns=>[0, 1]}).
+ and_return(passwd_s_status)
+ passwd_s_status.should_receive(:exitstatus).and_return(1)
+ lambda { @provider.check_lock }.should raise_error(Chef::Exceptions::User)
+ end
+
+ ['redhat', 'centos'].each do |os|
+ it "should not raise a Chef::Exceptions::User if passwd -S exits with 1 on #{os} and the passwd package is version 0.73-1" do
+ @node.automatic_attrs[:platform] = os
+ passwd_s_status.should_receive(:exitstatus).and_return(1)
+ @provider.should_receive(:shell_out!).
+ with("passwd", "-S", @new_resource.username, {:returns=>[0, 1]}).
+ and_return(passwd_s_status)
+ rpm_status = mock("Mixlib::ShellOut command", :exitstatus => 0, :stdout => "passwd-0.73-1\n", :stderr => "")
+ @provider.should_receive(:shell_out!).with("rpm -q passwd").and_return(rpm_status)
+ lambda { @provider.check_lock }.should_not raise_error(Chef::Exceptions::User)
+ end
+
+ it "should raise a Chef::Exceptions::User if passwd -S exits with 1 on #{os} and the passwd package is not version 0.73-1" do
+ @node.automatic_attrs[:platform] = os
+ passwd_s_status.should_receive(:exitstatus).and_return(1)
+ @provider.should_receive(:shell_out!).
+ with("passwd", "-S", @new_resource.username, {:returns=>[0, 1]}).
+ and_return(passwd_s_status)
+ rpm_status = mock("Mixlib::ShellOut command", :exitstatus => 0, :stdout => "passwd-0.73-2\n", :stderr => "")
+ @provider.should_receive(:shell_out!).with("rpm -q passwd").and_return(rpm_status)
+ lambda { @provider.check_lock }.should raise_error(Chef::Exceptions::User)
+ end
+
+ it "should raise a ShellCommandFailed exception if passwd -S exits with something other than 0 or 1 on #{os}" do
+ @node.automatic_attrs[:platform] = os
+ @provider.should_receive(:shell_out!).and_raise(Mixlib::ShellOut::ShellCommandFailed)
+ lambda { @provider.check_lock }.should raise_error(Mixlib::ShellOut::ShellCommandFailed)
+ end
+ end
+ end
+
+ describe "when locking the user" do
+ it "should run usermod -L with the new resources username" do
+ @provider.should_receive(:shell_out!).with("usermod", "-L", @new_resource.username)
+ @provider.lock_user
+ end
+ end
+
+ describe "when unlocking the user" do
+ it "should run usermod -L with the new resources username" do
+ @provider.should_receive(:shell_out!).with("usermod", "-U", @new_resource.username)
+ @provider.unlock_user
+ end
+ end
+
+ describe "when checking if home needs updating" do
+ [
+ {
+ "action" => "should return false if home matches",
+ "current_resource_home" => [ "/home/laurent" ],
+ "new_resource_home" => [ "/home/laurent" ],
+ "expected_result" => false
+ },
+ {
+ "action" => "should return true if home doesn't match",
+ "current_resource_home" => [ "/home/laurent" ],
+ "new_resource_home" => [ "/something/else" ],
+ "expected_result" => true
+ },
+ {
+ "action" => "should return false if home only differs by trailing slash",
+ "current_resource_home" => [ "/home/laurent" ],
+ "new_resource_home" => [ "/home/laurent/", "/home/laurent" ],
+ "expected_result" => false
+ },
+ {
+ "action" => "should return false if home is an equivalent path",
+ "current_resource_home" => [ "/home/laurent" ],
+ "new_resource_home" => [ "/home/./laurent", "/home/laurent" ],
+ "expected_result" => false
+ },
+ ].each do |home_check|
+ it home_check["action"] do
+ @provider.current_resource.home home_check["current_resource_home"].first
+ @current_home_mock = mock("Pathname")
+ @provider.new_resource.home home_check["new_resource_home"].first
+ @new_home_mock = mock("Pathname")
+
+ Pathname.should_receive(:new).with(@current_resource.home).and_return(@current_home_mock)
+ @current_home_mock.should_receive(:cleanpath).and_return(home_check["current_resource_home"].last)
+ Pathname.should_receive(:new).with(@new_resource.home).and_return(@new_home_mock)
+ @new_home_mock.should_receive(:cleanpath).and_return(home_check["new_resource_home"].last)
+
+ @provider.updating_home?.should == home_check["expected_result"]
+ end
+ end
+ it "should return true if the current home does not exist but a home is specified by the new resource" do
+ @new_resource = Chef::Resource::User.new("adam", @run_context)
+ @current_resource = Chef::Resource::User.new("adam", @run_context)
+ @provider = Chef::Provider::User::Useradd.new(@new_resource, @run_context)
+ @provider.current_resource = @current_resource
+ @current_resource.home nil
+ @new_resource.home "/home/kitten"
+
+ @provider.updating_home?.should == true
+ end
+ end
+end
+
diff --git a/spec/unit/provider/user/solaris_spec.rb b/spec/unit/provider/user/solaris_spec.rb
index 2353414dcc..92a73cd4c8 100644
--- a/spec/unit/provider/user/solaris_spec.rb
+++ b/spec/unit/provider/user/solaris_spec.rb
@@ -21,358 +21,68 @@
require 'spec_helper'
describe Chef::Provider::User::Solaris do
- before(:each) do
- @node = Chef::Node.new
- @events = Chef::EventDispatch::Dispatcher.new
- @run_context = Chef::RunContext.new(@node, {}, @events)
+ supported_useradd_options = {
+ 'comment' => "-c",
+ 'gid' => "-g",
+ 'uid' => "-u",
+ 'shell' => "-s"
+ }
- @new_resource = Chef::Resource::User.new("adam", @run_context)
- @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.system false
- @new_resource.manage_home false
- @new_resource.non_unique false
- @current_resource = Chef::Resource::User.new("adam", @run_context)
- @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"
- @current_resource.system false
- @current_resource.manage_home false
- @current_resource.non_unique false
- @current_resource.supports({:manage_home => false, :non_unique => false})
- @provider = Chef::Provider::User::Solaris.new(@new_resource, @run_context)
- @provider.current_resource = @current_resource
- end
-
- describe "when setting option" do
- field_list = {
- 'comment' => "-c",
- '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.universal_options
- end
-
- it "should set the option for #{attribute} if the new resources #{attribute} is not nil" do
- @new_resource.stub!(attribute).and_return("hola")
- @provider.universal_options.should eql(" #{option} 'hola'")
- end
-
- it "should set the option for #{attribute} if the new resources #{attribute} is not nil, without homedir management" do
- @new_resource.stub!(:supports).and_return({:manage_home => false,
- :non_unique => false})
- @new_resource.stub!(attribute).and_return("hola")
- @provider.universal_options.should eql(" #{option} 'hola'")
- end
-
- it "should set the option for #{attribute} if the new resources #{attribute} is not nil, without homedir management (using real attributes)" do
- @new_resource.stub!(:manage_home).and_return(false)
- @new_resource.stub!(:non_unique).and_return(false)
- @new_resource.stub!(attribute).and_return("hola")
- @provider.universal_options.should eql(" #{option} 'hola'")
- 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
- @provider.universal_options.should eql(match_string)
- end
-
- describe "when we want to set a password" do
- before do
- @new_resource.password "hocus-pocus"
- 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
-
- describe "when we want to create a system user" do
- before do
- @new_resource.manage_home(true)
- @new_resource.non_unique(false)
- end
-
- it "should set useradd -r" do
- @new_resource.system(true)
- @provider.useradd_options.should == " -r"
- end
- end
-
- describe "when the resource has a different home directory and supports home directory management" do
- before do
- @new_resource.stub!(:home).and_return("/wowaweea")
- @new_resource.stub!(:supports).and_return({:manage_home => true,
- :non_unique => false})
- end
-
- it "should set -m -d /homedir" do
- @provider.universal_options.should == " -m -d '/wowaweea'"
- @provider.useradd_options.should == ""
- end
- end
-
- describe "when the resource has a different home directory and supports home directory management (using real attributes)" do
- before do
- @new_resource.stub!(:home).and_return("/wowaweea")
- @new_resource.stub!(:manage_home).and_return(true)
- @new_resource.stub!(:non_unique).and_return(false)
- end
-
- it "should set -m -d /homedir" do
- @provider.universal_options.should eql(" -m -d '/wowaweea'")
- @provider.useradd_options.should == ""
- end
- end
+ include_examples "a useradd-based user provider", supported_useradd_options
- describe "when the resource supports non_unique ids" do
- before do
- @new_resource.stub!(:supports).and_return({:manage_home => false,
- :non_unique => true})
- end
-
- it "should set -m -o" do
- @provider.universal_options.should eql(" -o")
- end
- end
-
- describe "when the resource supports non_unique ids (using real attributes)" do
- before do
- @new_resource.stub!(:manage_home).and_return(false)
- @new_resource.stub!(:non_unique).and_return(true)
- end
-
- it "should set -m -o" do
- @provider.universal_options.should eql(" -o")
- end
- end
- end
-
- describe "when creating a user" do
+ describe "when we want to set a password" do
before(:each) do
- @current_resource = Chef::Resource::User.new(@new_resource.name, @run_context)
- @current_resource.username(@new_resource.username)
- @provider.current_resource = @current_resource
- @provider.new_resource.manage_home true
- @provider.new_resource.home "/Users/mud"
- @provider.new_resource.gid '23'
- end
-
- it "runs useradd with the computed command options" do
- command = "useradd -c 'Adam Jacob' -g '23' -s '/usr/bin/zsh' -u '1000' -m -d '/Users/mud' adam"
- @provider.should_receive(:shell_out!).with(command).and_return(true)
- @provider.should_receive(:manage_password).and_return(nil)
- @provider.create_user
- end
+ @node = Chef::Node.new
+ @events = Chef::EventDispatch::Dispatcher.new
+ @run_context = Chef::RunContext.new(@node, {}, @events)
- describe "and home is not specified for new system user resource" do
-
- before do
- @provider.new_resource.system true
- # there is no public API to set attribute's value to nil
- @provider.new_resource.instance_variable_set("@home", nil)
- end
-
- it "should not include -m or -d in the command options" do
- command = "useradd -c 'Adam Jacob' -g '23' -s '/usr/bin/zsh' -u '1000' -r adam"
- @provider.should_receive(:shell_out!).with(command).and_return(true)
- @provider.should_receive(:manage_password).and_return(nil)
- @provider.create_user
- end
-
- end
-
- end
-
- describe "when managing a user" do
- before(:each) do
- @provider.new_resource.manage_home true
- @provider.new_resource.home "/Users/mud"
- @provider.new_resource.gid '23'
- end
+ @new_resource = Chef::Resource::User.new("adam", @run_context)
+ @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.system false
+ @new_resource.manage_home false
+ @new_resource.non_unique false
+ @current_resource = Chef::Resource::User.new("adam", @run_context)
+ @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"
+ @current_resource.system false
+ @current_resource.manage_home false
+ @current_resource.non_unique false
+ @current_resource.supports({:manage_home => false, :non_unique => false})
+ @provider = Chef::Provider::User::Solaris.new(@new_resource, @run_context)
+ @provider.current_resource = @current_resource
- # CHEF-3423, -m must come before the username
- it "runs usermod with the computed command options" do
- @provider.should_receive(:shell_out!).with("usermod -g '23' -m -d '/Users/mud' adam").and_return(true)
- @provider.manage_user
+ @new_resource.password "hocus-pocus"
end
- it "does not set the -r option to usermod" do
- @new_resource.system(true)
- @provider.should_receive(:shell_out!).with("usermod -g '23' -m -d '/Users/mud' adam").and_return(true)
+ 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 "CHEF-3429: does not set -m if we aren't changing the home directory" do
- @provider.should_receive(:updating_home?).and_return(false)
- @provider.should_receive(:shell_out!).with("usermod -g '23' adam").and_return(true)
+ 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
- describe "when removing a user" do
-
- it "should run userdel with the new resources user name" do
- @provider.should_receive(:shell_out!).with("userdel #{@new_resource.username}").and_return(true)
- @provider.remove_user
- end
-
- it "should run userdel with the new resources user name and -r if manage_home is true" do
- @new_resource.stub!(:supports).and_return({ :manage_home => true,
- :non_unique => false})
- @provider.should_receive(:shell_out!).with("userdel -r #{@new_resource.username}").and_return(true)
- @provider.remove_user
- end
-
- it "should run userdel with the new resources user name if non_unique is true" do
- @new_resource.stub!(:supports).and_return({ :manage_home => false,
- :non_unique => true})
- @provider.should_receive(:shell_out!).with("userdel #{@new_resource.username}").and_return(true)
- @provider.remove_user
- end
- end
-
- describe "when checking the lock" do
- # lazy initialize so we can modify stdout and stderr strings
- let(:passwd_s_status) do
- mock("Mixlib::ShellOut command", :exitstatus => 0, :stdout => @stdout, :stderr => @stderr)
- end
-
- before(:each) do
- # @node = Chef::Node.new
- # @new_resource = mock("Chef::Resource::User",
- # :nil_object => true,
- # :username => "adam"
- # )
- #@provider = Chef::Provider::User::Useradd.new(@node, @new_resource)
- @stdout = "root P 09/02/2008 0 99999 7 -1"
- @stderr = ""
- end
-
- it "should return false if status begins with P" do
- @provider.should_receive(:shell_out!).with("passwd -S #{@new_resource.username}", {:returns=>[0, 1]}).and_return(passwd_s_status)
- @provider.check_lock.should eql(false)
- end
-
- it "should return false if status begins with N" do
- @stdout = "root N"
- @provider.should_receive(:shell_out!).with("passwd -S #{@new_resource.username}", {:returns=>[0, 1]}).and_return(passwd_s_status)
- @provider.check_lock.should eql(false)
- end
-
- it "should return true if status begins with L" do
- @stdout = "root L"
- @provider.should_receive(:shell_out!).with("passwd -S #{@new_resource.username}", {:returns=>[0, 1]}).and_return(passwd_s_status)
- @provider.check_lock.should eql(true)
- end
-
- it "should raise a Chef::Exceptions::User if passwd -S fails" do
- @node.automatic_attrs[:platform] = 'solaris2'
- @provider.should_receive(:shell_out!).with("passwd -S #{@new_resource.username}", {:returns=>[0, 1]}).and_return(passwd_s_status)
- passwd_s_status.should_receive(:exitstatus).and_return(1)
- lambda { @provider.check_lock }.should raise_error(Chef::Exceptions::User)
- end
- end
-
- describe "when locking the user" do
- it "should run usermod -L with the new resources username" do
- @provider.should_receive(:shell_out!).with("usermod -L #{@new_resource.username}")
- @provider.lock_user
- end
- end
-
- describe "when unlocking the user" do
- it "should run usermod -L with the new resources username" do
- @provider.should_receive(:shell_out!).with("usermod -U #{@new_resource.username}")
- @provider.unlock_user
- end
- end
-
- describe "when checking if home needs updating" do
- [
- {
- "action" => "should return false if home matches",
- "current_resource_home" => [ "/home/laurent" ],
- "new_resource_home" => [ "/home/laurent" ],
- "expected_result" => false
- },
- {
- "action" => "should return true if home doesn't match",
- "current_resource_home" => [ "/home/laurent" ],
- "new_resource_home" => [ "/something/else" ],
- "expected_result" => true
- },
- {
- "action" => "should return false if home only differs by trailing slash",
- "current_resource_home" => [ "/home/laurent" ],
- "new_resource_home" => [ "/home/laurent/", "/home/laurent" ],
- "expected_result" => false
- },
- {
- "action" => "should return false if home is an equivalent path",
- "current_resource_home" => [ "/home/laurent" ],
- "new_resource_home" => [ "/home/./laurent", "/home/laurent" ],
- "expected_result" => false
- },
- ].each do |home_check|
- it home_check["action"] do
- @provider.current_resource.home home_check["current_resource_home"].first
- @current_home_mock = mock("Pathname")
- @provider.new_resource.home home_check["new_resource_home"].first
- @new_home_mock = mock("Pathname")
-
- Pathname.should_receive(:new).with(@current_resource.home).and_return(@current_home_mock)
- @current_home_mock.should_receive(:cleanpath).and_return(home_check["current_resource_home"].last)
- Pathname.should_receive(:new).with(@new_resource.home).and_return(@new_home_mock)
- @new_home_mock.should_receive(:cleanpath).and_return(home_check["new_resource_home"].last)
-
- @provider.updating_home?.should == home_check["expected_result"]
- end
- end
- it "should return true if the current home does not exist but a home is specified by the new resource" do
- @new_resource = Chef::Resource::User.new("adam", @run_context)
- @current_resource = Chef::Resource::User.new("adam", @run_context)
- @provider = Chef::Provider::User::Solaris.new(@new_resource, @run_context)
- @provider.current_resource = @current_resource
- @current_resource.home nil
- @new_resource.home "/home/kitten"
-
- @provider.updating_home?.should == true
- end
- end
end
diff --git a/spec/unit/provider/user/useradd_spec.rb b/spec/unit/provider/user/useradd_spec.rb
index 61719e7d65..0cb93db577 100644
--- a/spec/unit/provider/user/useradd_spec.rb
+++ b/spec/unit/provider/user/useradd_spec.rb
@@ -21,356 +21,12 @@
require 'spec_helper'
describe Chef::Provider::User::Useradd 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)
- @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.system false
- @new_resource.manage_home false
- @new_resource.non_unique false
- @current_resource = Chef::Resource::User.new("adam", @run_context)
- @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"
- @current_resource.system false
- @current_resource.manage_home false
- @current_resource.non_unique false
- @current_resource.supports({:manage_home => false, :non_unique => false})
- @provider = Chef::Provider::User::Useradd.new(@new_resource, @run_context)
- @provider.current_resource = @current_resource
- end
-
- describe "when setting option" do
- field_list = {
- 'comment' => "-c",
- 'gid' => "-g",
- 'uid' => "-u",
- 'shell' => "-s",
- 'password' => "-p"
- }
-
- 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.universal_options
- end
-
- it "should set the option for #{attribute} if the new resources #{attribute} is not nil" do
- @new_resource.stub!(attribute).and_return("hola")
- @provider.universal_options.should eql(" #{option} 'hola'")
- end
-
- it "should set the option for #{attribute} if the new resources #{attribute} is not nil, without homedir management" do
- @new_resource.stub!(:supports).and_return({:manage_home => false,
- :non_unique => false})
- @new_resource.stub!(attribute).and_return("hola")
- @provider.universal_options.should eql(" #{option} 'hola'")
- end
-
- it "should set the option for #{attribute} if the new resources #{attribute} is not nil, without homedir management (using real attributes)" do
- @new_resource.stub!(:manage_home).and_return(false)
- @new_resource.stub!(:non_unique).and_return(false)
- @new_resource.stub!(attribute).and_return("hola")
- @provider.universal_options.should eql(" #{option} 'hola'")
- 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
- @provider.universal_options.should eql(match_string)
- end
-
- describe "when we want to create a system user" do
- before do
- @new_resource.manage_home(true)
- @new_resource.non_unique(false)
- end
-
- it "should set useradd -r" do
- @new_resource.system(true)
- @provider.useradd_options.should == " -r"
- end
- end
-
- describe "when the resource has a different home directory and supports home directory management" do
- before do
- @new_resource.stub!(:home).and_return("/wowaweea")
- @new_resource.stub!(:supports).and_return({:manage_home => true,
- :non_unique => false})
- end
-
- it "should set -m -d /homedir" do
- @provider.universal_options.should == " -m -d '/wowaweea'"
- @provider.useradd_options.should == ""
- end
- end
-
- describe "when the resource has a different home directory and supports home directory management (using real attributes)" do
- before do
- @new_resource.stub!(:home).and_return("/wowaweea")
- @new_resource.stub!(:manage_home).and_return(true)
- @new_resource.stub!(:non_unique).and_return(false)
- end
-
- it "should set -m -d /homedir" do
- @provider.universal_options.should eql(" -m -d '/wowaweea'")
- @provider.useradd_options.should == ""
- end
- end
-
- describe "when the resource supports non_unique ids" do
- before do
- @new_resource.stub!(:supports).and_return({:manage_home => false,
- :non_unique => true})
- end
-
- it "should set -m -o" do
- @provider.universal_options.should eql(" -o")
- end
- end
-
- describe "when the resource supports non_unique ids (using real attributes)" do
- before do
- @new_resource.stub!(:manage_home).and_return(false)
- @new_resource.stub!(:non_unique).and_return(true)
- end
-
- it "should set -m -o" do
- @provider.universal_options.should eql(" -o")
- end
- end
- end
-
- describe "when creating a user" do
- before(:each) do
- @current_resource = Chef::Resource::User.new(@new_resource.name, @run_context)
- @current_resource.username(@new_resource.username)
- @provider.current_resource = @current_resource
- @provider.new_resource.manage_home true
- @provider.new_resource.home "/Users/mud"
- @provider.new_resource.gid '23'
- end
-
- it "runs useradd with the computed command options" do
- command = "useradd -c 'Adam Jacob' -g '23' -p 'abracadabra' -s '/usr/bin/zsh' -u '1000' -m -d '/Users/mud' adam"
- @provider.should_receive(:shell_out!).with(command).and_return(true)
- @provider.create_user
- end
-
- describe "and home is not specified for new system user resource" do
-
- before do
- @provider.new_resource.system true
- # there is no public API to set attribute's value to nil
- @provider.new_resource.instance_variable_set("@home", nil)
- end
-
- it "should not include -m or -d in the command options" do
- command = "useradd -c 'Adam Jacob' -g '23' -p 'abracadabra' -s '/usr/bin/zsh' -u '1000' -r adam"
- @provider.should_receive(:shell_out!).with(command).and_return(true)
- @provider.create_user
- end
-
- end
-
- end
-
- describe "when managing a user" do
- before(:each) do
- @provider.new_resource.manage_home true
- @provider.new_resource.home "/Users/mud"
- @provider.new_resource.gid '23'
- end
-
- # CHEF-3423, -m must come before the username
- it "runs usermod with the computed command options" do
- @provider.should_receive(:shell_out!).with("usermod -g '23' -m -d '/Users/mud' adam").and_return(true)
- @provider.manage_user
- end
-
- it "does not set the -r option to usermod" do
- @new_resource.system(true)
- @provider.should_receive(:shell_out!).with("usermod -g '23' -m -d '/Users/mud' adam").and_return(true)
- @provider.manage_user
- end
-
- it "CHEF-3429: does not set -m if we aren't changing the home directory" do
- @provider.should_receive(:updating_home?).and_return(false)
- @provider.should_receive(:shell_out!).with("usermod -g '23' adam").and_return(true)
- @provider.manage_user
- end
- end
-
- describe "when removing a user" do
-
- it "should run userdel with the new resources user name" do
- @provider.should_receive(:shell_out!).with("userdel #{@new_resource.username}").and_return(true)
- @provider.remove_user
- end
-
- it "should run userdel with the new resources user name and -r if manage_home is true" do
- @new_resource.stub!(:supports).and_return({ :manage_home => true,
- :non_unique => false})
- @provider.should_receive(:shell_out!).with("userdel -r #{@new_resource.username}").and_return(true)
- @provider.remove_user
- end
-
- it "should run userdel with the new resources user name if non_unique is true" do
- @new_resource.stub!(:supports).and_return({ :manage_home => false,
- :non_unique => true})
- @provider.should_receive(:shell_out!).with("userdel #{@new_resource.username}").and_return(true)
- @provider.remove_user
- end
- end
-
- describe "when checking the lock" do
- # lazy initialize so we can modify stdout and stderr strings
- let(:passwd_s_status) do
- mock("Mixlib::ShellOut command", :exitstatus => 0, :stdout => @stdout, :stderr => @stderr)
- end
-
- before(:each) do
- # @node = Chef::Node.new
- # @new_resource = mock("Chef::Resource::User",
- # :nil_object => true,
- # :username => "adam"
- # )
- #@provider = Chef::Provider::User::Useradd.new(@node, @new_resource)
- @stdout = "root P 09/02/2008 0 99999 7 -1"
- @stderr = ""
- end
-
- it "should return false if status begins with P" do
- @provider.should_receive(:shell_out!).with("passwd -S #{@new_resource.username}", {:returns=>[0, 1]}).and_return(passwd_s_status)
- @provider.check_lock.should eql(false)
- end
-
- it "should return false if status begins with N" do
- @stdout = "root N"
- @provider.should_receive(:shell_out!).with("passwd -S #{@new_resource.username}", {:returns=>[0, 1]}).and_return(passwd_s_status)
- @provider.check_lock.should eql(false)
- end
-
- it "should return true if status begins with L" do
- @stdout = "root L"
- @provider.should_receive(:shell_out!).with("passwd -S #{@new_resource.username}", {:returns=>[0, 1]}).and_return(passwd_s_status)
- @provider.check_lock.should eql(true)
- end
-
- it "should raise a Chef::Exceptions::User if passwd -S fails on anything other than redhat/centos" do
- @node.automatic_attrs[:platform] = 'ubuntu'
- @provider.should_receive(:shell_out!).with("passwd -S #{@new_resource.username}", {:returns=>[0, 1]}).and_return(passwd_s_status)
- passwd_s_status.should_receive(:exitstatus).and_return(1)
- lambda { @provider.check_lock }.should raise_error(Chef::Exceptions::User)
- end
-
- ['redhat', 'centos'].each do |os|
- it "should not raise a Chef::Exceptions::User if passwd -S exits with 1 on #{os} and the passwd package is version 0.73-1" do
- @node.automatic_attrs[:platform] = os
- passwd_s_status.should_receive(:exitstatus).and_return(1)
- @provider.should_receive(:shell_out!).with("passwd -S #{@new_resource.username}", {:returns=>[0, 1]}).and_return(passwd_s_status)
- rpm_status = mock("Mixlib::ShellOut command", :exitstatus => 0, :stdout => "passwd-0.73-1\n", :stderr => "")
- @provider.should_receive(:shell_out!).with("rpm -q passwd").and_return(rpm_status)
- lambda { @provider.check_lock }.should_not raise_error(Chef::Exceptions::User)
- end
-
- it "should raise a Chef::Exceptions::User if passwd -S exits with 1 on #{os} and the passwd package is not version 0.73-1" do
- @node.automatic_attrs[:platform] = os
- passwd_s_status.should_receive(:exitstatus).and_return(1)
- @provider.should_receive(:shell_out!).with("passwd -S #{@new_resource.username}", {:returns=>[0, 1]}).and_return(passwd_s_status)
- rpm_status = mock("Mixlib::ShellOut command", :exitstatus => 0, :stdout => "passwd-0.73-2\n", :stderr => "")
- @provider.should_receive(:shell_out!).with("rpm -q passwd").and_return(rpm_status)
- lambda { @provider.check_lock }.should raise_error(Chef::Exceptions::User)
- end
-
- it "should raise a ShellCommandFailed exception if passwd -S exits with something other than 0 or 1 on #{os}" do
- @node.automatic_attrs[:platform] = os
- @provider.should_receive(:shell_out!).and_raise(Mixlib::ShellOut::ShellCommandFailed)
- lambda { @provider.check_lock }.should raise_error(Mixlib::ShellOut::ShellCommandFailed)
- end
- end
- end
-
- describe "when locking the user" do
- it "should run usermod -L with the new resources username" do
- @provider.should_receive(:shell_out!).with("usermod -L #{@new_resource.username}")
- @provider.lock_user
- end
- end
-
- describe "when unlocking the user" do
- it "should run usermod -L with the new resources username" do
- @provider.should_receive(:shell_out!).with("usermod -U #{@new_resource.username}")
- @provider.unlock_user
- end
- end
-
- describe "when checking if home needs updating" do
- [
- {
- "action" => "should return false if home matches",
- "current_resource_home" => [ "/home/laurent" ],
- "new_resource_home" => [ "/home/laurent" ],
- "expected_result" => false
- },
- {
- "action" => "should return true if home doesn't match",
- "current_resource_home" => [ "/home/laurent" ],
- "new_resource_home" => [ "/something/else" ],
- "expected_result" => true
- },
- {
- "action" => "should return false if home only differs by trailing slash",
- "current_resource_home" => [ "/home/laurent" ],
- "new_resource_home" => [ "/home/laurent/", "/home/laurent" ],
- "expected_result" => false
- },
- {
- "action" => "should return false if home is an equivalent path",
- "current_resource_home" => [ "/home/laurent" ],
- "new_resource_home" => [ "/home/./laurent", "/home/laurent" ],
- "expected_result" => false
- },
- ].each do |home_check|
- it home_check["action"] do
- @provider.current_resource.home home_check["current_resource_home"].first
- @current_home_mock = mock("Pathname")
- @provider.new_resource.home home_check["new_resource_home"].first
- @new_home_mock = mock("Pathname")
-
- Pathname.should_receive(:new).with(@current_resource.home).and_return(@current_home_mock)
- @current_home_mock.should_receive(:cleanpath).and_return(home_check["current_resource_home"].last)
- Pathname.should_receive(:new).with(@new_resource.home).and_return(@new_home_mock)
- @new_home_mock.should_receive(:cleanpath).and_return(home_check["new_resource_home"].last)
-
- @provider.updating_home?.should == home_check["expected_result"]
- end
- end
- it "should return true if the current home does not exist but a home is specified by the new resource" do
- @new_resource = Chef::Resource::User.new("adam", @run_context)
- @current_resource = Chef::Resource::User.new("adam", @run_context)
- @provider = Chef::Provider::User::Useradd.new(@new_resource, @run_context)
- @provider.current_resource = @current_resource
- @current_resource.home nil
- @new_resource.home "/home/kitten"
-
- @provider.updating_home?.should == true
- end
- end
+ supported_useradd_options = {
+ 'comment' => "-c",
+ 'gid' => "-g",
+ 'uid' => "-u",
+ 'shell' => "-s",
+ 'password' => "-p"
+ }
+ include_examples "a useradd-based user provider", supported_useradd_options
end