4 """Unittests for the posix1e module"""
6 # Copyright (C) 2002-2009, 2012 Iustin Pop <iusty@k1024.org>
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.
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.
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
33 TEST_DIR = os.environ.get("TEST_DIR", ".")
35 BASIC_ACL_TEXT = "u::rw,g::r,o::-"
37 # This is to workaround python 2/3 differences at syntactic level
38 # (which can't be worked around via if's)
39 M0500 = 320 # octal 0500
40 M0644 = 420 # octal 0644
41 M0755 = 493 # octal 755
44 """Wrapper to skip a test"""
45 new_fn = lambda x: None
46 new_fn.__doc__ = "SKIPPED %s" % fn.__doc__
50 def has_ext(extension):
51 """Decorator to skip tests based on platform support"""
59 """Support functions ACLs"""
67 """tear down function"""
68 for fname in self.rmfiles:
70 for dname in self.rmdirs:
74 """create a temp file"""
75 fh, fname = tempfile.mkstemp(".test", "xattr-", TEST_DIR)
76 self.rmfiles.append(fname)
80 """create a temp dir"""
81 dname = tempfile.mkdtemp(".test", "xattr-", TEST_DIR)
82 self.rmdirs.append(dname)
85 def _getsymlink(self):
86 """create a symlink"""
87 fh, fname = self._getfile()
90 os.symlink(fname + ".non-existent", fname)
94 class LoadTests(aclTest, unittest.TestCase):
95 """Load/create tests"""
96 def testFromFile(self):
97 """Test loading ACLs from a file"""
98 _, fname = self._getfile()
99 acl1 = posix1e.ACL(file=fname)
100 self.assertTrue(acl1.valid(), "ACL read from file should be valid")
102 def testFromDir(self):
103 """Test loading ACLs from a directory"""
104 dname = self._getdir()
105 acl1 = posix1e.ACL(file=dname)
106 acl2 = posix1e.ACL(filedef=dname)
107 self.assertTrue(acl1.valid(),
108 "ACL read from directory should be valid")
109 # default ACLs might or might not be valid; missing ones are
110 # not valid, so we don't test acl2 for validity
112 def testFromFd(self):
113 """Test loading ACLs from a file descriptor"""
114 fd, _ = self._getfile()
115 acl1 = posix1e.ACL(fd=fd)
116 self.assertTrue(acl1.valid(), "ACL read from fd should be valid")
118 def testFromEmpty(self):
119 """Test creating an empty ACL"""
121 self.assertFalse(acl1.valid(), "Empty ACL should not be valid")
123 def testFromText(self):
124 """Test creating an ACL from text"""
125 acl1 = posix1e.ACL(text=BASIC_ACL_TEXT)
126 self.assertTrue(acl1.valid(),
127 "ACL based on standard description should be valid")
129 class AclExtensions(aclTest, unittest.TestCase):
130 """ACL extensions checks"""
132 @has_ext(HAS_ACL_FROM_MODE)
133 def testFromMode(self):
134 """Test loading ACLs from an octal mode"""
135 acl1 = posix1e.ACL(mode=M0644)
136 self.assertTrue(acl1.valid(),
137 "ACL created via octal mode shoule be valid")
139 @has_ext(HAS_ACL_CHECK)
140 def testAclCheck(self):
141 """Test the acl_check method"""
142 acl1 = posix1e.ACL(text=BASIC_ACL_TEXT)
143 self.assertFalse(acl1.check(), "ACL is not valid")
145 self.assertTrue(acl2.check(), "Empty ACL should not be valid")
147 @has_ext(HAS_EXTENDED_CHECK)
148 def testExtended(self):
149 """Test the acl_extended function"""
150 fd, fname = self._getfile()
151 basic_acl = posix1e.ACL(text=BASIC_ACL_TEXT)
152 basic_acl.applyto(fd)
153 for item in fd, fname:
154 self.assertFalse(has_extended(item),
155 "A simple ACL should not be reported as extended")
156 enhanced_acl = posix1e.ACL(text="u::rw,g::-,o::-,u:root:rw,mask::r")
157 self.assertTrue(enhanced_acl.valid(),
158 "Failure to build an extended ACL")
159 enhanced_acl.applyto(fd)
160 for item in fd, fname:
161 self.assertTrue(has_extended(item),
162 "An extended ACL should be reported as such")
164 @has_ext(HAS_EQUIV_MODE)
165 def testEquivMode(self):
166 """Test the equiv_mode function"""
167 if HAS_ACL_FROM_MODE:
168 for mode in M0644, M0755:
169 acl = posix1e.ACL(mode=mode)
170 self.assertEqual(acl.equiv_mode(), mode)
171 acl = posix1e.ACL(text="u::rw,g::r,o::r")
172 self.assertEqual(acl.equiv_mode(), M0644)
173 acl = posix1e.ACL(text="u::rx,g::-,o::-")
174 self.assertEqual(acl.equiv_mode(), M0500)
177 class WriteTests(aclTest, unittest.TestCase):
180 def testDeleteDefault(self):
181 """Test removing the default ACL"""
182 dname = self._getdir()
183 posix1e.delete_default(dname)
185 def testReapply(self):
186 """Test re-applying an ACL"""
187 fd, fname = self._getfile()
188 acl1 = posix1e.ACL(fd=fd)
191 dname = self._getdir()
192 acl2 = posix1e.ACL(file=fname)
196 class ModificationTests(aclTest, unittest.TestCase):
197 """ACL modification tests"""
199 def checkRef(self, obj):
200 """Checks if a given obj has a 'sane' refcount"""
201 if platform.python_implementation() == "PyPy":
203 ref_cnt = sys.getrefcount(obj)
204 # FIXME: hardcoded value for the max ref count... but I've
205 # seen it overflow on bad reference counting, so it's better
207 if ref_cnt < 2 or ref_cnt > 1024:
208 self.fail("Wrong reference count, expected 2-1024 and got %d" %
212 """Test str() of an ACL."""
215 self.checkRef(str_acl)
217 @has_ext(HAS_ACL_ENTRY)
218 def testAppend(self):
219 """Test append a new Entry to the ACL"""
222 e.tag_type = posix1e.ACL_OTHER
225 self.checkRef(str_format)
227 @has_ext(HAS_ACL_ENTRY)
228 def testDelete(self):
229 """Test delete Entry from the ACL"""
232 e.tag_type = posix1e.ACL_OTHER
237 @has_ext(HAS_ACL_ENTRY)
238 def testDoubleEntries(self):
239 """Test double entries"""
240 acl = posix1e.ACL(text=BASIC_ACL_TEXT)
241 self.assertTrue(acl.valid(), "ACL is not valid")
242 for tag_type in (posix1e.ACL_USER_OBJ, posix1e.ACL_GROUP_OBJ,
245 e.tag_type = tag_type
247 self.assertFalse(acl.valid(),
248 "ACL containing duplicate entries"
249 " should not be valid")
252 @has_ext(HAS_ACL_ENTRY)
253 def testMultipleGoodEntries(self):
254 """Test multiple valid entries"""
255 acl = posix1e.ACL(text=BASIC_ACL_TEXT)
256 self.assertTrue(acl.valid(), "ACL is not valid")
257 for tag_type in (posix1e.ACL_USER,
259 for obj_id in range(5):
261 e.tag_type = tag_type
265 self.assertTrue(acl.valid(),
266 "ACL should be able to hold multiple"
267 " user/group entries")
269 @has_ext(HAS_ACL_ENTRY)
270 def testMultipleBadEntries(self):
271 """Test multiple invalid entries"""
272 acl = posix1e.ACL(text=BASIC_ACL_TEXT)
273 self.assertTrue(acl.valid(), "ACL built from standard description"
275 for tag_type in (posix1e.ACL_USER,
278 e1.tag_type = tag_type
282 self.assertTrue(acl.valid(), "ACL should be able to add a"
285 e2.tag_type = tag_type
289 self.assertFalse(acl.valid(), "ACL should not validate when"
290 " containing two duplicate entries")
294 @has_ext(HAS_ACL_ENTRY)
295 def testPermset(self):
296 """Test permissions"""
302 self.checkRef(str_ps)
304 posix1e.ACL_READ: "read",
305 posix1e.ACL_WRITE: "write",
306 posix1e.ACL_EXECUTE: "execute",
310 self.checkRef(str_ps)
311 self.assertFalse(ps.test(perm), "Empty permission set should not"
312 " have permission '%s'" % pmap[perm])
314 self.assertTrue(ps.test(perm), "Permission '%s' should exist"
315 " after addition" % pmap[perm])
317 self.checkRef(str_ps)
319 self.assertFalse(ps.test(perm), "Permission '%s' should not exist"
320 " after deletion" % pmap[perm])
323 if __name__ == "__main__":