unittests: abstract basic acl text into a constant
[pylibacl.git] / test / test_acls.py
1 #
2 #
3
4 import unittest
5 import os
6 import tempfile
7
8 import posix1e
9
10 TEST_DIR=os.environ.get("TESTDIR", ".")
11
12 BASIC_ACL_TEXT="u::rw,g::r,o::-"
13
14 def has_from_mode(fn):
15     """Decorator to skip tests based on platform support"""
16     if not posix1e.HAS_ACL_FROM_MODE:
17         new_fn = lambda x: None
18         new_fn.__doc__ = "SKIPPED %s" % fn.__doc__
19         fn = new_fn
20     return fn
21
22
23 def has_acl_entry(fn):
24     """Decorator to skip tests based on platform support"""
25     if not posix1e.HAS_ACL_ENTRY:
26         new_fn = lambda x: None
27         new_fn.__doc__ = "SKIPPED %s" % fn.__doc__
28         fn = new_fn
29     return fn
30
31
32 def has_acl_check(fn):
33     """Decorator to skip tests based on platform support"""
34     if not posix1e.HAS_ACL_CHECK:
35         new_fn = lambda x: None
36         new_fn.__doc__ = "SKIPPED %s" % fn.__doc__
37         fn = new_fn
38     return fn
39
40
41 class aclTest:
42     """Support functions ACLs"""
43
44     def setUp(self):
45         """set up function"""
46         self.rmfiles = []
47         self.rmdirs = []
48
49     def tearDown(self):
50         """tear down function"""
51         for fname in self.rmfiles:
52             os.unlink(fname)
53         for dname in self.rmdirs:
54             os.rmdir(dname)
55
56     def _getfile(self):
57         """create a temp file"""
58         fh, fname = tempfile.mkstemp(".test", "xattr-", TEST_DIR)
59         self.rmfiles.append(fname)
60         return fh, fname
61
62     def _getdir(self):
63         """create a temp dir"""
64         dname = tempfile.mkdtemp(".test", "xattr-", TEST_DIR)
65         self.rmdirs.append(dname)
66         return dname
67
68     def _getsymlink(self):
69         """create a symlink"""
70         fh, fname = self._getfile()
71         os.close(fh)
72         os.unlink(fname)
73         os.symlink(fname + ".non-existent", fname)
74         return fname
75
76
77 class LoadTests(aclTest, unittest.TestCase):
78     """Load/create tests"""
79     def testFromFile(self):
80         """Test loading ACLs from a file"""
81         _, fname = self._getfile()
82         acl1 = posix1e.ACL(file=fname)
83         self.failUnless(acl1.valid(), "ACL read from file should be valid")
84
85     def testFromDir(self):
86         """Test loading ACLs from a directory"""
87         dname = self._getdir()
88         acl1 = posix1e.ACL(file=dname)
89         acl2 = posix1e.ACL(filedef=dname)
90         self.failUnless(acl1.valid(),
91                         "ACL read from directory should be valid")
92         # default ACLs might or might not be valid; missing ones are
93         # not valid, so we don't test acl2 for validity
94
95     def testFromFd(self):
96         """Test loading ACLs from a file descriptor"""
97         fd, _ = self._getfile()
98         acl1 = posix1e.ACL(fd=fd)
99         self.failUnless(acl1.valid(), "ACL read from fd should be valid")
100
101     def testFromEmpty(self):
102         """Test creating an empty ACL"""
103         acl1 = posix1e.ACL()
104         self.failIf(acl1.valid(), "Empty ACL should not be valid")
105
106     def testFromText(self):
107         """Test creating an ACL from text"""
108         acl1 = posix1e.ACL(text=BASIC_ACL_TEXT)
109         self.failUnless(acl1.valid(),
110                         "ACL based on standard description should be valid")
111
112 class AclExtensions(aclTest, unittest.TestCase):
113     """ACL extensions checks"""
114
115     @has_from_mode
116     def testFromMode(self):
117         """Test loading ACLs from an octal mode"""
118         acl1 = posix1e.ACL(mode=0644)
119         self.failUnless(acl1.valid(),
120                         "ACL created via octal mode shoule be valid")
121
122     @has_acl_check
123     def testAclCheck(self):
124         """Test the acl_check method"""
125         acl1 = posix1e.ACL(text=BASIC_ACL_TEXT)
126         self.failIf(acl1.check(), "ACL is not valid")
127         acl2 = posix1e.ACL()
128         self.failUnless(acl2.check(), "Empty ACL should not be valid")
129
130
131 class WriteTests(aclTest, unittest.TestCase):
132     """Write tests"""
133
134     def testDeleteDefault(self):
135         """Test removing the default ACL"""
136         dname = self._getdir()
137         posix1e.delete_default(dname)
138
139     def testReapply(self):
140         """Test re-applying an ACL"""
141         fd, fname = self._getfile()
142         acl1 = posix1e.ACL(fd=fd)
143         acl1.applyto(fd)
144         acl1.applyto(fname)
145         dname = self._getdir()
146         acl2 = posix1e.ACL(file=fname)
147         acl2.applyto(dname)
148
149
150 class ModificationTests(aclTest, unittest.TestCase):
151     """ACL modification tests"""
152
153     @has_acl_entry
154     def testAppend(self):
155         """Test append a new Entry to the ACL"""
156         acl = posix1e.ACL()
157         e = acl.append()
158         e.tag_type = posix1e.ACL_OTHER
159         acl.calc_mask()
160
161     @has_acl_entry
162     def testDelete(self):
163         """Test delete Entry from the ACL"""
164         acl = posix1e.ACL()
165         e = acl.append()
166         e.tag_type = posix1e.ACL_OTHER
167         acl.calc_mask()
168         acl.delete_entry(e)
169         acl.calc_mask()
170
171     @has_acl_entry
172     def testDoubleEntries(self):
173         """Test double entries"""
174         acl = posix1e.ACL(text=BASIC_ACL_TEXT)
175         self.failUnless(acl.valid(), "ACL is not valid")
176         for tag_type in (posix1e.ACL_USER_OBJ, posix1e.ACL_GROUP_OBJ,
177                          posix1e.ACL_OTHER):
178             e = acl.append()
179             e.tag_type = tag_type
180             e.permset.clear()
181             self.failIf(acl.valid(),
182                         "ACL containing duplicate entries should not be valid")
183             acl.delete_entry(e)
184
185     @has_acl_entry
186     def testMultipleGoodEntries(self):
187         """Test multiple valid entries"""
188         acl = posix1e.ACL(text=BASIC_ACL_TEXT)
189         self.failUnless(acl.valid(), "ACL is not valid")
190         for tag_type in (posix1e.ACL_USER,
191                          posix1e.ACL_GROUP):
192             for obj_id in range(5):
193                 e = acl.append()
194                 e.tag_type = tag_type
195                 e.qualifier = obj_id
196                 e.permset.clear()
197                 acl.calc_mask()
198                 self.failUnless(acl.valid(),
199                                "ACL should be able to hold multiple"
200                                 " user/group entries")
201     @has_acl_entry
202     def testMultipleBadEntries(self):
203         """Test multiple invalid entries"""
204         acl = posix1e.ACL(text=BASIC_ACL_TEXT)
205         self.failUnless(acl.valid(), "ACL built from standard description"
206                         " should be valid")
207         for tag_type in (posix1e.ACL_USER,
208                          posix1e.ACL_GROUP):
209             e1 = acl.append()
210             e1.tag_type = tag_type
211             e1.qualifier = 0
212             e1.permset.clear()
213             acl.calc_mask()
214             self.failUnless(acl.valid(), "ACL should be able to add a"
215                             " user/group entry")
216             e2 = acl.append()
217             e2.tag_type = tag_type
218             e2.qualifier = 0
219             e2.permset.clear()
220             acl.calc_mask()
221             self.failIf(acl.valid(), "ACL should not validate when"
222                         " containing two duplicate entries")
223             acl.delete_entry(e1)
224             acl.delete_entry(e2)
225
226     @has_acl_entry
227     def testPermset(self):
228         """Test permissions"""
229         acl = posix1e.ACL()
230         e = acl.append()
231         ps = e.permset
232         ps.clear()
233         pmap = {
234             posix1e.ACL_READ: "read",
235             posix1e.ACL_WRITE: "write",
236             posix1e.ACL_EXECUTE: "execute",
237             }
238         for perm in pmap:
239             self.failIf(ps.test(perm), "Empty permission set should not"
240                         " have permission '%s'" % pmap[perm])
241             ps.add(perm)
242             self.failUnless(ps.test(perm), "Permission '%s' should exist"
243                         " after addition" % pmap[perm])
244             ps.delete(perm)
245             self.failIf(ps.test(perm), "Permission '%s' should not exist"
246                         " after deletion" % pmap[perm])
247
248
249 if __name__ == "__main__":
250     unittest.main()