]> git.k1024.org Git - pylibacl.git/blob - test/test_acls.py
Minor change in homepage url
[pylibacl.git] / test / test_acls.py
1 #
2 #
3
4 """Unittests for the posix1e module"""
5
6 #  Copyright (C) 2002-2008 Iustin Pop <iusty@k1024.org>
7 #
8 #  This library is free software; you can redistribute it and/or
9 #  modify it under the terms of the GNU Lesser General Public
10 #  License as published by the Free Software Foundation; either
11 #  version 2.1 of the License, or (at your option) any later version.
12 #
13 #  This library is distributed in the hope that it will be useful,
14 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 #  Lesser General Public License for more details.
17 #
18 #  You should have received a copy of the GNU Lesser General Public
19 #  License along with this library; if not, write to the Free Software
20 #  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 #  02110-1301  USA
22
23
24 import unittest
25 import os
26 import tempfile
27
28 import posix1e
29 from posix1e import *
30
31 TEST_DIR = os.environ.get("TESTDIR", ".")
32
33 BASIC_ACL_TEXT = "u::rw,g::r,o::-"
34
35 def _skip_test(fn):
36     """Wrapper to skip a test"""
37     new_fn = lambda x: None
38     new_fn.__doc__ = "SKIPPED %s" % fn.__doc__
39     return new_fn
40
41
42 def has_ext(extension):
43     """Decorator to skip tests based on platform support"""
44     if not extension:
45         return _skip_test
46     else:
47         return lambda x: x
48
49
50 class aclTest:
51     """Support functions ACLs"""
52
53     def setUp(self):
54         """set up function"""
55         self.rmfiles = []
56         self.rmdirs = []
57
58     def tearDown(self):
59         """tear down function"""
60         for fname in self.rmfiles:
61             os.unlink(fname)
62         for dname in self.rmdirs:
63             os.rmdir(dname)
64
65     def _getfile(self):
66         """create a temp file"""
67         fh, fname = tempfile.mkstemp(".test", "xattr-", TEST_DIR)
68         self.rmfiles.append(fname)
69         return fh, fname
70
71     def _getdir(self):
72         """create a temp dir"""
73         dname = tempfile.mkdtemp(".test", "xattr-", TEST_DIR)
74         self.rmdirs.append(dname)
75         return dname
76
77     def _getsymlink(self):
78         """create a symlink"""
79         fh, fname = self._getfile()
80         os.close(fh)
81         os.unlink(fname)
82         os.symlink(fname + ".non-existent", fname)
83         return fname
84
85
86 class LoadTests(aclTest, unittest.TestCase):
87     """Load/create tests"""
88     def testFromFile(self):
89         """Test loading ACLs from a file"""
90         _, fname = self._getfile()
91         acl1 = posix1e.ACL(file=fname)
92         self.failUnless(acl1.valid(), "ACL read from file should be valid")
93
94     def testFromDir(self):
95         """Test loading ACLs from a directory"""
96         dname = self._getdir()
97         acl1 = posix1e.ACL(file=dname)
98         acl2 = posix1e.ACL(filedef=dname)
99         self.failUnless(acl1.valid(),
100                         "ACL read from directory should be valid")
101         # default ACLs might or might not be valid; missing ones are
102         # not valid, so we don't test acl2 for validity
103
104     def testFromFd(self):
105         """Test loading ACLs from a file descriptor"""
106         fd, _ = self._getfile()
107         acl1 = posix1e.ACL(fd=fd)
108         self.failUnless(acl1.valid(), "ACL read from fd should be valid")
109
110     def testFromEmpty(self):
111         """Test creating an empty ACL"""
112         acl1 = posix1e.ACL()
113         self.failIf(acl1.valid(), "Empty ACL should not be valid")
114
115     def testFromText(self):
116         """Test creating an ACL from text"""
117         acl1 = posix1e.ACL(text=BASIC_ACL_TEXT)
118         self.failUnless(acl1.valid(),
119                         "ACL based on standard description should be valid")
120
121 class AclExtensions(aclTest, unittest.TestCase):
122     """ACL extensions checks"""
123
124     @has_ext(HAS_ACL_FROM_MODE)
125     def testFromMode(self):
126         """Test loading ACLs from an octal mode"""
127         acl1 = posix1e.ACL(mode=0644)
128         self.failUnless(acl1.valid(),
129                         "ACL created via octal mode shoule be valid")
130
131     @has_ext(HAS_ACL_CHECK)
132     def testAclCheck(self):
133         """Test the acl_check method"""
134         acl1 = posix1e.ACL(text=BASIC_ACL_TEXT)
135         self.failIf(acl1.check(), "ACL is not valid")
136         acl2 = posix1e.ACL()
137         self.failUnless(acl2.check(), "Empty ACL should not be valid")
138
139     @has_ext(HAS_EXTENDED_CHECK)
140     def testExtended(self):
141         """Test the acl_extended function"""
142         fd, fname = self._getfile()
143         basic_acl = posix1e.ACL(text=BASIC_ACL_TEXT)
144         basic_acl.applyto(fd)
145         for item in fd, fname:
146             self.failIf(has_extended(item),
147                         "A simple ACL should not be reported as extended")
148         enhanced_acl = posix1e.ACL(text="u::rw,g::-,o::-,u:root:rw,mask::r")
149         self.failUnless(enhanced_acl.valid(),
150                         "Failure to build an extended ACL")
151         enhanced_acl.applyto(fd)
152         for item in fd, fname:
153             self.failUnless(has_extended(item),
154                         "An extended ACL should be reported as such")
155
156     @has_ext(HAS_EQUIV_MODE)
157     def testEquivMode(self):
158         """Test the equiv_mode function"""
159         if HAS_ACL_FROM_MODE:
160             for mode in 0644, 0755:
161                 acl = posix1e.ACL(mode=mode)
162                 self.failUnlessEqual(acl.equiv_mode(), mode)
163         acl = posix1e.ACL(text="u::rw,g::r,o::r")
164         self.failUnlessEqual(acl.equiv_mode(), 0644)
165         acl = posix1e.ACL(text="u::rx,g::-,o::-")
166         self.failUnlessEqual(acl.equiv_mode(), 0500)
167
168
169 class WriteTests(aclTest, unittest.TestCase):
170     """Write tests"""
171
172     def testDeleteDefault(self):
173         """Test removing the default ACL"""
174         dname = self._getdir()
175         posix1e.delete_default(dname)
176
177     def testReapply(self):
178         """Test re-applying an ACL"""
179         fd, fname = self._getfile()
180         acl1 = posix1e.ACL(fd=fd)
181         acl1.applyto(fd)
182         acl1.applyto(fname)
183         dname = self._getdir()
184         acl2 = posix1e.ACL(file=fname)
185         acl2.applyto(dname)
186
187
188 class ModificationTests(aclTest, unittest.TestCase):
189     """ACL modification tests"""
190
191     @has_ext(HAS_ACL_ENTRY)
192     def testAppend(self):
193         """Test append a new Entry to the ACL"""
194         acl = posix1e.ACL()
195         e = acl.append()
196         e.tag_type = posix1e.ACL_OTHER
197         acl.calc_mask()
198
199     @has_ext(HAS_ACL_ENTRY)
200     def testDelete(self):
201         """Test delete Entry from the ACL"""
202         acl = posix1e.ACL()
203         e = acl.append()
204         e.tag_type = posix1e.ACL_OTHER
205         acl.calc_mask()
206         acl.delete_entry(e)
207         acl.calc_mask()
208
209     @has_ext(HAS_ACL_ENTRY)
210     def testDoubleEntries(self):
211         """Test double entries"""
212         acl = posix1e.ACL(text=BASIC_ACL_TEXT)
213         self.failUnless(acl.valid(), "ACL is not valid")
214         for tag_type in (posix1e.ACL_USER_OBJ, posix1e.ACL_GROUP_OBJ,
215                          posix1e.ACL_OTHER):
216             e = acl.append()
217             e.tag_type = tag_type
218             e.permset.clear()
219             self.failIf(acl.valid(),
220                         "ACL containing duplicate entries should not be valid")
221             acl.delete_entry(e)
222
223     @has_ext(HAS_ACL_ENTRY)
224     def testMultipleGoodEntries(self):
225         """Test multiple valid entries"""
226         acl = posix1e.ACL(text=BASIC_ACL_TEXT)
227         self.failUnless(acl.valid(), "ACL is not valid")
228         for tag_type in (posix1e.ACL_USER,
229                          posix1e.ACL_GROUP):
230             for obj_id in range(5):
231                 e = acl.append()
232                 e.tag_type = tag_type
233                 e.qualifier = obj_id
234                 e.permset.clear()
235                 acl.calc_mask()
236                 self.failUnless(acl.valid(),
237                                "ACL should be able to hold multiple"
238                                 " user/group entries")
239
240     @has_ext(HAS_ACL_ENTRY)
241     def testMultipleBadEntries(self):
242         """Test multiple invalid entries"""
243         acl = posix1e.ACL(text=BASIC_ACL_TEXT)
244         self.failUnless(acl.valid(), "ACL built from standard description"
245                         " should be valid")
246         for tag_type in (posix1e.ACL_USER,
247                          posix1e.ACL_GROUP):
248             e1 = acl.append()
249             e1.tag_type = tag_type
250             e1.qualifier = 0
251             e1.permset.clear()
252             acl.calc_mask()
253             self.failUnless(acl.valid(), "ACL should be able to add a"
254                             " user/group entry")
255             e2 = acl.append()
256             e2.tag_type = tag_type
257             e2.qualifier = 0
258             e2.permset.clear()
259             acl.calc_mask()
260             self.failIf(acl.valid(), "ACL should not validate when"
261                         " containing two duplicate entries")
262             acl.delete_entry(e1)
263             acl.delete_entry(e2)
264
265     @has_ext(HAS_ACL_ENTRY)
266     def testPermset(self):
267         """Test permissions"""
268         acl = posix1e.ACL()
269         e = acl.append()
270         ps = e.permset
271         ps.clear()
272         pmap = {
273             posix1e.ACL_READ: "read",
274             posix1e.ACL_WRITE: "write",
275             posix1e.ACL_EXECUTE: "execute",
276             }
277         for perm in pmap:
278             self.failIf(ps.test(perm), "Empty permission set should not"
279                         " have permission '%s'" % pmap[perm])
280             ps.add(perm)
281             self.failUnless(ps.test(perm), "Permission '%s' should exist"
282                         " after addition" % pmap[perm])
283             ps.delete(perm)
284             self.failIf(ps.test(perm), "Permission '%s' should not exist"
285                         " after deletion" % pmap[perm])
286
287
288 if __name__ == "__main__":
289     unittest.main()