2
2
require 'spec_helper'
4
user = Puppet::Type.type(:user)
8
ENV["PATH"] += File::PATH_SEPARATOR + "/usr/sbin" unless ENV["PATH"].split(File::PATH_SEPARATOR).include?("/usr/sbin")
9
@provider = stub 'provider'
10
@resource = stub 'resource', :resource => nil, :provider => @provider, :line => nil, :file => nil
13
it "should have a default provider inheriting from Puppet::Provider" do
14
user.defaultprovider.ancestors.should be_include(Puppet::Provider)
4
describe Puppet::Type.type(:user) do
6
@provider_class = described_class.provide(:simple) do
7
has_features :manages_expiry, :manages_password_age, :manages_passwords, :manages_solaris_rbac
11
def exists?; get(:ensure) != :absent; end
13
def self.instances; []; end
15
described_class.stubs(:defaultprovider).returns @provider_class
17
18
it "should be able to create a instance" do
18
user.new(:name => "foo").should_not be_nil
19
described_class.new(:name => "foo").should_not be_nil
21
22
it "should have an allows_duplicates feature" do
22
user.provider_feature(:allows_duplicates).should_not be_nil
23
described_class.provider_feature(:allows_duplicates).should_not be_nil
25
26
it "should have an manages_homedir feature" do
26
user.provider_feature(:manages_homedir).should_not be_nil
27
described_class.provider_feature(:manages_homedir).should_not be_nil
29
30
it "should have an manages_passwords feature" do
30
user.provider_feature(:manages_passwords).should_not be_nil
31
described_class.provider_feature(:manages_passwords).should_not be_nil
33
34
it "should have a manages_solaris_rbac feature" do
34
user.provider_feature(:manages_solaris_rbac).should_not be_nil
35
described_class.provider_feature(:manages_solaris_rbac).should_not be_nil
37
38
it "should have a manages_expiry feature" do
38
user.provider_feature(:manages_expiry).should_not be_nil
39
described_class.provider_feature(:manages_expiry).should_not be_nil
41
42
it "should have a manages_password_age feature" do
42
user.provider_feature(:manages_password_age).should_not be_nil
43
described_class.provider_feature(:manages_password_age).should_not be_nil
45
46
it "should have a system_users feature" do
46
user.provider_feature(:system_users).should_not be_nil
47
described_class.provider_feature(:system_users).should_not be_nil
49
50
describe "instances" do
50
it "should have a valid provider" do
51
user.new(:name => "foo").provider.class.ancestors.should be_include(Puppet::Provider)
54
51
it "should delegate existence questions to its provider" do
55
instance = user.new(:name => "foo")
56
instance.provider.expects(:exists?).returns "eh"
57
instance.exists?.should == "eh"
52
@provider = @provider_class.new(:name => 'foo', :ensure => :absent)
53
instance = described_class.new(:name => "foo", :provider => @provider)
54
instance.exists?.should == false
56
@provider.set(:ensure => :present)
57
instance.exists?.should == true
109
107
it "should include the result of retrieving each property's current value if the user is present" do
110
@user.property(:ensure).expects(:retrieve).returns :present
111
@user.property(:uid).expects(:retrieve).returns 15
112
108
@user.retrieve[@user.property(:uid)].should == 15
116
112
describe "when managing the ensure property" do
118
@ensure = user.attrclass(:ensure).new(:resource => @resource)
121
113
it "should support a :present value" do
122
lambda { @ensure.should = :present }.should_not raise_error
114
lambda { described_class.new(:name => 'foo', :ensure => :present) }.should_not raise_error
125
117
it "should support an :absent value" do
126
lambda { @ensure.should = :absent }.should_not raise_error
118
lambda { described_class.new(:name => 'foo', :ensure => :absent) }.should_not raise_error
129
121
it "should call :create on the provider when asked to sync to the :present state" do
122
@provider = @provider_class.new(:name => 'foo', :ensure => :absent)
130
123
@provider.expects(:create)
131
@ensure.should = :present
124
described_class.new(:name => 'foo', :ensure => :present, :provider => @provider).parameter(:ensure).sync
135
127
it "should call :delete on the provider when asked to sync to the :absent state" do
128
@provider = @provider_class.new(:name => 'foo', :ensure => :present)
136
129
@provider.expects(:delete)
137
@ensure.should = :absent
130
described_class.new(:name => 'foo', :ensure => :absent, :provider => @provider).parameter(:ensure).sync
141
133
describe "and determining the current state" do
142
134
it "should return :present when the provider indicates the user exists" do
143
@provider.expects(:exists?).returns true
144
@ensure.retrieve.should == :present
135
@provider = @provider_class.new(:name => 'foo', :ensure => :present)
136
described_class.new(:name => 'foo', :ensure => :absent, :provider => @provider).parameter(:ensure).retrieve.should == :present
147
139
it "should return :absent when the provider indicates the user does not exist" do
148
@provider.expects(:exists?).returns false
149
@ensure.retrieve.should == :absent
140
@provider = @provider_class.new(:name => 'foo', :ensure => :absent)
141
described_class.new(:name => 'foo', :ensure => :present, :provider => @provider).parameter(:ensure).retrieve.should == :absent
154
146
describe "when managing the uid property" do
155
147
it "should convert number-looking strings into actual numbers" do
156
uid = user.attrclass(:uid).new(:resource => @resource)
158
uid.should.must == 50
148
described_class.new(:name => 'foo', :uid => '50')[:uid].should == 50
161
151
it "should support UIDs as numbers" do
162
uid = user.attrclass(:uid).new(:resource => @resource)
164
uid.should.must == 50
152
described_class.new(:name => 'foo', :uid => 50)[:uid].should == 50
167
it "should :absent as a value" do
168
uid = user.attrclass(:uid).new(:resource => @resource)
170
uid.should.must == :absent
155
it "should support :absent as a value" do
156
described_class.new(:name => 'foo', :uid => :absent)[:uid].should == :absent
174
160
describe "when managing the gid" do
175
it "should :absent as a value" do
176
gid = user.attrclass(:gid).new(:resource => @resource)
178
gid.should.must == :absent
161
it "should support :absent as a value" do
162
described_class.new(:name => 'foo', :gid => :absent)[:gid].should == :absent
181
165
it "should convert number-looking strings into actual numbers" do
182
gid = user.attrclass(:gid).new(:resource => @resource)
184
gid.should.must == 50
166
described_class.new(:name => 'foo', :gid => '50')[:gid].should == 50
187
169
it "should support GIDs specified as integers" do
188
gid = user.attrclass(:gid).new(:resource => @resource)
190
gid.should.must == 50
170
described_class.new(:name => 'foo', :gid => 50)[:gid].should == 50
193
173
it "should support groups specified by name" do
194
gid = user.attrclass(:gid).new(:resource => @resource)
196
gid.should.must == "foo"
174
described_class.new(:name => 'foo', :gid => 'foo')[:gid].should == 'foo'
199
177
describe "when testing whether in sync" do
201
@gid = user.attrclass(:gid).new(:resource => @resource, :should => %w{foo bar})
204
178
it "should return true if no 'should' values are set" do
205
@gid = user.attrclass(:gid).new(:resource => @resource)
207
@gid.must be_safe_insync(500)
179
# this is currently not the case because gid has no default value, so we would never even
180
# call insync? on that property
181
if param = described_class.new(:name => 'foo').parameter(:gid)
182
param.must be_safe_insync(500)
210
186
it "should return true if any of the specified groups are equal to the current integer" do
211
187
Puppet::Util.expects(:gid).with("foo").returns 300
212
188
Puppet::Util.expects(:gid).with("bar").returns 500
214
@gid.must be_safe_insync(500)
189
described_class.new(:name => 'baz', :gid => [ 'foo', 'bar' ]).parameter(:gid).must be_safe_insync(500)
217
192
it "should return false if none of the specified groups are equal to the current integer" do
218
193
Puppet::Util.expects(:gid).with("foo").returns 300
219
194
Puppet::Util.expects(:gid).with("bar").returns 500
221
@gid.should_not be_safe_insync(700)
195
described_class.new(:name => 'baz', :gid => [ 'foo', 'bar' ]).parameter(:gid).must_not be_safe_insync(700)
225
199
describe "when syncing" do
227
@gid = user.attrclass(:gid).new(:resource => @resource, :should => %w{foo bar})
230
200
it "should use the first found, specified group as the desired value and send it to the provider" do
231
201
Puppet::Util.expects(:gid).with("foo").returns nil
232
202
Puppet::Util.expects(:gid).with("bar").returns 500
204
@provider = @provider_class.new(:name => 'foo')
205
resource = described_class.new(:name => 'foo', :provider => @provider, :gid => [ 'foo', 'bar' ])
234
207
@provider.expects(:gid=).with 500
208
resource.parameter(:gid).sync
213
describe "when managing groups" do
214
it "should support a singe group" do
215
lambda { described_class.new(:name => 'foo', :groups => 'bar') }.should_not raise_error
218
it "should support multiple groups as an array" do
219
lambda { described_class.new(:name => 'foo', :groups => [ 'bar' ]) }.should_not raise_error
220
lambda { described_class.new(:name => 'foo', :groups => [ 'bar', 'baz' ]) }.should_not raise_error
223
it "should not support a comma separated list" do
224
lambda { described_class.new(:name => 'foo', :groups => 'bar,baz') }.should raise_error(Puppet::Error, /Group names must be provided as an array/)
227
it "should not support an empty string" do
228
lambda { described_class.new(:name => 'foo', :groups => '') }.should raise_error(Puppet::Error, /Group names must not be empty/)
231
describe "when testing is in sync" do
234
# the useradd provider uses a single string to represent groups and so does Puppet::Property::List when converting to should values
235
@provider = @provider_class.new(:name => 'foo', :groups => 'a,b,e,f')
238
it "should not care about order" do
239
@property = described_class.new(:name => 'foo', :groups => [ 'a', 'c', 'b' ]).property(:groups)
240
@property.must be_safe_insync([ 'a', 'b', 'c' ])
241
@property.must be_safe_insync([ 'a', 'c', 'b' ])
242
@property.must be_safe_insync([ 'b', 'a', 'c' ])
243
@property.must be_safe_insync([ 'b', 'c', 'a' ])
244
@property.must be_safe_insync([ 'c', 'a', 'b' ])
245
@property.must be_safe_insync([ 'c', 'b', 'a' ])
248
it "should merge current value and desired value if membership minimal" do
249
@instance = described_class.new(:name => 'foo', :groups => [ 'a', 'c', 'b' ], :provider => @provider)
250
@instance[:membership] = :minimum
251
@instance[:groups].should == 'a,b,c,e,f'
254
it "should not treat a subset of groups insync if membership inclusive" do
255
@instance = described_class.new(:name => 'foo', :groups => [ 'a', 'c', 'b' ], :provider => @provider)
256
@instance[:membership] = :inclusive
257
@instance[:groups].should == 'a,b,c'
241
263
describe "when managing expiry" do
243
@expiry = user.attrclass(:expiry).new(:resource => @resource)
246
264
it "should fail if given an invalid date" do
247
lambda { @expiry.should = "200-20-20" }.should raise_error(Puppet::Error)
265
lambda { described_class.new(:name => 'foo', :expiry => "200-20-20") }.should raise_error(Puppet::Error, /Expiry dates must be YYYY-MM-DD/)
251
269
describe "when managing minimum password age" do
253
@age = user.attrclass(:password_min_age).new(:resource => @resource)
256
270
it "should accept a negative minimum age" do
257
expect { @age.should = -1 }.should_not raise_error
271
expect { described_class.new(:name => 'foo', :password_min_age => '-1') }.should_not raise_error
260
274
it "should fail with an empty minimum age" do
261
expect { @age.should = '' }.should raise_error(Puppet::Error)
275
expect { described_class.new(:name => 'foo', :password_min_age => '') }.should raise_error(Puppet::Error, /minimum age must be provided as a number/)
265
279
describe "when managing maximum password age" do
267
@age = user.attrclass(:password_max_age).new(:resource => @resource)
270
280
it "should accept a negative maximum age" do
271
expect { @age.should = -1 }.should_not raise_error
281
expect { described_class.new(:name => 'foo', :password_max_age => '-1') }.should_not raise_error
274
284
it "should fail with an empty maximum age" do
275
expect { @age.should = '' }.should raise_error(Puppet::Error)
285
expect { described_class.new(:name => 'foo', :password_max_age => '') }.should raise_error(Puppet::Error, /maximum age must be provided as a number/)
279
289
describe "when managing passwords" do
281
@password = user.attrclass(:password).new(:resource => @resource, :should => "mypass")
291
@password = described_class.new(:name => 'foo', :password => 'mypass').parameter(:password)
284
294
it "should not include the password in the change log when adding the password" do