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])
33 USER_ATTR = NAMESPACE.decode() + "." + USER_NN
36 LARGE_VAL = "x" * 2048
37 MANYOPS_COUNT = 131072
40 USER_NN = USER_NN.encode()
41 USER_VAL = USER_VAL.encode()
42 USER_ATTR = USER_ATTR.encode()
43 EMPTY_VAL = EMPTY_VAL.encode()
44 LARGE_VAL = LARGE_VAL.encode()
46 def ignore_tuples(attrs):
47 """Remove ignored attributes from the output of xattr.get_all."""
48 return [attr for attr in attrs
49 if attr[0] not in TEST_IGNORE_XATTRS]
52 """Remove ignored attributes from the output of xattr.list"""
53 return [attr for attr in attrs
54 if attr not in TEST_IGNORE_XATTRS]
56 def lists_equal(attrs, value):
57 """Helper to check list equivalence, skipping TEST_IGNORE_XATTRS."""
58 assert ignore(attrs) == value
60 def tuples_equal(attrs, value):
61 """Helper to check list equivalence, skipping TEST_IGNORE_XATTRS."""
62 assert ignore_tuples(attrs) == value
65 class xattrTest(unittest.TestCase):
72 """tear down function"""
73 for fname in self.rmfiles:
76 except EnvironmentError:
78 for dname in self.rmdirs:
81 except EnvironmentError:
85 """create a temp file"""
86 fh, fname = tempfile.mkstemp(".test", "xattr-", TEST_DIR)
87 self.rmfiles.append(fname)
91 """create a temp dir"""
92 dname = tempfile.mkdtemp(".test", "xattr-", TEST_DIR)
93 self.rmdirs.append(dname)
96 def _getsymlink(self, dangling=True):
97 """create a symlink"""
98 fh, fname = self._getfile()
102 sname = fname + ".symlink"
103 os.symlink(fname, sname)
104 self.rmfiles.append(sname)
107 def _checkDeprecated(self, item, symlink=False):
108 """check deprecated list, set, get operations against an item"""
109 lists_equal(xattr.listxattr(item, symlink), [])
110 self.assertRaises(EnvironmentError, xattr.setxattr, item,
112 XATTR_REPLACE, symlink)
114 xattr.setxattr(item, USER_ATTR, USER_VAL, 0, symlink)
116 err = sys.exc_info()[1]
117 if symlink and (err.errno == errno.EPERM or
118 err.errno == errno.ENOENT):
119 # symlinks may fail, in which case we abort the rest
120 # of the test for this case (Linux returns EPERM; OS X
124 self.assertRaises(EnvironmentError, xattr.setxattr, item,
125 USER_ATTR, USER_VAL, XATTR_CREATE, symlink)
126 lists_equal(xattr.listxattr(item, symlink), [USER_ATTR])
127 self.assertEqual(xattr.getxattr(item, USER_ATTR, symlink),
129 tuples_equal(xattr.get_all(item, nofollow=symlink),
130 [(USER_ATTR, USER_VAL)])
131 xattr.removexattr(item, USER_ATTR, symlink)
132 lists_equal(xattr.listxattr(item, symlink), [])
133 tuples_equal(xattr.get_all(item, nofollow=symlink),
135 self.assertRaises(EnvironmentError, xattr.removexattr,
136 item, USER_ATTR, symlink)
138 def _checkListSetGet(self, item, symlink=False, use_ns=False):
139 """check list, set, get operations against an item"""
140 lists_equal(xattr.list(item, symlink), [])
141 self.assertRaises(EnvironmentError, xattr.set, item,
145 self.assertRaises(EnvironmentError, xattr.set, item,
152 xattr.set(item, USER_NN, USER_VAL,
156 xattr.set(item, USER_ATTR, USER_VAL,
159 err = sys.exc_info()[1]
160 if symlink and (err.errno == errno.EPERM or
161 err.errno == errno.ENOENT):
162 # symlinks may fail, in which case we abort the rest
163 # of the test for this case (Linux returns EPERM; OS X
167 self.assertRaises(EnvironmentError, xattr.set, item,
171 self.assertRaises(EnvironmentError, xattr.set, item,
176 lists_equal(xattr.list(item, nofollow=symlink), [USER_ATTR])
177 lists_equal(xattr.list(item, nofollow=symlink,
180 self.assertEqual(xattr.list(item, namespace=NAMESPACE, nofollow=symlink),
182 self.assertEqual(xattr.get(item, USER_ATTR, nofollow=symlink),
184 self.assertEqual(xattr.get(item, USER_NN, nofollow=symlink,
185 namespace=NAMESPACE), USER_VAL)
186 tuples_equal(xattr.get_all(item, nofollow=symlink),
187 [(USER_ATTR, USER_VAL)])
188 self.assertEqual(xattr.get_all(item, nofollow=symlink,
189 namespace=NAMESPACE),
190 [(USER_NN, USER_VAL)])
192 xattr.remove(item, USER_NN, namespace=NAMESPACE, nofollow=symlink)
194 xattr.remove(item, USER_ATTR, nofollow=symlink)
195 lists_equal(xattr.list(item, nofollow=symlink), [])
196 tuples_equal(xattr.get_all(item, nofollow=symlink),
198 self.assertRaises(EnvironmentError, xattr.remove,
199 item, USER_ATTR, nofollow=symlink)
200 self.assertRaises(EnvironmentError, xattr.remove, item,
201 USER_NN, namespace=NAMESPACE, nofollow=symlink)
203 def testNoXattrDeprecated(self):
204 """test no attributes (deprecated functions)"""
205 fh, fname = self._getfile()
206 lists_equal(xattr.listxattr(fname), [])
207 tuples_equal(xattr.get_all(fname), [])
208 self.assertRaises(EnvironmentError, xattr.getxattr, fname,
210 dname = self._getdir()
211 lists_equal(xattr.listxattr(dname), [])
212 tuples_equal(xattr.get_all(dname), [])
213 self.assertRaises(EnvironmentError, xattr.getxattr, dname,
215 _, sname = self._getsymlink()
216 lists_equal(xattr.listxattr(sname, True), [])
217 tuples_equal(xattr.get_all(sname, nofollow=True), [])
218 self.assertRaises(EnvironmentError, xattr.getxattr, fname,
222 def testNoXattr(self):
223 """test no attributes"""
224 fh, fname = self._getfile()
225 lists_equal(xattr.list(fname), [])
226 self.assertEqual(xattr.list(fname, namespace=NAMESPACE), [])
227 tuples_equal(xattr.get_all(fname), [])
228 self.assertEqual(xattr.get_all(fname, namespace=NAMESPACE), [])
229 self.assertRaises(EnvironmentError, xattr.get, fname,
230 USER_NN, namespace=NAMESPACE)
231 dname = self._getdir()
232 lists_equal(xattr.list(dname), [])
233 self.assertEqual(xattr.list(dname, namespace=NAMESPACE), [])
234 tuples_equal(xattr.get_all(dname), [])
235 self.assertEqual(xattr.get_all(dname, namespace=NAMESPACE), [])
236 self.assertRaises(EnvironmentError, xattr.get, dname,
237 USER_NN, namespace=NAMESPACE)
238 _, sname = self._getsymlink()
239 lists_equal(xattr.list(sname, nofollow=True), [])
240 self.assertEqual(xattr.list(sname, nofollow=True,
241 namespace=NAMESPACE), [])
242 tuples_equal(xattr.get_all(sname, nofollow=True), [])
243 self.assertEqual(xattr.get_all(sname, nofollow=True,
244 namespace=NAMESPACE), [])
245 self.assertRaises(EnvironmentError, xattr.get, sname,
246 USER_NN, namespace=NAMESPACE, nofollow=True)
248 def testFileByNameDeprecated(self):
249 """test set and retrieve one attribute by file name (deprecated)"""
250 fh, fname = self._getfile()
251 self._checkDeprecated(fname)
254 def testFileByName(self):
255 """test set and retrieve one attribute by file name"""
256 fh, fname = self._getfile()
257 self._checkListSetGet(fname)
258 self._checkListSetGet(fname, use_ns=True)
261 def testFileByDescriptorDeprecated(self):
262 """test file descriptor operations (deprecated functions)"""
263 fh, fname = self._getfile()
264 self._checkDeprecated(fh)
267 def testFileByDescriptor(self):
268 """test file descriptor operations"""
269 fh, fname = self._getfile()
270 self._checkListSetGet(fh)
271 self._checkListSetGet(fh, use_ns=True)
274 def testFileByObjectDeprecated(self):
275 """test file descriptor operations (deprecated functions)"""
276 fh, fname = self._getfile()
278 self._checkDeprecated(fo)
281 def testFileByObject(self):
282 """test file descriptor operations"""
283 fh, fname = self._getfile()
285 self._checkListSetGet(fo)
286 self._checkListSetGet(fo, use_ns=True)
289 def testMixedAccessDeprecated(self):
290 """test mixed access to file (deprecated functions)"""
291 fh, fname = self._getfile()
293 lists_equal(xattr.listxattr(fname), [])
294 xattr.setxattr(fname, USER_ATTR, USER_VAL)
295 lists_equal(xattr.listxattr(fh), [USER_ATTR])
296 self.assertEqual(xattr.getxattr(fo, USER_ATTR), USER_VAL)
297 tuples_equal(xattr.get_all(fo), [(USER_ATTR, USER_VAL)])
298 tuples_equal(xattr.get_all(fname),
299 [(USER_ATTR, USER_VAL)])
302 def testMixedAccess(self):
303 """test mixed access to file"""
304 fh, fname = self._getfile()
306 lists_equal(xattr.list(fname), [])
307 xattr.set(fname, USER_ATTR, USER_VAL)
308 lists_equal(xattr.list(fh), [USER_ATTR])
309 self.assertEqual(xattr.list(fh, namespace=NAMESPACE), [USER_NN])
310 self.assertEqual(xattr.get(fo, USER_ATTR), USER_VAL)
311 self.assertEqual(xattr.get(fo, USER_NN, namespace=NAMESPACE),
313 tuples_equal(xattr.get_all(fo),
314 [(USER_ATTR, USER_VAL)])
315 self.assertEqual(xattr.get_all(fo, namespace=NAMESPACE),
316 [(USER_NN, USER_VAL)])
317 tuples_equal(xattr.get_all(fname),
318 [(USER_ATTR, USER_VAL)])
319 self.assertEqual(xattr.get_all(fname, namespace=NAMESPACE),
320 [(USER_NN, USER_VAL)])
323 def testDirOpsDeprecated(self):
324 """test attribute setting on directories (deprecated functions)"""
325 dname = self._getdir()
326 self._checkDeprecated(dname)
328 def testDirOps(self):
329 """test attribute setting on directories"""
330 dname = self._getdir()
331 self._checkListSetGet(dname)
332 self._checkListSetGet(dname, use_ns=True)
334 def testSymlinkOpsDeprecated(self):
335 """test symlink operations (deprecated functions)"""
336 _, sname = self._getsymlink()
337 self.assertRaises(EnvironmentError, xattr.listxattr, sname)
338 self._checkDeprecated(sname, symlink=True)
339 target, sname = self._getsymlink(dangling=False)
340 xattr.setxattr(target, USER_ATTR, USER_VAL)
341 lists_equal(xattr.listxattr(target), [USER_ATTR])
342 lists_equal(xattr.listxattr(sname, True), [])
343 self.assertRaises(EnvironmentError, xattr.removexattr, sname,
345 xattr.removexattr(sname, USER_ATTR, False)
347 def testSymlinkOps(self):
348 """test symlink operations"""
349 _, sname = self._getsymlink()
350 self.assertRaises(EnvironmentError, xattr.list, sname)
351 self._checkListSetGet(sname, symlink=True)
352 self._checkListSetGet(sname, symlink=True, use_ns=True)
353 target, sname = self._getsymlink(dangling=False)
354 xattr.set(target, USER_ATTR, USER_VAL)
355 lists_equal(xattr.list(target), [USER_ATTR])
356 lists_equal(xattr.list(sname, nofollow=True), [])
357 self.assertRaises(EnvironmentError, xattr.remove, sname,
358 USER_ATTR, nofollow=True)
359 xattr.remove(sname, USER_ATTR, nofollow=False)
361 def testBinaryPayloadDeprecated(self):
362 """test binary values (deprecated functions)"""
363 fh, fname = self._getfile()
365 BINVAL = "abc" + '\0' + "def"
367 BINVAL = BINVAL.encode()
368 xattr.setxattr(fname, USER_ATTR, BINVAL)
369 lists_equal(xattr.listxattr(fname), [USER_ATTR])
370 self.assertEqual(xattr.getxattr(fname, USER_ATTR), BINVAL)
371 tuples_equal(xattr.get_all(fname), [(USER_ATTR, BINVAL)])
372 xattr.removexattr(fname, USER_ATTR)
374 def testBinaryPayload(self):
375 """test binary values"""
376 fh, fname = self._getfile()
378 BINVAL = "abc" + '\0' + "def"
380 BINVAL = BINVAL.encode()
381 xattr.set(fname, USER_ATTR, BINVAL)
382 lists_equal(xattr.list(fname), [USER_ATTR])
383 self.assertEqual(xattr.list(fname, namespace=NAMESPACE), [USER_NN])
384 self.assertEqual(xattr.get(fname, USER_ATTR), BINVAL)
385 self.assertEqual(xattr.get(fname, USER_NN,
386 namespace=NAMESPACE), BINVAL)
387 tuples_equal(xattr.get_all(fname), [(USER_ATTR, BINVAL)])
388 self.assertEqual(xattr.get_all(fname, namespace=NAMESPACE),
390 xattr.remove(fname, USER_ATTR)
392 def testManyOpsDeprecated(self):
393 """test many ops (deprecated functions)"""
394 fh, fname = self._getfile()
395 xattr.setxattr(fh, USER_ATTR, USER_VAL)
397 for i in range(MANYOPS_COUNT):
398 lists_equal(xattr.listxattr(fh), VL)
399 for i in range(MANYOPS_COUNT):
400 self.assertEqual(xattr.getxattr(fh, USER_ATTR), USER_VAL)
401 for i in range(MANYOPS_COUNT):
402 tuples_equal(xattr.get_all(fh),
403 [(USER_ATTR, USER_VAL)])
405 def testManyOps(self):
407 fh, fname = self._getfile()
408 xattr.set(fh, USER_ATTR, USER_VAL)
411 for i in range(MANYOPS_COUNT):
412 lists_equal(xattr.list(fh), VL)
413 lists_equal(xattr.list(fh, namespace=EMPTY_NS), VL)
414 self.assertEqual(xattr.list(fh, namespace=NAMESPACE), VN)
415 for i in range(MANYOPS_COUNT):
416 self.assertEqual(xattr.get(fh, USER_ATTR), USER_VAL)
417 self.assertEqual(xattr.get(fh, USER_NN, namespace=NAMESPACE),
419 for i in range(MANYOPS_COUNT):
420 tuples_equal(xattr.get_all(fh),
421 [(USER_ATTR, USER_VAL)])
422 self.assertEqual(xattr.get_all(fh, namespace=NAMESPACE),
423 [(USER_NN, USER_VAL)])
425 def testNoneNamespace(self):
426 fh, fname = self._getfile()
427 self.assertRaises(TypeError, xattr.get, fh, USER_ATTR,
430 def testEmptyValue(self):
431 fh, fname = self._getfile()
432 xattr.set(fh, USER_ATTR, EMPTY_VAL)
433 self.assertEqual(xattr.get(fh, USER_ATTR), EMPTY_VAL)
435 def testWrongCall(self):
436 for call in [xattr.get,
437 xattr.list, xattr.listxattr,
438 xattr.remove, xattr.removexattr,
439 xattr.set, xattr.setxattr,
440 xattr.get, xattr.getxattr]:
441 self.assertRaises(TypeError, call)
443 def testWrongType(self):
444 self.assertRaises(TypeError, xattr.get, object(), USER_ATTR)
445 for call in [xattr.listxattr, xattr.list]:
446 self.assertRaises(TypeError, call, object())
447 for call in [xattr.remove, xattr.removexattr,
448 xattr.get, xattr.getxattr]:
449 self.assertRaises(TypeError, call, object(), USER_ATTR)
450 for call in [xattr.set, xattr.setxattr]:
451 self.assertRaises(TypeError, call, object(), USER_ATTR, USER_VAL)
454 def testLargeAttribute(self):
455 fh, fname = self._getfile()
457 xattr.set(fh, USER_ATTR, LARGE_VAL)
458 self.assertEqual(xattr.get(fh, USER_ATTR), LARGE_VAL)
461 if __name__ == "__main__":