11 from xattr import NS_USER, XATTR_CREATE, XATTR_REPLACE
13 NAMESPACE = os.environ.get("NAMESPACE", NS_USER)
15 if sys.hexversion >= 0x03000000:
22 TEST_DIR = os.environ.get("TEST_DIR", ".")
23 TEST_IGNORE_XATTRS = os.environ.get("TEST_IGNORE_XATTRS", "")
24 if TEST_IGNORE_XATTRS == "":
25 TEST_IGNORE_XATTRS = []
27 TEST_IGNORE_XATTRS = TEST_IGNORE_XATTRS.split(",")
28 # The following has to be a list comprehension, not a generator, to
29 # avoid weird consequences of lazy evaluation.
30 TEST_IGNORE_XATTRS.extend([a.encode() for a in TEST_IGNORE_XATTRS])
32 class xattrTest(unittest.TestCase):
34 USER_ATTR = NAMESPACE.decode() + "." + USER_NN
37 LARGE_VAL = "x" * 2048
38 MANYOPS_COUNT = 131072
41 USER_NN = USER_NN.encode()
42 USER_VAL = USER_VAL.encode()
43 USER_ATTR = USER_ATTR.encode()
44 EMPTY_VAL = EMPTY_VAL.encode()
45 LARGE_VAL = LARGE_VAL.encode()
48 def _ignore_tuples(attrs):
49 """Remove ignored attributes from the output of xattr.get_all."""
50 return [attr for attr in attrs
51 if attr[0] not in TEST_IGNORE_XATTRS]
55 """Remove ignored attributes from the output of xattr.list"""
56 return [attr for attr in attrs
57 if attr not in TEST_IGNORE_XATTRS]
59 def checkList(self, attrs, value):
60 """Helper to check list equivalence, skipping TEST_IGNORE_XATTRS."""
61 self.assertEqual(self._ignore(attrs), value)
63 def checkTuples(self, attrs, value):
64 """Helper to check list equivalence, skipping TEST_IGNORE_XATTRS."""
65 self.assertEqual(self._ignore_tuples(attrs), value)
73 """tear down function"""
74 for fname in self.rmfiles:
77 except EnvironmentError:
79 for dname in self.rmdirs:
82 except EnvironmentError:
86 """create a temp file"""
87 fh, fname = tempfile.mkstemp(".test", "xattr-", TEST_DIR)
88 self.rmfiles.append(fname)
92 """create a temp dir"""
93 dname = tempfile.mkdtemp(".test", "xattr-", TEST_DIR)
94 self.rmdirs.append(dname)
97 def _getsymlink(self, dangling=True):
98 """create a symlink"""
99 fh, fname = self._getfile()
103 sname = fname + ".symlink"
104 os.symlink(fname, sname)
105 self.rmfiles.append(sname)
108 def _checkDeprecated(self, item, symlink=False):
109 """check deprecated list, set, get operations against an item"""
110 self.checkList(xattr.listxattr(item, symlink), [])
111 self.assertRaises(EnvironmentError, xattr.setxattr, item,
112 self.USER_ATTR, self.USER_VAL,
113 XATTR_REPLACE, symlink)
115 xattr.setxattr(item, self.USER_ATTR, self.USER_VAL, 0, symlink)
117 err = sys.exc_info()[1]
118 if symlink and (err.errno == errno.EPERM or
119 err.errno == errno.ENOENT):
120 # symlinks may fail, in which case we abort the rest
121 # of the test for this case (Linux returns EPERM; OS X
125 self.assertRaises(EnvironmentError, xattr.setxattr, item,
126 self.USER_ATTR, self.USER_VAL, XATTR_CREATE, symlink)
127 self.checkList(xattr.listxattr(item, symlink), [self.USER_ATTR])
128 self.assertEqual(xattr.getxattr(item, self.USER_ATTR, symlink),
130 self.checkTuples(xattr.get_all(item, nofollow=symlink),
131 [(self.USER_ATTR, self.USER_VAL)])
132 xattr.removexattr(item, self.USER_ATTR, symlink)
133 self.checkList(xattr.listxattr(item, symlink), [])
134 self.checkTuples(xattr.get_all(item, nofollow=symlink),
136 self.assertRaises(EnvironmentError, xattr.removexattr,
137 item, self.USER_ATTR, symlink)
139 def _checkListSetGet(self, item, symlink=False, use_ns=False):
140 """check list, set, get operations against an item"""
141 self.checkList(xattr.list(item, symlink), [])
142 self.assertRaises(EnvironmentError, xattr.set, item,
143 self.USER_ATTR, self.USER_VAL,
146 self.assertRaises(EnvironmentError, xattr.set, item,
147 self.USER_NN, self.USER_VAL,
153 xattr.set(item, self.USER_NN, self.USER_VAL,
157 xattr.set(item, self.USER_ATTR, self.USER_VAL,
160 err = sys.exc_info()[1]
161 if symlink and (err.errno == errno.EPERM or
162 err.errno == errno.ENOENT):
163 # symlinks may fail, in which case we abort the rest
164 # of the test for this case (Linux returns EPERM; OS X
168 self.assertRaises(EnvironmentError, xattr.set, item,
169 self.USER_ATTR, self.USER_VAL,
172 self.assertRaises(EnvironmentError, xattr.set, item,
173 self.USER_NN, self.USER_VAL,
177 self.checkList(xattr.list(item, nofollow=symlink), [self.USER_ATTR])
178 self.checkList(xattr.list(item, nofollow=symlink,
181 self.assertEqual(xattr.list(item, namespace=NAMESPACE, nofollow=symlink),
183 self.assertEqual(xattr.get(item, self.USER_ATTR, nofollow=symlink),
185 self.assertEqual(xattr.get(item, self.USER_NN, nofollow=symlink,
186 namespace=NAMESPACE), self.USER_VAL)
187 self.checkTuples(xattr.get_all(item, nofollow=symlink),
188 [(self.USER_ATTR, self.USER_VAL)])
189 self.assertEqual(xattr.get_all(item, nofollow=symlink,
190 namespace=NAMESPACE),
191 [(self.USER_NN, self.USER_VAL)])
193 xattr.remove(item, self.USER_NN, namespace=NAMESPACE, nofollow=symlink)
195 xattr.remove(item, self.USER_ATTR, nofollow=symlink)
196 self.checkList(xattr.list(item, nofollow=symlink), [])
197 self.checkTuples(xattr.get_all(item, nofollow=symlink),
199 self.assertRaises(EnvironmentError, xattr.remove,
200 item, self.USER_ATTR, nofollow=symlink)
201 self.assertRaises(EnvironmentError, xattr.remove, item,
202 self.USER_NN, namespace=NAMESPACE, nofollow=symlink)
204 def testNoXattrDeprecated(self):
205 """test no attributes (deprecated functions)"""
206 fh, fname = self._getfile()
207 self.checkList(xattr.listxattr(fname), [])
208 self.checkTuples(xattr.get_all(fname), [])
209 self.assertRaises(EnvironmentError, xattr.getxattr, fname,
211 dname = self._getdir()
212 self.checkList(xattr.listxattr(dname), [])
213 self.checkTuples(xattr.get_all(dname), [])
214 self.assertRaises(EnvironmentError, xattr.getxattr, dname,
216 _, sname = self._getsymlink()
217 self.checkList(xattr.listxattr(sname, True), [])
218 self.checkTuples(xattr.get_all(sname, nofollow=True), [])
219 self.assertRaises(EnvironmentError, xattr.getxattr, fname,
220 self.USER_ATTR, True)
223 def testNoXattr(self):
224 """test no attributes"""
225 fh, fname = self._getfile()
226 self.checkList(xattr.list(fname), [])
227 self.assertEqual(xattr.list(fname, namespace=NAMESPACE), [])
228 self.checkTuples(xattr.get_all(fname), [])
229 self.assertEqual(xattr.get_all(fname, namespace=NAMESPACE), [])
230 self.assertRaises(EnvironmentError, xattr.get, fname,
231 self.USER_NN, namespace=NAMESPACE)
232 dname = self._getdir()
233 self.checkList(xattr.list(dname), [])
234 self.assertEqual(xattr.list(dname, namespace=NAMESPACE), [])
235 self.checkTuples(xattr.get_all(dname), [])
236 self.assertEqual(xattr.get_all(dname, namespace=NAMESPACE), [])
237 self.assertRaises(EnvironmentError, xattr.get, dname,
238 self.USER_NN, namespace=NAMESPACE)
239 _, sname = self._getsymlink()
240 self.checkList(xattr.list(sname, nofollow=True), [])
241 self.assertEqual(xattr.list(sname, nofollow=True,
242 namespace=NAMESPACE), [])
243 self.checkTuples(xattr.get_all(sname, nofollow=True), [])
244 self.assertEqual(xattr.get_all(sname, nofollow=True,
245 namespace=NAMESPACE), [])
246 self.assertRaises(EnvironmentError, xattr.get, sname,
247 self.USER_NN, namespace=NAMESPACE, nofollow=True)
249 def testFileByNameDeprecated(self):
250 """test set and retrieve one attribute by file name (deprecated)"""
251 fh, fname = self._getfile()
252 self._checkDeprecated(fname)
255 def testFileByName(self):
256 """test set and retrieve one attribute by file name"""
257 fh, fname = self._getfile()
258 self._checkListSetGet(fname)
259 self._checkListSetGet(fname, use_ns=True)
262 def testFileByDescriptorDeprecated(self):
263 """test file descriptor operations (deprecated functions)"""
264 fh, fname = self._getfile()
265 self._checkDeprecated(fh)
268 def testFileByDescriptor(self):
269 """test file descriptor operations"""
270 fh, fname = self._getfile()
271 self._checkListSetGet(fh)
272 self._checkListSetGet(fh, use_ns=True)
275 def testFileByObjectDeprecated(self):
276 """test file descriptor operations (deprecated functions)"""
277 fh, fname = self._getfile()
279 self._checkDeprecated(fo)
282 def testFileByObject(self):
283 """test file descriptor operations"""
284 fh, fname = self._getfile()
286 self._checkListSetGet(fo)
287 self._checkListSetGet(fo, use_ns=True)
290 def testMixedAccessDeprecated(self):
291 """test mixed access to file (deprecated functions)"""
292 fh, fname = self._getfile()
294 self.checkList(xattr.listxattr(fname), [])
295 xattr.setxattr(fname, self.USER_ATTR, self.USER_VAL)
296 self.checkList(xattr.listxattr(fh), [self.USER_ATTR])
297 self.assertEqual(xattr.getxattr(fo, self.USER_ATTR), self.USER_VAL)
298 self.checkTuples(xattr.get_all(fo), [(self.USER_ATTR, self.USER_VAL)])
299 self.checkTuples(xattr.get_all(fname),
300 [(self.USER_ATTR, self.USER_VAL)])
303 def testMixedAccess(self):
304 """test mixed access to file"""
305 fh, fname = self._getfile()
307 self.checkList(xattr.list(fname), [])
308 xattr.set(fname, self.USER_ATTR, self.USER_VAL)
309 self.checkList(xattr.list(fh), [self.USER_ATTR])
310 self.assertEqual(xattr.list(fh, namespace=NAMESPACE), [self.USER_NN])
311 self.assertEqual(xattr.get(fo, self.USER_ATTR), self.USER_VAL)
312 self.assertEqual(xattr.get(fo, self.USER_NN, namespace=NAMESPACE),
314 self.checkTuples(xattr.get_all(fo),
315 [(self.USER_ATTR, self.USER_VAL)])
316 self.assertEqual(xattr.get_all(fo, namespace=NAMESPACE),
317 [(self.USER_NN, self.USER_VAL)])
318 self.checkTuples(xattr.get_all(fname),
319 [(self.USER_ATTR, self.USER_VAL)])
320 self.assertEqual(xattr.get_all(fname, namespace=NAMESPACE),
321 [(self.USER_NN, self.USER_VAL)])
324 def testDirOpsDeprecated(self):
325 """test attribute setting on directories (deprecated functions)"""
326 dname = self._getdir()
327 self._checkDeprecated(dname)
329 def testDirOps(self):
330 """test attribute setting on directories"""
331 dname = self._getdir()
332 self._checkListSetGet(dname)
333 self._checkListSetGet(dname, use_ns=True)
335 def testSymlinkOpsDeprecated(self):
336 """test symlink operations (deprecated functions)"""
337 _, sname = self._getsymlink()
338 self.assertRaises(EnvironmentError, xattr.listxattr, sname)
339 self._checkDeprecated(sname, symlink=True)
340 target, sname = self._getsymlink(dangling=False)
341 xattr.setxattr(target, self.USER_ATTR, self.USER_VAL)
342 self.checkList(xattr.listxattr(target), [self.USER_ATTR])
343 self.checkList(xattr.listxattr(sname, True), [])
344 self.assertRaises(EnvironmentError, xattr.removexattr, sname,
345 self.USER_ATTR, True)
346 xattr.removexattr(sname, self.USER_ATTR, False)
348 def testSymlinkOps(self):
349 """test symlink operations"""
350 _, sname = self._getsymlink()
351 self.assertRaises(EnvironmentError, xattr.list, sname)
352 self._checkListSetGet(sname, symlink=True)
353 self._checkListSetGet(sname, symlink=True, use_ns=True)
354 target, sname = self._getsymlink(dangling=False)
355 xattr.set(target, self.USER_ATTR, self.USER_VAL)
356 self.checkList(xattr.list(target), [self.USER_ATTR])
357 self.checkList(xattr.list(sname, nofollow=True), [])
358 self.assertRaises(EnvironmentError, xattr.remove, sname,
359 self.USER_ATTR, nofollow=True)
360 xattr.remove(sname, self.USER_ATTR, nofollow=False)
362 def testBinaryPayloadDeprecated(self):
363 """test binary values (deprecated functions)"""
364 fh, fname = self._getfile()
366 BINVAL = "abc" + '\0' + "def"
368 BINVAL = BINVAL.encode()
369 xattr.setxattr(fname, self.USER_ATTR, BINVAL)
370 self.checkList(xattr.listxattr(fname), [self.USER_ATTR])
371 self.assertEqual(xattr.getxattr(fname, self.USER_ATTR), BINVAL)
372 self.checkTuples(xattr.get_all(fname), [(self.USER_ATTR, BINVAL)])
373 xattr.removexattr(fname, self.USER_ATTR)
375 def testBinaryPayload(self):
376 """test binary values"""
377 fh, fname = self._getfile()
379 BINVAL = "abc" + '\0' + "def"
381 BINVAL = BINVAL.encode()
382 xattr.set(fname, self.USER_ATTR, BINVAL)
383 self.checkList(xattr.list(fname), [self.USER_ATTR])
384 self.assertEqual(xattr.list(fname, namespace=NAMESPACE), [self.USER_NN])
385 self.assertEqual(xattr.get(fname, self.USER_ATTR), BINVAL)
386 self.assertEqual(xattr.get(fname, self.USER_NN,
387 namespace=NAMESPACE), BINVAL)
388 self.checkTuples(xattr.get_all(fname), [(self.USER_ATTR, BINVAL)])
389 self.assertEqual(xattr.get_all(fname, namespace=NAMESPACE),
390 [(self.USER_NN, BINVAL)])
391 xattr.remove(fname, self.USER_ATTR)
393 def testManyOpsDeprecated(self):
394 """test many ops (deprecated functions)"""
395 fh, fname = self._getfile()
396 xattr.setxattr(fh, self.USER_ATTR, self.USER_VAL)
397 VL = [self.USER_ATTR]
398 for i in range(self.MANYOPS_COUNT):
399 self.checkList(xattr.listxattr(fh), VL)
400 for i in range(self.MANYOPS_COUNT):
401 self.assertEqual(xattr.getxattr(fh, self.USER_ATTR), self.USER_VAL)
402 for i in range(self.MANYOPS_COUNT):
403 self.checkTuples(xattr.get_all(fh),
404 [(self.USER_ATTR, self.USER_VAL)])
406 def testManyOps(self):
408 fh, fname = self._getfile()
409 xattr.set(fh, self.USER_ATTR, self.USER_VAL)
410 VL = [self.USER_ATTR]
412 for i in range(self.MANYOPS_COUNT):
413 self.checkList(xattr.list(fh), VL)
414 self.checkList(xattr.list(fh, namespace=EMPTY_NS), VL)
415 self.assertEqual(xattr.list(fh, namespace=NAMESPACE), VN)
416 for i in range(self.MANYOPS_COUNT):
417 self.assertEqual(xattr.get(fh, self.USER_ATTR), self.USER_VAL)
418 self.assertEqual(xattr.get(fh, self.USER_NN, namespace=NAMESPACE),
420 for i in range(self.MANYOPS_COUNT):
421 self.checkTuples(xattr.get_all(fh),
422 [(self.USER_ATTR, self.USER_VAL)])
423 self.assertEqual(xattr.get_all(fh, namespace=NAMESPACE),
424 [(self.USER_NN, self.USER_VAL)])
426 def testNoneNamespace(self):
427 fh, fname = self._getfile()
428 self.assertRaises(TypeError, xattr.get, fh, self.USER_ATTR,
431 def testEmptyValue(self):
432 fh, fname = self._getfile()
433 xattr.set(fh, self.USER_ATTR, self.EMPTY_VAL)
434 self.assertEqual(xattr.get(fh, self.USER_ATTR), self.EMPTY_VAL)
436 def testWrongCall(self):
437 for call in [xattr.get,
438 xattr.list, xattr.listxattr,
439 xattr.remove, xattr.removexattr,
440 xattr.set, xattr.setxattr,
441 xattr.get, xattr.getxattr]:
442 self.assertRaises(TypeError, call)
444 def testWrongType(self):
445 self.assertRaises(TypeError, xattr.get, object(), self.USER_ATTR)
446 for call in [xattr.listxattr, xattr.list]:
447 self.assertRaises(TypeError, call, object())
448 for call in [xattr.remove, xattr.removexattr,
449 xattr.get, xattr.getxattr]:
450 self.assertRaises(TypeError, call, object(), self.USER_ATTR)
451 for call in [xattr.set, xattr.setxattr]:
452 self.assertRaises(TypeError, call, object(), self.USER_ATTR, self.USER_VAL)
455 def testLargeAttribute(self):
456 fh, fname = self._getfile()
458 xattr.set(fh, self.USER_ATTR, self.LARGE_VAL)
459 self.assertEqual(xattr.get(fh, self.USER_ATTR), self.LARGE_VAL)
462 if __name__ == "__main__":