File Coverage

blib/lib/Test/Unix/Group.pm
Criterion Covered Total %
statement 20 78 25.6
branch 0 26 0.0
condition 0 9 0.0
subroutine 6 7 85.7
pod 1 1 100.0
total 27 121 22.3


line stmt bran cond sub pod time code
1             package Test::Unix::Group;
2              
3             # Copyright (c) 2005 Nik Clayton
4             # All rights reserved.
5             #
6             # Redistribution and use in source and binary forms, with or without
7             # modification, are permitted provided that the following conditions
8             # are met:
9             # 1. Redistributions of source code must retain the above copyright
10             # notice, this list of conditions and the following disclaimer.
11             # 2. Redistributions in binary form must reproduce the above copyright
12             # notice, this list of conditions and the following disclaimer in the
13             # documentation and/or other materials provided with the distribution.
14             #
15             # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16             # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17             # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18             # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19             # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20             # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21             # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22             # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23             # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24             # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25             # SUCH DAMAGE.
26              
27 1     1   22039 use warnings;
  1         2  
  1         28  
28 1     1   5 use strict;
  1         2  
  1         28  
29              
30 1     1   3 use Test::Builder;
  1         5  
  1         61  
31              
32             require Exporter;
33             our @ISA = qw(Exporter);
34             our @EXPORT = qw(group_ok);
35              
36             my $Test = Test::Builder->new;
37              
38 1     1   833 use User::pwent;
  1         10332  
  1         6  
39 1     1   785 use User::grent;
  1         1292  
  1         4  
40              
41             my @GROUP_FIELDS = qw(name gid passwd members);
42             my %GROUP_FIELDS = map { $_ => 1 } @GROUP_FIELDS;
43              
44             sub import {
45 1     1   11 my($self) = shift;
46 1         4 my $pack = caller;
47              
48 1         5 $Test->exported_to($pack);
49 1         12 $Test->plan(@_);
50              
51 1         137 $self->export_to_level(1, $self, qw(group_ok));
52             }
53              
54             =head1 NAME
55              
56             Test::Unix::Group - Test::Builder based tests for Unix groups
57              
58             =head1 VERSION
59              
60             Version 0.01
61              
62             =cut
63              
64             our $VERSION = '0.01';
65              
66             =head1 SYNOPSIS
67              
68             use Test::Unix::Group tests => 4;
69              
70             group_ok({ name => 'wheel' }, "'wheel' must exist");
71             group_ok({ name => 'wheel' }); # Auto-generate test name
72             group_ok({ name => 'wheel',
73             gid => 0, }, "'wheel' must have gid 0");
74              
75             group_ok({ name => 'wheel', members => [qw(root nik)], }
76             "'wheel' has the correct members");
77              
78             Test::Unix::Group B exports C to make it
79             easier to test whether or not Unix groups have been correctly
80             configured.
81              
82             Test::Unix::Group uses Test::Builder, so plays nicely with
83             Test::Simple, Test::More, and other Test::Builder based modules.
84              
85             =head1 FUNCTIONS
86              
87             =head2 group_ok($spec, [ $test_name ]);
88              
89             group_ok() tests that a group exists and matches the given specification.
90              
91             The specification is a hashref that consists of one or more keys.
92             Keys are taken from the L module, and are C,
93             C, C, and C. See L for more
94             details.
95              
96             Each value associated with a key, except C, is the value that
97             that entry is supposed to have.
98              
99             C behaves a little differently. The C key should
100             have an array ref as a value. This array should contain the user
101             names of all the users who must be members of the group. Note that
102             this is not an exclusive list, and allows for users other than those
103             in the list to be members of the group. This is because it is not
104             practical to test all the accounts on the system to verify that they
105             are not members of the given group via their user account GID.
106              
107             User accounts provided to the C key are looked for in the
108             list of members explicitly listed in the group. If they are not found
109             there then their account information is obtained and their account GID
110             is examined to see if they are members through that mechanism.
111              
112             Only the C key is mandatory, the others are optional. If they
113             are not present in the specification then they are not checked.
114              
115             The C<$test_name> is optional. If it is not present then a sensible
116             one is generated following the form
117              
118             Checking group '$group' ($key, $key, $key, ...)
119              
120             =cut
121              
122             sub group_ok {
123 0     0 1   my($spec, $test_name) = @_;
124              
125 0 0         if(! defined $spec) {
126 0           my $ok = $Test->ok(0, "group_ok()");
127 0           $Test->diag(" group_ok() called with no arguments");
128 0           return $ok;
129             }
130              
131 0 0         if(ref($spec) ne 'HASH') {
132 0           my $ok = $Test->ok(0, 'group_ok()');
133 0           $Test->diag(" First argument to group_ok() must be a hash ref");
134 0           return $ok;
135             }
136              
137 0 0 0       if(! exists $spec->{name} or
      0        
138             ! defined $spec->{name} or
139             $spec->{name} =~ /^\s*$/) {
140 0           my $t = $test_name;
141 0 0         $t = "group_ok(...)" unless defined $t;
142 0           my $ok = $Test->ok(0, $t);
143 0           $Test->diag(" group_ok() called with no group name");
144 0           return $ok;
145             }
146              
147 0 0         if(! defined $test_name) {
148 0           $test_name = "Checking group '$spec->{name}'";
149 0           $test_name .= ' (' . join(', ', sort keys %$spec) . ')';
150             }
151              
152 0           my($g, @diag);
153              
154 0           $g = getgrnam($spec->{name});
155              
156 0 0         if(! defined $g) {
157 0           my $ok = $Test->ok(0, $test_name);
158 0           $Test->diag(" Group '$spec->{name}' does not exist");
159 0           return $ok;
160             }
161              
162 0           foreach my $field (keys %$spec) {
163 0 0         if(! exists $GROUP_FIELDS{$field}) {
164 0           push @diag, " Invalid field '$field' given";
165 0           next;
166             }
167              
168 0 0 0       if(! defined $spec->{$field} or $spec->{$field} =~ /^\s*$/) {
169 0           push @diag, " Empty field '$field' given";
170 0           next;
171             }
172              
173             # All members in $spec->{members} must exist in the group, either
174             # in the members returned by getgrnam(), or, if any are left over,
175             # by checking each account's group membership.
176 0 0         if($field eq 'members') {
177 0           my %exp_members = map { $_ => 1 } @{$spec->{members}};
  0            
  0            
178              
179 0           delete $exp_members{$_} foreach @{$g->members};
  0            
180              
181             # Any members left? If so, check their group ownership
182 0           foreach my $name (sort keys %exp_members) {
183 0           my $u = getpwnam($name);
184 0 0         if(! defined $u) {
185 0           push @diag, " You looked for user '$name' in group '$spec->{name}'\n";
186 0           push @diag, " That account does not exist on this system";
187 0           next;
188             }
189              
190 0 0         if($g->gid != $u->gid) {
191 0           push @diag, " Field: members\n";
192 0           push @diag, " expected: user '$name' with gid " . $g->gid . "\n";
193 0           push @diag, " got: user '$name' with gid " . $u->gid . "\n";
194             }
195             }
196              
197 0           next;
198             }
199              
200 0 0         if($spec->{$field} ne $g->$field) {
201 0           push @diag, " Field: $field\n";
202 0           push @diag, " expected: $spec->{$field}\n";
203 0           push @diag, " got: " . $g->$field . "\n";
204 0           next;
205             }
206             }
207              
208 0 0         if(@diag) {
209 0           my $ok = $Test->ok(0, $test_name);
210 0           $Test->diag(@diag);
211 0           return $ok;
212             }
213              
214 0           return $Test->ok(1, $test_name);
215             }
216              
217             =head1 EXAMPLES
218              
219             Verify that a group exists.
220              
221             group_ok({ name => 'wheel' }, "Group 'wheel' exists");
222              
223             Verify that a group exists with a given GID. Omit the test name, rely
224             on the default.
225              
226             group_ok({ name => 'wheel', gid => 0 });
227              
228             Verify that the group exists and contains at least the members
229             C.
230              
231             group_ok({ name => 'wheel', members => [ qw(root nik) ] });
232              
233             =head1 SEE ALSO
234              
235             Test::Unix::User, Test::Simple, Test::Builder, User::grent.
236              
237             =head1 AUTHOR
238              
239             Nik Clayton, C>
240              
241             =head1 BUGS
242              
243             Please report any bugs or feature requests to
244             C, or through the web interface at
245             L.
246             I will be notified, and then you'll automatically be notified of progress on
247             your bug as I make changes.
248              
249             =head1 COPYRIGHT & LICENSE
250              
251             Copyright (c) 2005 Nik Clayton
252             All rights reserved.
253              
254             Redistribution and use in source and binary forms, with or without
255             modification, are permitted provided that the following conditions
256             are met:
257              
258             1. Redistributions of source code must retain the above copyright
259             notice, this list of conditions and the following disclaimer.
260             2. Redistributions in binary form must reproduce the above copyright
261             notice, this list of conditions and the following disclaimer in the
262             documentation and/or other materials provided with the distribution.
263              
264             THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
265             ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
266             IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
267             ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
268             FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
269             DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
270             OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271             HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
272             LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
273             OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
274             SUCH DAMAGE.
275              
276             =cut
277              
278             1; # End of Test::Unix::Group