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
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()
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]
54 """Remove ignored attributes from the output of xattr.list"""
55 return [attr for attr in attrs
56 if attr not in TEST_IGNORE_XATTRS]
58 def lists_equal(attrs, value):
59 """Helper to check list equivalence, skipping TEST_IGNORE_XATTRS."""
60 assert ignore(attrs) == value
62 def tuples_equal(attrs, value):
63 """Helper to check list equivalence, skipping TEST_IGNORE_XATTRS."""
64 assert ignore_tuples(attrs) == value
66 # Fixtures and helpers
70 """per-test temp dir based in TEST_DIR"""
71 with tempfile.TemporaryDirectory(dir=TEST_DIR) as dname:
75 fh, fname = tempfile.mkstemp(".test", "xattr-", path)
78 def get_file_name(path):
79 fh, fname = get_file(path)
83 def get_file_fd(path):
84 return get_file(path)[0]
86 def get_file_object(path):
87 fd = get_file(path)[0]
91 return tempfile.mkdtemp(".test", "xattr-", path)
93 def get_symlink(path, dangling=True):
94 """create a symlink"""
95 fh, fname = get_file(path)
99 sname = fname + ".symlink"
100 os.symlink(fname, sname)
103 def get_valid_symlink(path):
104 return get_symlink(path, dangling=False)[1]
106 def get_dangling_symlink(path):
107 return get_symlink(path, dangling=True)[1]
109 # Note: user attributes are only allowed on files and directories, so
110 # we have to skip the symlinks here. See xattr(7).
112 (get_file_name, False),
113 (get_file_fd, False),
114 (get_file_object, False),
116 (get_valid_symlink, False),
117 # (get_valid_symlink, True),
118 # (get_dangling_symlink, True),
128 # "dangling symlink",
131 @pytest.fixture(params=ITEMS_P, ids=ITEMS_D)
132 def subject(testdir, request):
133 return request.param[0](testdir), request.param[1]
135 @pytest.fixture(params=[True, False], ids=["with namespace", "no namespace"])
139 @pytest.fixture(params=[True, False], ids=["dangling", "valid"])
140 def use_dangling(request):
145 def test_empty_value(subject):
146 item, nofollow = subject
147 xattr.set(item, USER_ATTR, EMPTY_VAL, nofollow=nofollow)
148 assert xattr.get(item, USER_ATTR, nofollow=nofollow) == EMPTY_VAL
150 def test_large_value(subject):
151 item, nofollow = subject
152 xattr.set(item, USER_ATTR, LARGE_VAL)
153 assert xattr.get(item, USER_ATTR, nofollow=nofollow) == LARGE_VAL
156 def test_file_mixed_access_deprecated(testdir):
157 """test mixed access to file (deprecated functions)"""
158 fh, fname = get_file(testdir)
159 with os.fdopen(fh) as fo:
160 lists_equal(xattr.listxattr(fname), [])
161 xattr.setxattr(fname, USER_ATTR, USER_VAL)
162 lists_equal(xattr.listxattr(fh), [USER_ATTR])
163 assert xattr.getxattr(fo, USER_ATTR) == USER_VAL
164 tuples_equal(xattr.get_all(fo), [(USER_ATTR, USER_VAL)])
165 tuples_equal(xattr.get_all(fname),
166 [(USER_ATTR, USER_VAL)])
168 def test_file_mixed_access(testdir):
169 """test mixed access to file"""
170 fh, fname = get_file(testdir)
171 with os.fdopen(fh) as fo:
172 lists_equal(xattr.list(fname), [])
173 xattr.set(fname, USER_ATTR, USER_VAL)
174 lists_equal(xattr.list(fh), [USER_ATTR])
175 assert xattr.list(fh, namespace=NAMESPACE) == [USER_NN]
176 assert xattr.get(fo, USER_ATTR) == USER_VAL
177 assert xattr.get(fo, USER_NN, namespace=NAMESPACE) == USER_VAL
178 tuples_equal(xattr.get_all(fo),
179 [(USER_ATTR, USER_VAL)])
180 assert xattr.get_all(fo, namespace=NAMESPACE) == \
181 [(USER_NN, USER_VAL)]
182 tuples_equal(xattr.get_all(fname), [(USER_ATTR, USER_VAL)])
183 assert xattr.get_all(fname, namespace=NAMESPACE) == \
184 [(USER_NN, USER_VAL)]
186 def test_ListSetGet(subject, use_ns):
187 """check list, set, get operations against an item"""
189 lists_equal(xattr.list(item), [])
190 with pytest.raises(EnvironmentError):
192 xattr.set(item, USER_NN, USER_VAL, flags=XATTR_REPLACE,
195 xattr.set(item, USER_ATTR, USER_VAL, flags=XATTR_REPLACE)
197 xattr.set(item, USER_NN, USER_VAL,
200 xattr.set(item, USER_ATTR, USER_VAL)
201 with pytest.raises(EnvironmentError):
203 xattr.set(item, USER_NN, USER_VAL,
204 flags=XATTR_CREATE, namespace=NAMESPACE)
206 xattr.set(item, USER_ATTR, USER_VAL, flags=XATTR_CREATE)
208 assert xattr.list(item, namespace=NAMESPACE) == [USER_NN]
210 lists_equal(xattr.list(item), [USER_ATTR])
211 lists_equal(xattr.list(item, namespace=EMPTY_NS),
214 assert xattr.get(item, USER_NN, namespace=NAMESPACE) == USER_VAL
216 assert xattr.get(item, USER_ATTR) == USER_VAL
218 assert xattr.get_all(item, namespace=NAMESPACE) == \
219 [(USER_NN, USER_VAL)]
221 tuples_equal(xattr.get_all(item),
222 [(USER_ATTR, USER_VAL)])
224 xattr.remove(item, USER_NN, namespace=NAMESPACE)
226 xattr.remove(item, USER_ATTR)
227 lists_equal(xattr.list(item), [])
228 tuples_equal(xattr.get_all(item), [])
229 with pytest.raises(EnvironmentError):
231 xattr.remove(item, USER_NN, namespace=NAMESPACE)
233 xattr.remove(item, USER_ATTR)
235 def test_ListSetGetDeprecated(subject):
236 """check deprecated list, set, get operations against an item"""
238 lists_equal(xattr.listxattr(item), [])
239 with pytest.raises(EnvironmentError):
240 xattr.setxattr(item, USER_ATTR, USER_VAL, XATTR_REPLACE)
241 xattr.setxattr(item, USER_ATTR, USER_VAL, 0)
242 with pytest.raises(EnvironmentError):
243 xattr.setxattr(item, USER_ATTR, USER_VAL, XATTR_CREATE)
244 lists_equal(xattr.listxattr(item), [USER_ATTR])
245 assert xattr.getxattr(item, USER_ATTR) == USER_VAL
246 tuples_equal(xattr.get_all(item), [(USER_ATTR, USER_VAL)])
247 xattr.removexattr(item, USER_ATTR)
248 lists_equal(xattr.listxattr(item), [])
249 tuples_equal(xattr.get_all(item), [])
250 with pytest.raises(EnvironmentError):
251 xattr.removexattr(item, USER_ATTR)
253 def test_many_ops(subject):
256 xattr.set(item, USER_ATTR, USER_VAL)
259 for i in range(MANYOPS_COUNT):
260 lists_equal(xattr.list(item), VL)
261 lists_equal(xattr.list(item, namespace=EMPTY_NS), VL)
262 assert xattr.list(item, namespace=NAMESPACE) == VN
263 for i in range(MANYOPS_COUNT):
264 assert xattr.get(item, USER_ATTR) == USER_VAL
265 assert xattr.get(item, USER_NN, namespace=NAMESPACE) == USER_VAL
266 for i in range(MANYOPS_COUNT):
267 tuples_equal(xattr.get_all(item),
268 [(USER_ATTR, USER_VAL)])
269 assert xattr.get_all(item, namespace=NAMESPACE) == \
270 [(USER_NN, USER_VAL)]
272 def test_many_ops_deprecated(subject):
273 """test many ops (deprecated functions)"""
275 xattr.setxattr(item, USER_ATTR, USER_VAL)
277 for i in range(MANYOPS_COUNT):
278 lists_equal(xattr.listxattr(item), VL)
279 for i in range(MANYOPS_COUNT):
280 assert xattr.getxattr(item, USER_ATTR) == USER_VAL
281 for i in range(MANYOPS_COUNT):
282 tuples_equal(xattr.get_all(item),
283 [(USER_ATTR, USER_VAL)])
285 def test_no_attributes_deprecated(subject):
286 """test no attributes (deprecated functions)"""
288 lists_equal(xattr.listxattr(item), [])
289 tuples_equal(xattr.get_all(item), [])
290 with pytest.raises(EnvironmentError):
291 xattr.getxattr(item, USER_ATTR)
293 def test_no_attributes_deprecated_symlinks(testdir, use_dangling):
294 """test no attributes on symlinks (deprecated functions)"""
295 _, sname = get_symlink(testdir, dangling=use_dangling)
296 lists_equal(xattr.listxattr(sname, True), [])
297 tuples_equal(xattr.get_all(sname, nofollow=True), [])
298 with pytest.raises(EnvironmentError):
299 xattr.getxattr(sname, USER_ATTR, True)
301 def test_no_attributes(subject):
302 """test no attributes"""
304 lists_equal(xattr.list(item), [])
305 assert xattr.list(item, namespace=NAMESPACE) == []
306 tuples_equal(xattr.get_all(item), [])
307 assert xattr.get_all(item, namespace=NAMESPACE) == []
308 with pytest.raises(EnvironmentError):
309 xattr.get(item, USER_NN, namespace=NAMESPACE)
311 def test_no_attributes_symlinks(testdir, use_dangling):
312 """test no attributes on symlinks"""
313 _, sname = get_symlink(testdir, dangling=use_dangling)
314 lists_equal(xattr.list(sname, nofollow=True), [])
315 assert xattr.list(sname, nofollow=True,
316 namespace=NAMESPACE) == []
317 tuples_equal(xattr.get_all(sname, nofollow=True), [])
318 assert xattr.get_all(sname, nofollow=True,
319 namespace=NAMESPACE) == []
320 with pytest.raises(EnvironmentError):
321 xattr.get(sname, USER_NN, namespace=NAMESPACE, nofollow=True)
323 def test_binary_payload_deprecated(subject):
324 """test binary values (deprecated functions)"""
327 xattr.setxattr(item, USER_ATTR, BINVAL)
328 lists_equal(xattr.listxattr(item), [USER_ATTR])
329 assert xattr.getxattr(item, USER_ATTR) == BINVAL
330 tuples_equal(xattr.get_all(item), [(USER_ATTR, BINVAL)])
331 xattr.removexattr(item, USER_ATTR)
333 def test_binary_payload(subject):
334 """test binary values"""
337 xattr.set(item, USER_ATTR, BINVAL)
338 lists_equal(xattr.list(item), [USER_ATTR])
339 assert xattr.list(item, namespace=NAMESPACE) == [USER_NN]
340 assert xattr.get(item, USER_ATTR) == BINVAL
341 assert xattr.get(item, USER_NN, namespace=NAMESPACE) == BINVAL
342 tuples_equal(xattr.get_all(item), [(USER_ATTR, BINVAL)])
343 assert xattr.get_all(item, namespace=NAMESPACE) == [(USER_NN, BINVAL)]
344 xattr.remove(item, USER_ATTR)
346 def test_none_namespace(subject):
347 with pytest.raises(TypeError):
348 xattr.get(subject[0], USER_ATTR, namespace=None)
350 @pytest.mark.parametrize(
352 [xattr.get, xattr.list, xattr.listxattr,
353 xattr.remove, xattr.removexattr,
354 xattr.set, xattr.setxattr,
355 xattr.get, xattr.getxattr])
356 def test_wrong_call(call):
357 with pytest.raises(TypeError):
360 @pytest.mark.parametrize(
361 "call, args", [(xattr.get, [USER_ATTR]),
362 (xattr.listxattr, []),
364 (xattr.remove, [USER_ATTR]),
365 (xattr.removexattr, [USER_ATTR]),
366 (xattr.get, [USER_ATTR]),
367 (xattr.getxattr, [USER_ATTR]),
368 (xattr.set, [USER_ATTR, USER_VAL]),
369 (xattr.setxattr, [USER_ATTR, USER_VAL])])
370 def test_wrong_argument_type(call, args):
371 with pytest.raises(TypeError):
372 call(object(), *args)