4 """Unittests for the posix1e module"""
6 # Copyright (C) 2002-2009, 2012, 2014 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
43 # Check if running under Python 3
44 IS_PY_3K = sys.hexversion >= 0x03000000
47 """Wrapper to skip a test"""
48 new_fn = lambda x: None
49 new_fn.__doc__ = "SKIPPED %s" % fn.__doc__
53 def has_ext(extension):
54 """Decorator to skip tests based on platform support"""
62 """Support functions ACLs"""
70 """tear down function"""
71 for fname in self.rmfiles:
73 for dname in self.rmdirs:
77 """create a temp file"""
78 fh, fname = tempfile.mkstemp(".test", "xattr-", TEST_DIR)
79 self.rmfiles.append(fname)
83 """create a temp dir"""
84 dname = tempfile.mkdtemp(".test", "xattr-", TEST_DIR)
85 self.rmdirs.append(dname)
88 def _getsymlink(self):
89 """create a symlink"""
90 fh, fname = self._getfile()
93 os.symlink(fname + ".non-existent", fname)
97 class LoadTests(aclTest, unittest.TestCase):
98 """Load/create tests"""
99 def testFromFile(self):
100 """Test loading ACLs from a file"""
101 _, fname = self._getfile()
102 acl1 = posix1e.ACL(file=fname)
103 self.assertTrue(acl1.valid(), "ACL read from file should be valid")
105 def testFromDir(self):
106 """Test loading ACLs from a directory"""
107 dname = self._getdir()
108 acl1 = posix1e.ACL(file=dname)
109 acl2 = posix1e.ACL(filedef=dname)
110 self.assertTrue(acl1.valid(),
111 "ACL read from directory should be valid")
112 # default ACLs might or might not be valid; missing ones are
113 # not valid, so we don't test acl2 for validity
115 def testFromFd(self):
116 """Test loading ACLs from a file descriptor"""
117 fd, _ = self._getfile()
118 acl1 = posix1e.ACL(fd=fd)
119 self.assertTrue(acl1.valid(), "ACL read from fd should be valid")
121 def testFromEmpty(self):
122 """Test creating an empty ACL"""
124 self.assertFalse(acl1.valid(), "Empty ACL should not be valid")
126 def testFromText(self):
127 """Test creating an ACL from text"""
128 acl1 = posix1e.ACL(text=BASIC_ACL_TEXT)
129 self.assertTrue(acl1.valid(),
130 "ACL based on standard description should be valid")
132 class AclExtensions(aclTest, unittest.TestCase):
133 """ACL extensions checks"""
135 @has_ext(HAS_ACL_FROM_MODE)
136 def testFromMode(self):
137 """Test loading ACLs from an octal mode"""
138 acl1 = posix1e.ACL(mode=M0644)
139 self.assertTrue(acl1.valid(),
140 "ACL created via octal mode shoule be valid")
142 @has_ext(HAS_ACL_CHECK)
143 def testAclCheck(self):
144 """Test the acl_check method"""
145 acl1 = posix1e.ACL(text=BASIC_ACL_TEXT)
146 self.assertFalse(acl1.check(), "ACL is not valid")
148 self.assertTrue(acl2.check(), "Empty ACL should not be valid")
150 @has_ext(HAS_EXTENDED_CHECK)
151 def testExtended(self):
152 """Test the acl_extended function"""
153 fd, fname = self._getfile()
154 basic_acl = posix1e.ACL(text=BASIC_ACL_TEXT)
155 basic_acl.applyto(fd)
156 for item in fd, fname:
157 self.assertFalse(has_extended(item),
158 "A simple ACL should not be reported as extended")
159 enhanced_acl = posix1e.ACL(text="u::rw,g::-,o::-,u:root:rw,mask::r")
160 self.assertTrue(enhanced_acl.valid(),
161 "Failure to build an extended ACL")
162 enhanced_acl.applyto(fd)
163 for item in fd, fname:
164 self.assertTrue(has_extended(item),
165 "An extended ACL should be reported as such")
167 @has_ext(HAS_EQUIV_MODE)
168 def testEquivMode(self):
169 """Test the equiv_mode function"""
170 if HAS_ACL_FROM_MODE:
171 for mode in M0644, M0755:
172 acl = posix1e.ACL(mode=mode)
173 self.assertEqual(acl.equiv_mode(), mode)
174 acl = posix1e.ACL(text="u::rw,g::r,o::r")
175 self.assertEqual(acl.equiv_mode(), M0644)
176 acl = posix1e.ACL(text="u::rx,g::-,o::-")
177 self.assertEqual(acl.equiv_mode(), M0500)
180 class WriteTests(aclTest, unittest.TestCase):
183 def testDeleteDefault(self):
184 """Test removing the default ACL"""
185 dname = self._getdir()
186 posix1e.delete_default(dname)
188 def testReapply(self):
189 """Test re-applying an ACL"""
190 fd, fname = self._getfile()
191 acl1 = posix1e.ACL(fd=fd)
194 dname = self._getdir()
195 acl2 = posix1e.ACL(file=fname)
199 class ModificationTests(aclTest, unittest.TestCase):
200 """ACL modification tests"""
202 def checkRef(self, obj):
203 """Checks if a given obj has a 'sane' refcount"""
204 if platform.python_implementation() == "PyPy":
206 ref_cnt = sys.getrefcount(obj)
207 # FIXME: hardcoded value for the max ref count... but I've
208 # seen it overflow on bad reference counting, so it's better
210 if ref_cnt < 2 or ref_cnt > 1024:
211 self.fail("Wrong reference count, expected 2-1024 and got %d" %
215 """Test str() of an ACL."""
218 self.checkRef(str_acl)
220 @has_ext(HAS_ACL_ENTRY)
221 def testAppend(self):
222 """Test append a new Entry to the ACL"""
225 e.tag_type = posix1e.ACL_OTHER
228 self.checkRef(str_format)
230 @has_ext(HAS_ACL_ENTRY)
231 def testDelete(self):
232 """Test delete Entry from the ACL"""
235 e.tag_type = posix1e.ACL_OTHER
240 @has_ext(HAS_ACL_ENTRY)
241 def testDoubleEntries(self):
242 """Test double entries"""
243 acl = posix1e.ACL(text=BASIC_ACL_TEXT)
244 self.assertTrue(acl.valid(), "ACL is not valid")
245 for tag_type in (posix1e.ACL_USER_OBJ, posix1e.ACL_GROUP_OBJ,
248 e.tag_type = tag_type
250 self.assertFalse(acl.valid(),
251 "ACL containing duplicate entries"
252 " should not be valid")
255 @has_ext(HAS_ACL_ENTRY)
256 def testMultipleGoodEntries(self):
257 """Test multiple valid entries"""
258 acl = posix1e.ACL(text=BASIC_ACL_TEXT)
259 self.assertTrue(acl.valid(), "ACL is not valid")
260 for tag_type in (posix1e.ACL_USER,
262 for obj_id in range(5):
264 e.tag_type = tag_type
268 self.assertTrue(acl.valid(),
269 "ACL should be able to hold multiple"
270 " user/group entries")
272 @has_ext(HAS_ACL_ENTRY)
273 def testMultipleBadEntries(self):
274 """Test multiple invalid entries"""
275 acl = posix1e.ACL(text=BASIC_ACL_TEXT)
276 self.assertTrue(acl.valid(), "ACL built from standard description"
278 for tag_type in (posix1e.ACL_USER,
281 e1.tag_type = tag_type
285 self.assertTrue(acl.valid(), "ACL should be able to add a"
288 e2.tag_type = tag_type
292 self.assertFalse(acl.valid(), "ACL should not validate when"
293 " containing two duplicate entries")
297 @has_ext(HAS_ACL_ENTRY)
298 def testPermset(self):
299 """Test permissions"""
305 self.checkRef(str_ps)
307 posix1e.ACL_READ: "read",
308 posix1e.ACL_WRITE: "write",
309 posix1e.ACL_EXECUTE: "execute",
313 self.checkRef(str_ps)
314 self.assertFalse(ps.test(perm), "Empty permission set should not"
315 " have permission '%s'" % pmap[perm])
317 self.assertTrue(ps.test(perm), "Permission '%s' should exist"
318 " after addition" % pmap[perm])
320 self.checkRef(str_ps)
322 self.assertFalse(ps.test(perm), "Permission '%s' should not exist"
323 " after deletion" % pmap[perm])
326 @has_ext(HAS_ACL_ENTRY and IS_PY_3K)
327 def testQualifierOverflow(self):
328 """Tests qualifier overflow handling"""
331 qualifier = sys.maxsize * 2
332 for tag in [posix1e.ACL_USER, posix1e.ACL_GROUP]:
333 e.tag_type = posix1e.ACL_USER
334 with self.assertRaises(OverflowError):
335 e.qualifier = qualifier
339 if __name__ == "__main__":