7153636f47371f879574bde51c4a355e14f5af53
[rrq/fuse_xattrs.git] / test / tests.py
1 #!/usr/bin/env python3
2
3
4 # fuse_xattrs - Add xattrs support using sidecar files
5 #
6 # Copyright (C) 2016  Felipe Barriga Richards <felipe {at} felipebarriga.cl>
7 #
8 # This program can be distributed under the terms of the GNU GPL.
9 # See the file COPYING.
10
11
12 import unittest
13 import xattr
14 from pathlib import Path
15 import os
16
17 # TODO
18 # - listxattr: list too long
19 # - sidecar file permissions
20
21
22 class TestXAttrs(unittest.TestCase):
23     def setUp(self):
24         self.randomFile = "./mount/tmp/foo.txt"
25         self.randomFileSidecar = "./mount/tmp/foo.txt.xattr"
26         if os.path.isfile(self.randomFile):
27             os.remove(self.randomFile)
28         Path(self.randomFile).touch()
29
30         if os.path.isfile(self.randomFileSidecar):
31             os.remove(self.randomFileSidecar)
32
33     def tearDown(self):
34         os.remove(self.randomFile)
35
36     def test_xattr_set(self):
37         xattr.setxattr(self.randomFile, "user.foo", bytes("bar", "utf-8"))
38
39     def test_xattr_set_name_max_length(self):
40         enc = "utf-8"
41         key = "user." + "x" * 250
42         value = "x"
43         self.assertEqual(len(key), 255)
44         xattr.setxattr(self.randomFile, key, bytes(value, enc))
45
46         key = "user." + "x" * 251
47         self.assertEqual(len(key), 256)
48         with self.assertRaises(OSError) as ex:
49             xattr.setxattr(self.randomFile, key, bytes(value, enc))
50         self.assertEqual(ex.exception.errno, 34)
51         self.assertEqual(ex.exception.strerror, "Numerical result out of range")
52
53     @unittest.expectedFailure
54     def test_xattr_set_value_max_size(self):
55         enc = "utf-8"
56         key = "user.foo"
57         value = "x" * (64 * 1024 + 1)  # we want max 64KiB of data
58         with self.assertRaises(OSError) as ex:
59             xattr.setxattr(self.randomFile, key, bytes(value, enc))
60
61         # on btrfs we get "no space left on device"
62         self.assertEqual(ex.exception.errno, 28)
63         self.assertEqual(ex.exception.strerror, "No space left on device")
64
65         # on fuse_xattr we get "Argument list too long"
66         # the error is thrown by fuse, not by fuse_xattr code
67
68     def test_xattr_set_namespaces(self):
69         with self.assertRaises(OSError) as ex:
70             xattr.setxattr(self.randomFile, "system.foo", bytes("bar", "utf-8"))
71         self.assertEqual(ex.exception.errno, 95)
72         self.assertEqual(ex.exception.strerror, "Operation not supported")
73
74         with self.assertRaises(OSError) as ex:
75             xattr.setxattr(self.randomFile, "trust.foo", bytes("bar", "utf-8"))
76         self.assertEqual(ex.exception.errno, 95)
77         self.assertEqual(ex.exception.strerror, "Operation not supported")
78
79         with self.assertRaises(OSError) as ex:
80             xattr.setxattr(self.randomFile, "foo.foo", bytes("bar", "utf-8"))
81         self.assertEqual(ex.exception.errno, 95)
82         self.assertEqual(ex.exception.strerror, "Operation not supported")
83
84         with self.assertRaises(PermissionError) as ex:
85             xattr.setxattr(self.randomFile, "security.foo", bytes("bar", "utf-8"))
86         self.assertEqual(ex.exception.errno, 1)
87         self.assertEqual(ex.exception.strerror, "Operation not permitted")
88
89     def test_xattr_get_non_existent(self):
90         key = "user.foo"
91         with self.assertRaises(OSError) as ex:
92             xattr.getxattr(self.randomFile, key)
93         self.assertEqual(ex.exception.errno, 61)
94         self.assertEqual(ex.exception.strerror, "No data available")
95
96     def test_xattr_get(self):
97         enc = "utf-8"
98         key = "user.foo"
99         value = "bar"
100         xattr.setxattr(self.randomFile, key, bytes(value, enc))
101         read_value = xattr.getxattr(self.randomFile, key)
102         self.assertEqual(value, read_value.decode(enc))
103
104     def test_xattr_set_override(self):
105         enc = "utf-8"
106         key = "user.foo"
107         value1 = "bar"
108         value2 = "rab"
109         xattr.setxattr(self.randomFile, key, bytes(value1, enc))
110         xattr.setxattr(self.randomFile, key, bytes(value2, enc))
111         read_value = xattr.getxattr(self.randomFile, key)
112         self.assertEqual(value2, read_value.decode(enc))
113
114     def test_xattr_set_create(self):
115         enc = "utf-8"
116         key = "user.foo"
117         value1 = "bar"
118         value2 = "rab"
119         xattr.setxattr(self.randomFile, key, bytes(value1, enc), xattr.XATTR_CREATE)
120         with self.assertRaises(FileExistsError) as ex:
121             xattr.setxattr(self.randomFile, key, bytes(value2, enc), xattr.XATTR_CREATE)
122         self.assertEqual(ex.exception.errno, 17)
123         self.assertEqual(ex.exception.strerror, "File exists")
124
125         read_value = xattr.getxattr(self.randomFile, key)
126         self.assertEqual(value1, read_value.decode(enc))
127
128     def test_xattr_set_replace(self):
129         enc = "utf-8"
130         key = "user.foo"
131         value = "bar"
132         with self.assertRaises(OSError) as ex:
133             xattr.setxattr(self.randomFile, key, bytes(value, enc), xattr.XATTR_REPLACE)
134         self.assertEqual(ex.exception.errno, 61)
135         self.assertEqual(ex.exception.strerror, "No data available")
136
137         with self.assertRaises(OSError) as ex:
138             xattr.getxattr(self.randomFile, key)
139         self.assertEqual(ex.exception.errno, 61)
140         self.assertEqual(ex.exception.strerror, "No data available")
141
142     def test_xattr_list_empty(self):
143         attrs = xattr.listxattr(self.randomFile)
144         self.assertEqual(len(attrs), 0)
145
146     def test_xattr_list(self):
147         enc = "utf-8"
148         key1 = "user.foo"
149         key2 = "user.foo2"
150         key3 = "user.foo3"
151         value = "bar"
152
153         # set 3 keys
154         xattr.setxattr(self.randomFile, key1, bytes(value, enc))
155         xattr.setxattr(self.randomFile, key2, bytes(value, enc))
156         xattr.setxattr(self.randomFile, key3, bytes(value, enc))
157
158         # get and check the list
159         attrs = xattr.listxattr(self.randomFile)
160
161         self.assertEqual(len(attrs), 3)
162         self.assertTrue(key1 in attrs)
163         self.assertTrue(key2 in attrs)
164         self.assertTrue(key3 in attrs)
165
166     def test_xattr_unicode(self):
167         enc = "utf-8"
168         key = "user.fooシüßてЙĘ𝄠✠"
169         value = "bar"
170
171         # set
172         xattr.setxattr(self.randomFile, key, bytes(value, enc))
173
174         # list
175         attrs = xattr.listxattr(self.randomFile)
176         self.assertEqual(len(attrs), 1)
177         self.assertTrue(key in attrs)
178
179         # read
180         read_value = xattr.getxattr(self.randomFile, key)
181         self.assertEqual(value, read_value.decode(enc))
182
183         # remove
184         xattr.removexattr(self.randomFile, key)
185
186     def test_xattr_remove(self):
187         enc = "utf-8"
188         key = "user.foo"
189         value = "bar"
190
191         # set
192         xattr.setxattr(self.randomFile, key, bytes(value, enc))
193
194         # remove
195         xattr.removexattr(self.randomFile, key)
196
197         # list should be empty
198         attrs = xattr.listxattr(self.randomFile)
199         self.assertEqual(len(attrs), 0)
200
201         # should fail when trying to read it
202         with self.assertRaises(OSError) as ex:
203             xattr.getxattr(self.randomFile, key)
204         self.assertEqual(ex.exception.errno, 61)
205         self.assertEqual(ex.exception.strerror, "No data available")
206
207         # removing twice should fail
208         with self.assertRaises(OSError) as ex:
209             xattr.getxattr(self.randomFile, key)
210         self.assertEqual(ex.exception.errno, 61)
211         self.assertEqual(ex.exception.strerror, "No data available")
212
213
214 if __name__ == '__main__':
215     unittest.main()