]> git.k1024.org Git - pylibacl.git/blob - tests/test_acls.py
Unittest fixes for python 3
[pylibacl.git] / tests / 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 # This is to workaround python 2/3 differences at syntactic level
36 # (which can't be worked around via if's)
37 M0500 = 320 # octal 0500
38 M0644 = 420 # octal 0644
39 M0755 = 493 # octal 755
40
41 def _skip_test(fn):
42     """Wrapper to skip a test"""
43     new_fn = lambda x: None
44     new_fn.__doc__ = "SKIPPED %s" % fn.__doc__
45     return new_fn
46
47
48 def has_ext(extension):
49     """Decorator to skip tests based on platform support"""
50     if not extension:
51         return _skip_test
52     else:
53         return lambda x: x
54
55
56 class aclTest:
57     """Support functions ACLs"""
58
59     def setUp(self):
60         """set up function"""
61         self.rmfiles = []
62         self.rmdirs = []
63
64     def tearDown(self):
65         """tear down function"""
66         for fname in self.rmfiles:
67             os.unlink(fname)
68         for dname in self.rmdirs:
69             os.rmdir(dname)
70
71     def _getfile(self):
72         """create a temp file"""
73         fh, fname = tempfile.mkstemp(".test", "xattr-", TEST_DIR)
74         self.rmfiles.append(fname)
75         return fh, fname
76
77     def _getdir(self):
78         """create a temp dir"""
79         dname = tempfile.mkdtemp(".test", "xattr-", TEST_DIR)
80         self.rmdirs.append(dname)
81         return dname
82
83     def _getsymlink(self):
84         """create a symlink"""
85         fh, fname = self._getfile()
86         os.close(fh)
87         os.unlink(fname)
88         os.symlink(fname + ".non-existent", fname)
89         return fname
90
91
92 class LoadTests(aclTest, unittest.TestCase):
93     """Load/create tests"""
94     def testFromFile(self):
95         """Test loading ACLs from a file"""
96         _, fname = self._getfile()
97         acl1 = posix1e.ACL(file=fname)
98         self.failUnless(acl1.valid(), "ACL read from file should be valid")
99
100     def testFromDir(self):
101         """Test loading ACLs from a directory"""
102         dname = self._getdir()
103         acl1 = posix1e.ACL(file=dname)
104         acl2 = posix1e.ACL(filedef=dname)
105         self.failUnless(acl1.valid(),
106                         "ACL read from directory should be valid")
107         # default ACLs might or might not be valid; missing ones are
108         # not valid, so we don't test acl2 for validity
109
110     def testFromFd(self):
111         """Test loading ACLs from a file descriptor"""
112         fd, _ = self._getfile()
113         acl1 = posix1e.ACL(fd=fd)
114         self.failUnless(acl1.valid(), "ACL read from fd should be valid")
115
116     def testFromEmpty(self):
117         """Test creating an empty ACL"""
118         acl1 = posix1e.ACL()
119         self.failIf(acl1.valid(), "Empty ACL should not be valid")
120
121     def testFromText(self):
122         """Test creating an ACL from text"""
123         acl1 = posix1e.ACL(text=BASIC_ACL_TEXT)
124         self.failUnless(acl1.valid(),
125                         "ACL based on standard description should be valid")
126
127 class AclExtensions(aclTest, unittest.TestCase):
128     """ACL extensions checks"""
129
130     @has_ext(HAS_ACL_FROM_MODE)
131     def testFromMode(self):
132         """Test loading ACLs from an octal mode"""
133         acl1 = posix1e.ACL(mode=M0644)
134         self.failUnless(acl1.valid(),
135                         "ACL created via octal mode shoule be valid")
136
137     @has_ext(HAS_ACL_CHECK)
138     def testAclCheck(self):
139         """Test the acl_check method"""
140         acl1 = posix1e.ACL(text=BASIC_ACL_TEXT)
141         self.failIf(acl1.check(), "ACL is not valid")
142         acl2 = posix1e.ACL()
143         self.failUnless(acl2.check(), "Empty ACL should not be valid")
144
145     @has_ext(HAS_EXTENDED_CHECK)
146     def testExtended(self):
147         """Test the acl_extended function"""
148         fd, fname = self._getfile()
149         basic_acl = posix1e.ACL(text=BASIC_ACL_TEXT)
150         basic_acl.applyto(fd)
151         for item in fd, fname:
152             self.failIf(has_extended(item),
153                         "A simple ACL should not be reported as extended")
154         enhanced_acl = posix1e.ACL(text="u::rw,g::-,o::-,u:root:rw,mask::r")
155         self.failUnless(enhanced_acl.valid(),
156                         "Failure to build an extended ACL")
157         enhanced_acl.applyto(fd)
158         for item in fd, fname:
159             self.failUnless(has_extended(item),
160                         "An extended ACL should be reported as such")
161
162     @has_ext(HAS_EQUIV_MODE)
163     def testEquivMode(self):
164         """Test the equiv_mode function"""
165         if HAS_ACL_FROM_MODE:
166             for mode in M0644, M0755:
167                 acl = posix1e.ACL(mode=mode)
168                 self.failUnlessEqual(acl.equiv_mode(), mode)
169         acl = posix1e.ACL(text="u::rw,g::r,o::r")
170         self.failUnlessEqual(acl.equiv_mode(), M0644)
171         acl = posix1e.ACL(text="u::rx,g::-,o::-")
172         self.failUnlessEqual(acl.equiv_mode(), M0500)
173
174
175 class WriteTests(aclTest, unittest.TestCase):
176     """Write tests"""
177
178     def testDeleteDefault(self):
179         """Test removing the default ACL"""
180         dname = self._getdir()
181         posix1e.delete_default(dname)
182
183     def testReapply(self):
184         """Test re-applying an ACL"""
185         fd, fname = self._getfile()
186         acl1 = posix1e.ACL(fd=fd)
187         acl1.applyto(fd)
188         acl1.applyto(fname)
189         dname = self._getdir()
190         acl2 = posix1e.ACL(file=fname)
191         acl2.applyto(dname)
192
193
194 class ModificationTests(aclTest, unittest.TestCase):
195     """ACL modification tests"""
196
197     @has_ext(HAS_ACL_ENTRY)
198     def testAppend(self):
199         """Test append a new Entry to the ACL"""
200         acl = posix1e.ACL()
201         e = acl.append()
202         e.tag_type = posix1e.ACL_OTHER
203         acl.calc_mask()
204
205     @has_ext(HAS_ACL_ENTRY)
206     def testDelete(self):
207         """Test delete Entry from the ACL"""
208         acl = posix1e.ACL()
209         e = acl.append()
210         e.tag_type = posix1e.ACL_OTHER
211         acl.calc_mask()
212         acl.delete_entry(e)
213         acl.calc_mask()
214
215     @has_ext(HAS_ACL_ENTRY)
216     def testDoubleEntries(self):
217         """Test double entries"""
218         acl = posix1e.ACL(text=BASIC_ACL_TEXT)
219         self.failUnless(acl.valid(), "ACL is not valid")
220         for tag_type in (posix1e.ACL_USER_OBJ, posix1e.ACL_GROUP_OBJ,
221                          posix1e.ACL_OTHER):
222             e = acl.append()
223             e.tag_type = tag_type
224             e.permset.clear()
225             self.failIf(acl.valid(),
226                         "ACL containing duplicate entries should not be valid")
227             acl.delete_entry(e)
228
229     @has_ext(HAS_ACL_ENTRY)
230     def testMultipleGoodEntries(self):
231         """Test multiple valid entries"""
232         acl = posix1e.ACL(text=BASIC_ACL_TEXT)
233         self.failUnless(acl.valid(), "ACL is not valid")
234         for tag_type in (posix1e.ACL_USER,
235                          posix1e.ACL_GROUP):
236             for obj_id in range(5):
237                 e = acl.append()
238                 e.tag_type = tag_type
239                 e.qualifier = obj_id
240                 e.permset.clear()
241                 acl.calc_mask()
242                 self.failUnless(acl.valid(),
243                                "ACL should be able to hold multiple"
244                                 " user/group entries")
245
246     @has_ext(HAS_ACL_ENTRY)
247     def testMultipleBadEntries(self):
248         """Test multiple invalid entries"""
249         acl = posix1e.ACL(text=BASIC_ACL_TEXT)
250         self.failUnless(acl.valid(), "ACL built from standard description"
251                         " should be valid")
252         for tag_type in (posix1e.ACL_USER,
253                          posix1e.ACL_GROUP):
254             e1 = acl.append()
255             e1.tag_type = tag_type
256             e1.qualifier = 0
257             e1.permset.clear()
258             acl.calc_mask()
259             self.failUnless(acl.valid(), "ACL should be able to add a"
260                             " user/group entry")
261             e2 = acl.append()
262             e2.tag_type = tag_type
263             e2.qualifier = 0
264             e2.permset.clear()
265             acl.calc_mask()
266             self.failIf(acl.valid(), "ACL should not validate when"
267                         " containing two duplicate entries")
268             acl.delete_entry(e1)
269             acl.delete_entry(e2)
270
271     @has_ext(HAS_ACL_ENTRY)
272     def testPermset(self):
273         """Test permissions"""
274         acl = posix1e.ACL()
275         e = acl.append()
276         ps = e.permset
277         ps.clear()
278         pmap = {
279             posix1e.ACL_READ: "read",
280             posix1e.ACL_WRITE: "write",
281             posix1e.ACL_EXECUTE: "execute",
282             }
283         for perm in pmap:
284             self.failIf(ps.test(perm), "Empty permission set should not"
285                         " have permission '%s'" % pmap[perm])
286             ps.add(perm)
287             self.failUnless(ps.test(perm), "Permission '%s' should exist"
288                         " after addition" % pmap[perm])
289             ps.delete(perm)
290             self.failIf(ps.test(perm), "Permission '%s' should not exist"
291                         " after deletion" % pmap[perm])
292
293
294 if __name__ == "__main__":
295     unittest.main()