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
32 TEST_DIR = os.environ.get("TESTDIR", ".")
34 BASIC_ACL_TEXT = "u::rw,g::r,o::-"
36 # This is to workaround python 2/3 differences at syntactic level
37 # (which can't be worked around via if's)
38 M0500 = 320 # octal 0500
39 M0644 = 420 # octal 0644
40 M0755 = 493 # octal 755
43 """Wrapper to skip a test"""
44 new_fn = lambda x: None
45 new_fn.__doc__ = "SKIPPED %s" % fn.__doc__
49 def has_ext(extension):
50 """Decorator to skip tests based on platform support"""
58 """Support functions ACLs"""
66 """tear down function"""
67 for fname in self.rmfiles:
69 for dname in self.rmdirs:
73 """create a temp file"""
74 fh, fname = tempfile.mkstemp(".test", "xattr-", TEST_DIR)
75 self.rmfiles.append(fname)
79 """create a temp dir"""
80 dname = tempfile.mkdtemp(".test", "xattr-", TEST_DIR)
81 self.rmdirs.append(dname)
84 def _getsymlink(self):
85 """create a symlink"""
86 fh, fname = self._getfile()
89 os.symlink(fname + ".non-existent", fname)
93 class LoadTests(aclTest, unittest.TestCase):
94 """Load/create tests"""
95 def testFromFile(self):
96 """Test loading ACLs from a file"""
97 _, fname = self._getfile()
98 acl1 = posix1e.ACL(file=fname)
99 self.assertTrue(acl1.valid(), "ACL read from file should be valid")
101 def testFromDir(self):
102 """Test loading ACLs from a directory"""
103 dname = self._getdir()
104 acl1 = posix1e.ACL(file=dname)
105 acl2 = posix1e.ACL(filedef=dname)
106 self.assertTrue(acl1.valid(),
107 "ACL read from directory should be valid")
108 # default ACLs might or might not be valid; missing ones are
109 # not valid, so we don't test acl2 for validity
111 def testFromFd(self):
112 """Test loading ACLs from a file descriptor"""
113 fd, _ = self._getfile()
114 acl1 = posix1e.ACL(fd=fd)
115 self.assertTrue(acl1.valid(), "ACL read from fd should be valid")
117 def testFromEmpty(self):
118 """Test creating an empty ACL"""
120 self.assertFalse(acl1.valid(), "Empty ACL should not be valid")
122 def testFromText(self):
123 """Test creating an ACL from text"""
124 acl1 = posix1e.ACL(text=BASIC_ACL_TEXT)
125 self.assertTrue(acl1.valid(),
126 "ACL based on standard description should be valid")
128 class AclExtensions(aclTest, unittest.TestCase):
129 """ACL extensions checks"""
131 @has_ext(HAS_ACL_FROM_MODE)
132 def testFromMode(self):
133 """Test loading ACLs from an octal mode"""
134 acl1 = posix1e.ACL(mode=M0644)
135 self.assertTrue(acl1.valid(),
136 "ACL created via octal mode shoule be valid")
138 @has_ext(HAS_ACL_CHECK)
139 def testAclCheck(self):
140 """Test the acl_check method"""
141 acl1 = posix1e.ACL(text=BASIC_ACL_TEXT)
142 self.assertFalse(acl1.check(), "ACL is not valid")
144 self.assertTrue(acl2.check(), "Empty ACL should not be valid")
146 @has_ext(HAS_EXTENDED_CHECK)
147 def testExtended(self):
148 """Test the acl_extended function"""
149 fd, fname = self._getfile()
150 basic_acl = posix1e.ACL(text=BASIC_ACL_TEXT)
151 basic_acl.applyto(fd)
152 for item in fd, fname:
153 self.assertFalse(has_extended(item),
154 "A simple ACL should not be reported as extended")
155 enhanced_acl = posix1e.ACL(text="u::rw,g::-,o::-,u:root:rw,mask::r")
156 self.assertTrue(enhanced_acl.valid(),
157 "Failure to build an extended ACL")
158 enhanced_acl.applyto(fd)
159 for item in fd, fname:
160 self.assertTrue(has_extended(item),
161 "An extended ACL should be reported as such")
163 @has_ext(HAS_EQUIV_MODE)
164 def testEquivMode(self):
165 """Test the equiv_mode function"""
166 if HAS_ACL_FROM_MODE:
167 for mode in M0644, M0755:
168 acl = posix1e.ACL(mode=mode)
169 self.assertEqual(acl.equiv_mode(), mode)
170 acl = posix1e.ACL(text="u::rw,g::r,o::r")
171 self.assertEqual(acl.equiv_mode(), M0644)
172 acl = posix1e.ACL(text="u::rx,g::-,o::-")
173 self.assertEqual(acl.equiv_mode(), M0500)
176 class WriteTests(aclTest, unittest.TestCase):
179 def testDeleteDefault(self):
180 """Test removing the default ACL"""
181 dname = self._getdir()
182 posix1e.delete_default(dname)
184 def testReapply(self):
185 """Test re-applying an ACL"""
186 fd, fname = self._getfile()
187 acl1 = posix1e.ACL(fd=fd)
190 dname = self._getdir()
191 acl2 = posix1e.ACL(file=fname)
195 class ModificationTests(aclTest, unittest.TestCase):
196 """ACL modification tests"""
198 def checkRef(self, obj):
199 """Checks if a given obj has a 'sane' refcount"""
200 ref_cnt = sys.getrefcount(obj)
201 # FIXME: hardcoded value for the max ref count... but I've
202 # seen it overflow on bad reference counting, so it's better
204 if ref_cnt < 2 or ref_cnt > 1024:
205 self.fail("Wrong reference count, expected 2-1024 and got %d" %
209 """Test str() of an ACL."""
212 self.checkRef(str_acl)
214 @has_ext(HAS_ACL_ENTRY)
215 def testAppend(self):
216 """Test append a new Entry to the ACL"""
219 e.tag_type = posix1e.ACL_OTHER
222 self.checkRef(str_format)
224 @has_ext(HAS_ACL_ENTRY)
225 def testDelete(self):
226 """Test delete Entry from the ACL"""
229 e.tag_type = posix1e.ACL_OTHER
234 @has_ext(HAS_ACL_ENTRY)
235 def testDoubleEntries(self):
236 """Test double entries"""
237 acl = posix1e.ACL(text=BASIC_ACL_TEXT)
238 self.assertTrue(acl.valid(), "ACL is not valid")
239 for tag_type in (posix1e.ACL_USER_OBJ, posix1e.ACL_GROUP_OBJ,
242 e.tag_type = tag_type
244 self.assertFalse(acl.valid(),
245 "ACL containing duplicate entries should not be valid")
248 @has_ext(HAS_ACL_ENTRY)
249 def testMultipleGoodEntries(self):
250 """Test multiple valid entries"""
251 acl = posix1e.ACL(text=BASIC_ACL_TEXT)
252 self.assertTrue(acl.valid(), "ACL is not valid")
253 for tag_type in (posix1e.ACL_USER,
255 for obj_id in range(5):
257 e.tag_type = tag_type
261 self.assertTrue(acl.valid(),
262 "ACL should be able to hold multiple"
263 " user/group entries")
265 @has_ext(HAS_ACL_ENTRY)
266 def testMultipleBadEntries(self):
267 """Test multiple invalid entries"""
268 acl = posix1e.ACL(text=BASIC_ACL_TEXT)
269 self.assertTrue(acl.valid(), "ACL built from standard description"
271 for tag_type in (posix1e.ACL_USER,
274 e1.tag_type = tag_type
278 self.assertTrue(acl.valid(), "ACL should be able to add a"
281 e2.tag_type = tag_type
285 self.assertFalse(acl.valid(), "ACL should not validate when"
286 " containing two duplicate entries")
290 @has_ext(HAS_ACL_ENTRY)
291 def testPermset(self):
292 """Test permissions"""
298 self.checkRef(str_ps)
300 posix1e.ACL_READ: "read",
301 posix1e.ACL_WRITE: "write",
302 posix1e.ACL_EXECUTE: "execute",
306 self.checkRef(str_ps)
307 self.assertFalse(ps.test(perm), "Empty permission set should not"
308 " have permission '%s'" % pmap[perm])
310 self.assertTrue(ps.test(perm), "Permission '%s' should exist"
311 " after addition" % pmap[perm])
313 self.checkRef(str_ps)
315 self.assertFalse(ps.test(perm), "Permission '%s' should not exist"
316 " after deletion" % pmap[perm])
319 if __name__ == "__main__":