summaryrefslogtreecommitdiff
path: root/spec/unit/provider/group
diff options
context:
space:
mode:
Diffstat (limited to 'spec/unit/provider/group')
-rw-r--r--spec/unit/provider/group/dscl_spec.rb294
-rw-r--r--spec/unit/provider/group/gpasswd_spec.rb108
-rw-r--r--spec/unit/provider/group/groupadd_spec.rb161
-rw-r--r--spec/unit/provider/group/groupmod_spec.rb134
-rw-r--r--spec/unit/provider/group/pw_spec.rb140
-rw-r--r--spec/unit/provider/group/usermod_spec.rb95
-rw-r--r--spec/unit/provider/group/windows_spec.rb94
7 files changed, 1026 insertions, 0 deletions
diff --git a/spec/unit/provider/group/dscl_spec.rb b/spec/unit/provider/group/dscl_spec.rb
new file mode 100644
index 0000000000..b526848dfd
--- /dev/null
+++ b/spec/unit/provider/group/dscl_spec.rb
@@ -0,0 +1,294 @@
+#
+# 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 = mock("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 = mock("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.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(Chef::Exceptions::Group)
+ 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(: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
diff --git a/spec/unit/provider/group/gpasswd_spec.rb b/spec/unit/provider/group/gpasswd_spec.rb
new file mode 100644
index 0000000000..59da88e851
--- /dev/null
+++ b/spec/unit/provider/group/gpasswd_spec.rb
@@ -0,0 +1,108 @@
+#
+# 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.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(Chef::Exceptions::Group)
+ 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 "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.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
+
+ 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
diff --git a/spec/unit/provider/group/groupadd_spec.rb b/spec/unit/provider/group/groupadd_spec.rb
new file mode 100644
index 0000000000..f08e14f99b
--- /dev/null
+++ b/spec/unit/provider/group/groupadd_spec.rb
@@ -0,0 +1,161 @@
+#
+# 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
+ @current_resource = Chef::Resource::Group.new("aj")
+ @current_resource.gid(50)
+ @current_resource.members(["root", "aj"])
+ @current_resource.system 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
+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
+
+ describe "modify_group_members" do
+
+ it "should raise an error when calling modify_group_members" do
+ lambda { @provider.modify_group_members ; @provider.converge }.should raise_error(Chef::Exceptions::Group, "you must override modify_group_members 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
new file mode 100644
index 0000000000..c9c56313b5
--- /dev/null
+++ b/spec/unit/provider/group/groupmod_spec.rb
@@ -0,0 +1,134 @@
+#
+# 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(Chef::Exceptions::Group)
+ 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")
+ Chef::Log.should_receive(:debug).with("group[wheel] removing members lobster, rage, fist")
+ @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
new file mode 100644
index 0000000000..a7dbdb8615
--- /dev/null
+++ b/spec/unit/provider/group/pw_spec.rb
@@ -0,0 +1,140 @@
+#
+# 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)
+ @provider.should_receive(:run_command).with({ :command => "pw groupmod wheel -g '42' -M 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 log an appropriate message" do
+ Chef::Log.should_receive(:debug).with("group[wheel] not changing group members, the group has no members")
+ @provider.set_members_option
+ end
+
+ it "should set no options" do
+ @provider.set_members_option.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_option
+ end
+
+ it "should set the -d option with the members joined by ','" do
+ @provider.set_members_option.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] setting group members to all, your, base")
+ @provider.set_members_option
+ end
+
+ it "should set the -M option with the members joined by ','" do
+ @provider.set_members_option.should eql(" -M all,your,base")
+ end
+ end
+ end
+
+ describe"load_current_resource" do
+ before (:each) do
+ @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(Chef::Exceptions::Group)
+ end
+ end
+end
diff --git a/spec/unit/provider/group/usermod_spec.rb b/spec/unit/provider/group/usermod_spec.rb
new file mode 100644
index 0000000000..6e6e275a7a
--- /dev/null
+++ b/spec/unit/provider/group/usermod_spec.rb
@@ -0,0 +1,95 @@
+#
+# 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" ]
+ @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!(:members).and_return([])
+ end
+
+ it "should log an appropriate message" do
+ Chef::Log.should_receive(:debug).with("group[wheel] not changing group members, the group has no members")
+ @provider.modify_group_members
+ end
+ end
+
+ describe "with supplied members" do
+ platforms = {
+ "openbsd" => "-G",
+ "netbsd" => "-G",
+ "solaris" => "-a -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
+
+ platforms.each do |platform, flags|
+ it "should usermod each user when the append option is set on #{platform}" do
+ @node.automatic_attrs[:platform] = platform
+ @new_resource.stub!(:append).and_return(true)
+ @provider.should_receive(:run_command).with({:command => "usermod #{flags} wheel all"})
+ @provider.should_receive(:run_command).with({:command => "usermod #{flags} wheel your"})
+ @provider.should_receive(:run_command).with({:command => "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.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(Chef::Exceptions::Group)
+ end
+ end
+end
diff --git a/spec/unit/provider/group/windows_spec.rb b/spec/unit/provider/group/windows_spec.rb
new file mode 100644
index 0000000000..084d1d0acf
--- /dev/null
+++ b/spec/unit/provider/group/windows_spec.rb
@@ -0,0 +1,94 @@
+#
+# 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 = mock("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.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
+
+ it "should call @net_group.local_set_members if append fails" do
+ @new_resource.stub!(:append).and_return(true)
+ @net_group.stub!(:local_add_members).and_raise(ArgumentError)
+ @net_group.should_receive(:local_add_members).with(@new_resource.members)
+ @net_group.should_receive(:local_set_members).with(@new_resource.members + @current_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