diff options
author | Stig Sandbeck Mathisen <ssm@debian.org> | 2014-09-07 10:14:36 +0200 |
---|---|---|
committer | Stig Sandbeck Mathisen <ssm@debian.org> | 2014-09-07 10:14:36 +0200 |
commit | d4b83be375ac1dead058e091191ee7c7b7c24c8a (patch) | |
tree | dc825687392ae3068de5b764be60c53122d9e02a /spec/unit/util/windows | |
parent | 229cbb976fe0f70f5f30548b83517b415840f9bb (diff) | |
parent | 1681684857c6e39d60d87b0b3520d8783977ceff (diff) | |
download | puppet-upstream/3.7.0.tar.gz |
Imported Upstream version 3.7.0upstream/3.7.0
Diffstat (limited to 'spec/unit/util/windows')
-rw-r--r-- | spec/unit/util/windows/access_control_entry_spec.rb | 2 | ||||
-rwxr-xr-x | spec/unit/util/windows/adsi_spec.rb | 440 | ||||
-rw-r--r-- | spec/unit/util/windows/api_types_spec.rb | 28 | ||||
-rwxr-xr-x | spec/unit/util/windows/registry_spec.rb | 13 | ||||
-rwxr-xr-x | spec/unit/util/windows/sid_spec.rb | 9 | ||||
-rw-r--r-- | spec/unit/util/windows/string_spec.rb | 4 |
6 files changed, 483 insertions, 13 deletions
diff --git a/spec/unit/util/windows/access_control_entry_spec.rb b/spec/unit/util/windows/access_control_entry_spec.rb index b139b0d42..8d3f51c8a 100644 --- a/spec/unit/util/windows/access_control_entry_spec.rb +++ b/spec/unit/util/windows/access_control_entry_spec.rb @@ -5,7 +5,7 @@ require 'puppet/util/windows' describe "Puppet::Util::Windows::AccessControlEntry", :if => Puppet.features.microsoft_windows? do let(:klass) { Puppet::Util::Windows::AccessControlEntry } let(:sid) { 'S-1-5-18' } - let(:mask) { Windows::File::FILE_ALL_ACCESS } + let(:mask) { Puppet::Util::Windows::File::FILE_ALL_ACCESS } it "creates an access allowed ace" do ace = klass.new(sid, mask) diff --git a/spec/unit/util/windows/adsi_spec.rb b/spec/unit/util/windows/adsi_spec.rb new file mode 100755 index 000000000..f569d91e9 --- /dev/null +++ b/spec/unit/util/windows/adsi_spec.rb @@ -0,0 +1,440 @@ +#!/usr/bin/env ruby + +require 'spec_helper' + +require 'puppet/util/windows' + +describe Puppet::Util::Windows::ADSI, :if => Puppet.features.microsoft_windows? do + let(:connection) { stub 'connection' } + + before(:each) do + Puppet::Util::Windows::ADSI.instance_variable_set(:@computer_name, 'testcomputername') + Puppet::Util::Windows::ADSI.stubs(:connect).returns connection + end + + after(:each) do + Puppet::Util::Windows::ADSI.instance_variable_set(:@computer_name, nil) + end + + it "should generate the correct URI for a resource" do + Puppet::Util::Windows::ADSI.uri('test', 'user').should == "WinNT://./test,user" + end + + it "should be able to get the name of the computer" do + Puppet::Util::Windows::ADSI.computer_name.should == 'testcomputername' + end + + it "should be able to provide the correct WinNT base URI for the computer" do + Puppet::Util::Windows::ADSI.computer_uri.should == "WinNT://." + end + + it "should generate a fully qualified WinNT URI" do + Puppet::Util::Windows::ADSI.computer_uri('testcomputername').should == "WinNT://testcomputername" + end + + describe ".sid_for_account" do + it "should return nil if the account does not exist" do + Puppet::Util::Windows::SID.expects(:name_to_sid).with('foobar').returns nil + + Puppet::Util::Windows::ADSI.sid_for_account('foobar').should be_nil + end + + it "should return a SID for a passed user or group name" do + Puppet::Util::Windows::SID.expects(:name_to_sid).with('testers').returns 'S-1-5-32-547' + + Puppet::Util::Windows::ADSI.sid_for_account('testers').should == 'S-1-5-32-547' + end + + it "should return a SID for a passed fully-qualified user or group name" do + Puppet::Util::Windows::SID.expects(:name_to_sid).with('MACHINE\testers').returns 'S-1-5-32-547' + + Puppet::Util::Windows::ADSI.sid_for_account('MACHINE\testers').should == 'S-1-5-32-547' + end + end + + describe ".computer_name" do + it "should return a non-empty ComputerName string" do + Puppet::Util::Windows::ADSI.instance_variable_set(:@computer_name, nil) + Puppet::Util::Windows::ADSI.computer_name.should_not be_empty + end + end + + describe ".sid_uri" do + it "should raise an error when the input is not a SID object" do + [Object.new, {}, 1, :symbol, '', nil].each do |input| + expect { + Puppet::Util::Windows::ADSI.sid_uri(input) + }.to raise_error(Puppet::Error, /Must use a valid SID object/) + end + end + + it "should return a SID uri for a well-known SID (SYSTEM)" do + sid = Win32::Security::SID.new('SYSTEM') + Puppet::Util::Windows::ADSI.sid_uri(sid).should == 'WinNT://S-1-5-18' + end + end + + describe Puppet::Util::Windows::ADSI::User do + let(:username) { 'testuser' } + let(:domain) { 'DOMAIN' } + let(:domain_username) { "#{domain}\\#{username}"} + + it "should generate the correct URI" do + Puppet::Util::Windows::ADSI.stubs(:sid_uri_safe).returns(nil) + Puppet::Util::Windows::ADSI::User.uri(username).should == "WinNT://./#{username},user" + end + + it "should generate the correct URI for a user with a domain" do + Puppet::Util::Windows::ADSI.stubs(:sid_uri_safe).returns(nil) + Puppet::Util::Windows::ADSI::User.uri(username, domain).should == "WinNT://#{domain}/#{username},user" + end + + it "should be able to parse a username without a domain" do + Puppet::Util::Windows::ADSI::User.parse_name(username).should == [username, '.'] + end + + it "should be able to parse a username with a domain" do + Puppet::Util::Windows::ADSI::User.parse_name(domain_username).should == [username, domain] + end + + it "should raise an error with a username that contains a /" do + expect { + Puppet::Util::Windows::ADSI::User.parse_name("#{domain}/#{username}") + }.to raise_error(Puppet::Error, /Value must be in DOMAIN\\user style syntax/) + end + + it "should be able to create a user" do + adsi_user = stub('adsi') + + connection.expects(:Create).with('user', username).returns(adsi_user) + Puppet::Util::Windows::ADSI::Group.expects(:exists?).with(username).returns(false) + + user = Puppet::Util::Windows::ADSI::User.create(username) + + user.should be_a(Puppet::Util::Windows::ADSI::User) + user.native_user.should == adsi_user + end + + it "should be able to check the existence of a user" do + Puppet::Util::Windows::ADSI.stubs(:sid_uri_safe).returns(nil) + Puppet::Util::Windows::ADSI.expects(:connect).with("WinNT://./#{username},user").returns connection + Puppet::Util::Windows::ADSI::User.exists?(username).should be_true + end + + it "should be able to check the existence of a domain user" do + Puppet::Util::Windows::ADSI.stubs(:sid_uri_safe).returns(nil) + Puppet::Util::Windows::ADSI.expects(:connect).with("WinNT://#{domain}/#{username},user").returns connection + Puppet::Util::Windows::ADSI::User.exists?(domain_username).should be_true + end + + it "should be able to confirm the existence of a user with a well-known SID" do + + system_user = Win32::Security::SID::LocalSystem + # ensure that the underlying OS is queried here + Puppet::Util::Windows::ADSI.unstub(:connect) + Puppet::Util::Windows::ADSI::User.exists?(system_user).should be_true + end + + it "should return nil with an unknown SID" do + + bogus_sid = 'S-1-2-3-4' + # ensure that the underlying OS is queried here + Puppet::Util::Windows::ADSI.unstub(:connect) + Puppet::Util::Windows::ADSI::User.exists?(bogus_sid).should be_false + end + + it "should be able to delete a user" do + connection.expects(:Delete).with('user', username) + + Puppet::Util::Windows::ADSI::User.delete(username) + end + + it "should return an enumeration of IADsUser wrapped objects" do + Puppet::Util::Windows::ADSI.stubs(:sid_uri_safe).returns(nil) + + name = 'Administrator' + wmi_users = [stub('WMI', :name => name)] + Puppet::Util::Windows::ADSI.expects(:execquery).with('select name from win32_useraccount where localaccount = "TRUE"').returns(wmi_users) + + native_user = stub('IADsUser') + homedir = "C:\\Users\\#{name}" + native_user.expects(:Get).with('HomeDirectory').returns(homedir) + Puppet::Util::Windows::ADSI.expects(:connect).with("WinNT://./#{name},user").returns(native_user) + + users = Puppet::Util::Windows::ADSI::User.to_a + users.length.should == 1 + users[0].name.should == name + users[0]['HomeDirectory'].should == homedir + end + + describe "an instance" do + let(:adsi_user) { stub('user', :objectSID => []) } + let(:sid) { stub(:account => username, :domain => 'testcomputername') } + let(:user) { Puppet::Util::Windows::ADSI::User.new(username, adsi_user) } + + it "should provide its groups as a list of names" do + names = ["group1", "group2"] + + groups = names.map { |name| mock('group', :Name => name) } + + adsi_user.expects(:Groups).returns(groups) + + user.groups.should =~ names + end + + it "should be able to test whether a given password is correct" do + Puppet::Util::Windows::ADSI::User.expects(:logon).with(username, 'pwdwrong').returns(false) + Puppet::Util::Windows::ADSI::User.expects(:logon).with(username, 'pwdright').returns(true) + + user.password_is?('pwdwrong').should be_false + user.password_is?('pwdright').should be_true + end + + it "should be able to set a password" do + adsi_user.expects(:SetPassword).with('pwd') + adsi_user.expects(:SetInfo).at_least_once + + flagname = "UserFlags" + fADS_UF_DONT_EXPIRE_PASSWD = 0x10000 + + adsi_user.expects(:Get).with(flagname).returns(0) + adsi_user.expects(:Put).with(flagname, fADS_UF_DONT_EXPIRE_PASSWD) + + user.password = 'pwd' + end + + it "should generate the correct URI" do + Puppet::Util::Windows::SID.stubs(:octet_string_to_sid_object).returns(sid) + user.uri.should == "WinNT://testcomputername/#{username},user" + end + + describe "when given a set of groups to which to add the user" do + let(:groups_to_set) { 'group1,group2' } + + before(:each) do + Puppet::Util::Windows::SID.stubs(:octet_string_to_sid_object).returns(sid) + user.expects(:groups).returns ['group2', 'group3'] + end + + describe "if membership is specified as inclusive" do + it "should add the user to those groups, and remove it from groups not in the list" do + group1 = stub 'group1' + group1.expects(:Add).with("WinNT://testcomputername/#{username},user") + + group3 = stub 'group1' + group3.expects(:Remove).with("WinNT://testcomputername/#{username},user") + + Puppet::Util::Windows::ADSI.expects(:sid_uri).with(sid).returns("WinNT://testcomputername/#{username},user").twice + Puppet::Util::Windows::ADSI.expects(:connect).with('WinNT://./group1,group').returns group1 + Puppet::Util::Windows::ADSI.expects(:connect).with('WinNT://./group3,group').returns group3 + + user.set_groups(groups_to_set, false) + end + end + + describe "if membership is specified as minimum" do + it "should add the user to the specified groups without affecting its other memberships" do + group1 = stub 'group1' + group1.expects(:Add).with("WinNT://testcomputername/#{username},user") + + Puppet::Util::Windows::ADSI.expects(:sid_uri).with(sid).returns("WinNT://testcomputername/#{username},user") + Puppet::Util::Windows::ADSI.expects(:connect).with('WinNT://./group1,group').returns group1 + + user.set_groups(groups_to_set, true) + end + end + end + end + end + + describe Puppet::Util::Windows::ADSI::Group do + let(:groupname) { 'testgroup' } + + describe "an instance" do + let(:adsi_group) { stub 'group' } + let(:group) { Puppet::Util::Windows::ADSI::Group.new(groupname, adsi_group) } + let(:someone_sid){ stub(:account => 'someone', :domain => 'testcomputername')} + + it "should be able to add a member (deprecated)" do + Puppet.expects(:deprecation_warning).with('Puppet::Util::Windows::ADSI::Group#add_members is deprecated; please use Puppet::Util::Windows::ADSI::Group#add_member_sids') + + Puppet::Util::Windows::SID.expects(:name_to_sid_object).with('someone').returns(someone_sid) + Puppet::Util::Windows::ADSI.expects(:sid_uri).with(someone_sid).returns("WinNT://testcomputername/someone,user") + + adsi_group.expects(:Add).with("WinNT://testcomputername/someone,user") + + group.add_member('someone') + end + + it "should raise when adding a member that can't resolve to a SID (deprecated)" do + expect { + group.add_member('foobar') + }.to raise_error(Puppet::Error, /Could not resolve username: foobar/) + end + + it "should be able to remove a member (deprecated)" do + Puppet.expects(:deprecation_warning).with('Puppet::Util::Windows::ADSI::Group#remove_members is deprecated; please use Puppet::Util::Windows::ADSI::Group#remove_member_sids') + + Puppet::Util::Windows::SID.expects(:name_to_sid_object).with('someone').returns(someone_sid) + Puppet::Util::Windows::ADSI.expects(:sid_uri).with(someone_sid).returns("WinNT://testcomputername/someone,user") + + adsi_group.expects(:Remove).with("WinNT://testcomputername/someone,user") + + group.remove_member('someone') + end + + it "should raise when removing a member that can't resolve to a SID (deprecated)" do + expect { + group.remove_member('foobar') + }.to raise_error(Puppet::Error, /Could not resolve username: foobar/) + end + + describe "should be able to use SID objects" do + let(:system) { Puppet::Util::Windows::SID.name_to_sid_object('SYSTEM') } + + it "to add a member" do + adsi_group.expects(:Add).with("WinNT://S-1-5-18") + + group.add_member_sids(system) + end + + it "to remove a member" do + adsi_group.expects(:Remove).with("WinNT://S-1-5-18") + + group.remove_member_sids(system) + end + end + + it "should provide its groups as a list of names" do + names = ['user1', 'user2'] + + users = names.map { |name| mock('user', :Name => name) } + + adsi_group.expects(:Members).returns(users) + + group.members.should =~ names + end + + it "should be able to add a list of users to a group" do + names = ['DOMAIN\user1', 'user2'] + sids = [ + stub(:account => 'user1', :domain => 'DOMAIN'), + stub(:account => 'user2', :domain => 'testcomputername'), + stub(:account => 'user3', :domain => 'DOMAIN2'), + ] + + # use stubbed objectSid on member to return stubbed SID + Puppet::Util::Windows::SID.expects(:octet_string_to_sid_object).with([0]).returns(sids[0]) + Puppet::Util::Windows::SID.expects(:octet_string_to_sid_object).with([1]).returns(sids[1]) + + Puppet::Util::Windows::SID.expects(:name_to_sid_object).with('user2').returns(sids[1]) + Puppet::Util::Windows::SID.expects(:name_to_sid_object).with('DOMAIN2\user3').returns(sids[2]) + + Puppet::Util::Windows::ADSI.expects(:sid_uri).with(sids[0]).returns("WinNT://DOMAIN/user1,user") + Puppet::Util::Windows::ADSI.expects(:sid_uri).with(sids[2]).returns("WinNT://DOMAIN2/user3,user") + + members = names.each_with_index.map{|n,i| stub(:Name => n, :objectSID => [i])} + adsi_group.expects(:Members).returns members + + adsi_group.expects(:Remove).with('WinNT://DOMAIN/user1,user') + adsi_group.expects(:Add).with('WinNT://DOMAIN2/user3,user') + + group.set_members(['user2', 'DOMAIN2\user3']) + end + + it "should raise an error when a username does not resolve to a SID" do + expect { + adsi_group.expects(:Members).returns [] + group.set_members(['foobar']) + }.to raise_error(Puppet::Error, /Could not resolve username: foobar/) + end + + it "should generate the correct URI" do + Puppet::Util::Windows::ADSI.stubs(:sid_uri_safe).returns(nil) + group.uri.should == "WinNT://./#{groupname},group" + end + end + + it "should generate the correct URI" do + Puppet::Util::Windows::ADSI.stubs(:sid_uri_safe).returns(nil) + Puppet::Util::Windows::ADSI::Group.uri("people").should == "WinNT://./people,group" + end + + it "should be able to create a group" do + adsi_group = stub("adsi") + + connection.expects(:Create).with('group', groupname).returns(adsi_group) + Puppet::Util::Windows::ADSI::User.expects(:exists?).with(groupname).returns(false) + + group = Puppet::Util::Windows::ADSI::Group.create(groupname) + + group.should be_a(Puppet::Util::Windows::ADSI::Group) + group.native_group.should == adsi_group + end + + it "should be able to confirm the existence of a group" do + Puppet::Util::Windows::ADSI.stubs(:sid_uri_safe).returns(nil) + Puppet::Util::Windows::ADSI.expects(:connect).with("WinNT://./#{groupname},group").returns connection + + Puppet::Util::Windows::ADSI::Group.exists?(groupname).should be_true + end + + it "should be able to confirm the existence of a group with a well-known SID" do + + service_group = Win32::Security::SID::Service + # ensure that the underlying OS is queried here + Puppet::Util::Windows::ADSI.unstub(:connect) + Puppet::Util::Windows::ADSI::Group.exists?(service_group).should be_true + end + + it "should return nil with an unknown SID" do + + bogus_sid = 'S-1-2-3-4' + # ensure that the underlying OS is queried here + Puppet::Util::Windows::ADSI.unstub(:connect) + Puppet::Util::Windows::ADSI::Group.exists?(bogus_sid).should be_false + end + + it "should be able to delete a group" do + connection.expects(:Delete).with('group', groupname) + + Puppet::Util::Windows::ADSI::Group.delete(groupname) + end + + it "should return an enumeration of IADsGroup wrapped objects" do + Puppet::Util::Windows::ADSI.stubs(:sid_uri_safe).returns(nil) + + name = 'Administrators' + wmi_groups = [stub('WMI', :name => name)] + Puppet::Util::Windows::ADSI.expects(:execquery).with('select name from win32_group where localaccount = "TRUE"').returns(wmi_groups) + + native_group = stub('IADsGroup') + native_group.expects(:Members).returns([stub(:Name => 'Administrator')]) + Puppet::Util::Windows::ADSI.expects(:connect).with("WinNT://./#{name},group").returns(native_group) + + groups = Puppet::Util::Windows::ADSI::Group.to_a + groups.length.should == 1 + groups[0].name.should == name + groups[0].members.should == ['Administrator'] + end + end + + describe Puppet::Util::Windows::ADSI::UserProfile do + it "should be able to delete a user profile" do + connection.expects(:Delete).with("Win32_UserProfile.SID='S-A-B-C'") + Puppet::Util::Windows::ADSI::UserProfile.delete('S-A-B-C') + end + + it "should warn on 2003" do + connection.expects(:Delete).raises(RuntimeError, + "Delete (WIN32OLERuntimeError) + OLE error code:80041010 in SWbemServicesEx + Invalid class + HRESULT error code:0x80020009 + Exception occurred.") + + Puppet.expects(:warning).with("Cannot delete user profile for 'S-A-B-C' prior to Vista SP1") + Puppet::Util::Windows::ADSI::UserProfile.delete('S-A-B-C') + end + end +end diff --git a/spec/unit/util/windows/api_types_spec.rb b/spec/unit/util/windows/api_types_spec.rb new file mode 100644 index 000000000..a1e1c76c9 --- /dev/null +++ b/spec/unit/util/windows/api_types_spec.rb @@ -0,0 +1,28 @@ +# encoding: UTF-8 +#!/usr/bin/env ruby + +require 'spec_helper' + +describe "FFI::MemoryPointer", :if => Puppet.features.microsoft_windows? do + context "read_wide_string" do + let (:string) { "foo_bar" } + + it "should properly roundtrip a given string" do + read_string = nil + FFI::MemoryPointer.from_string_to_wide_string(string) do |ptr| + read_string = ptr.read_wide_string(string.length) + end + + read_string.should == string + end + + it "should return a given string in the default encoding" do + read_string = nil + FFI::MemoryPointer.from_string_to_wide_string(string) do |ptr| + read_string = ptr.read_wide_string(string.length) + end + + read_string.encoding.should == Encoding.default_external + end + end +end diff --git a/spec/unit/util/windows/registry_spec.rb b/spec/unit/util/windows/registry_spec.rb index 636ba0c93..ed52539a5 100755 --- a/spec/unit/util/windows/registry_spec.rb +++ b/spec/unit/util/windows/registry_spec.rb @@ -1,7 +1,6 @@ #! /usr/bin/env ruby require 'spec_helper' require 'puppet/util/windows' -require 'puppet/util/windows/registry' describe Puppet::Util::Windows::Registry, :if => Puppet::Util::Platform.windows? do subject do @@ -43,12 +42,14 @@ describe Puppet::Util::Windows::Registry, :if => Puppet::Util::Platform.windows? yielded.should == subkey end - [described_class::KEY64, described_class::KEY32].each do |access| - it "should open the key for read access 0x#{access.to_s(16)}" do - mode = described_class::KEY_READ | access - hkey.expects(:open).with(path, mode) + if Puppet::Util::Platform.windows? + [described_class::KEY64, described_class::KEY32].each do |access| + it "should open the key for read access 0x#{access.to_s(16)}" do + mode = described_class::KEY_READ | access + hkey.expects(:open).with(path, mode) - subject.open(name, path, mode) {|reg| } + subject.open(name, path, mode) {|reg| } + end end end diff --git a/spec/unit/util/windows/sid_spec.rb b/spec/unit/util/windows/sid_spec.rb index 770512188..2748f13c6 100755 --- a/spec/unit/util/windows/sid_spec.rb +++ b/spec/unit/util/windows/sid_spec.rb @@ -4,12 +4,9 @@ require 'spec_helper' describe "Puppet::Util::Windows::SID", :if => Puppet.features.microsoft_windows? do if Puppet.features.microsoft_windows? require 'puppet/util/windows' - class SIDTester - include Puppet::Util::Windows::SID - end end - let(:subject) { SIDTester.new } + let(:subject) { Puppet::Util::Windows::SID } let(:sid) { Win32::Security::SID::LocalSystem } let(:invalid_sid) { 'bogus' } let(:unknown_sid) { 'S-0-0-0' } @@ -50,7 +47,7 @@ describe "Puppet::Util::Windows::SID", :if => Puppet.features.microsoft_windows? expect { invalid_octet = [1] subject.octet_string_to_sid_object(invalid_octet) - }.to raise_error(Win32::Security::SID::Error, /No mapping between account names and security IDs was done./) + }.to raise_error(SystemCallError, /No mapping between account names and security IDs was done./) end end @@ -159,7 +156,7 @@ describe "Puppet::Util::Windows::SID", :if => Puppet.features.microsoft_windows? it "should raise if the conversion fails" do subject.expects(:string_to_sid_ptr).with(sid). - raises(Puppet::Util::Windows::Error.new("Failed to convert string SID: #{sid}", Windows::Error::ERROR_ACCESS_DENIED)) + raises(Puppet::Util::Windows::Error.new("Failed to convert string SID: #{sid}", Puppet::Util::Windows::Error::ERROR_ACCESS_DENIED)) expect { subject.string_to_sid_ptr(sid) {|ptr| } diff --git a/spec/unit/util/windows/string_spec.rb b/spec/unit/util/windows/string_spec.rb index 60f7e6449..5c6473e70 100644 --- a/spec/unit/util/windows/string_spec.rb +++ b/spec/unit/util/windows/string_spec.rb @@ -50,5 +50,9 @@ describe "Puppet::Util::Windows::String", :if => Puppet.features.microsoft_windo it "should convert an UTF-32BE string" do converts_to_wide_string("bob\u00E8".encode(Encoding::UTF_32BE)) end + + it "should return a nil when given a nil" do + wide_string(nil).should == nil + end end end |