1 #!/usr/bin/env python 2 """Unit test suite for the fs_config_genertor.py tool.""" 3 4 import tempfile 5 import textwrap 6 import unittest 7 8 from fs_config_generator import AID 9 from fs_config_generator import AIDHeaderParser 10 from fs_config_generator import FSConfigFileParser 11 from fs_config_generator import FSConfig 12 from fs_config_generator import Utils 13 14 15 # Disable protected access so we can test class internal 16 # methods. Also, disable invalid-name as some of the 17 # class method names are over length. 18 # pylint: disable=protected-access,invalid-name 19 class Tests(unittest.TestCase): 20 """Test class for unit tests""" 21 22 def test_is_overlap(self): 23 """Test overlap detection helper""" 24 25 self.assertTrue(AIDHeaderParser._is_overlap((0, 1), (1, 2))) 26 27 self.assertTrue(AIDHeaderParser._is_overlap((0, 100), (90, 200))) 28 29 self.assertTrue(AIDHeaderParser._is_overlap((20, 50), (1, 101))) 30 31 self.assertFalse(AIDHeaderParser._is_overlap((0, 100), (101, 200))) 32 33 self.assertFalse(AIDHeaderParser._is_overlap((-10, 0), (10, 20))) 34 35 def test_in_any_range(self): 36 """Test if value in range""" 37 38 self.assertFalse(Utils.in_any_range(50, [(100, 200), (1, 2), (1, 1)])) 39 self.assertFalse(Utils.in_any_range(250, [(100, 200), (1, 2), (1, 1)])) 40 41 self.assertTrue(Utils.in_any_range(100, [(100, 200), (1, 2), (1, 1)])) 42 self.assertTrue(Utils.in_any_range(200, [(100, 200), (1, 2), (1, 1)])) 43 self.assertTrue(Utils.in_any_range(150, [(100, 200)])) 44 45 def test_aid(self): 46 """Test AID class constructor""" 47 48 aid = AID('AID_FOO_BAR', '0xFF', 'myfakefile') 49 self.assertEquals(aid.identifier, 'AID_FOO_BAR') 50 self.assertEquals(aid.value, '0xFF') 51 self.assertEquals(aid.found, 'myfakefile') 52 self.assertEquals(aid.normalized_value, '255') 53 self.assertEquals(aid.friendly, 'foo_bar') 54 55 aid = AID('AID_MEDIA_EX', '1234', 'myfakefile') 56 self.assertEquals(aid.identifier, 'AID_MEDIA_EX') 57 self.assertEquals(aid.value, '1234') 58 self.assertEquals(aid.found, 'myfakefile') 59 self.assertEquals(aid.normalized_value, '1234') 60 self.assertEquals(aid.friendly, 'mediaex') 61 62 def test_aid_header_parser_good(self): 63 """Test AID Header Parser good input file""" 64 65 with tempfile.NamedTemporaryFile() as temp_file: 66 temp_file.write( 67 textwrap.dedent(""" 68 #define AID_FOO 1000 69 #define AID_BAR 1001 70 #define SOMETHING "something" 71 #define AID_OEM_RESERVED_START 2900 72 #define AID_OEM_RESERVED_END 2999 73 #define AID_OEM_RESERVED_1_START 7000 74 #define AID_OEM_RESERVED_1_END 8000 75 """)) 76 temp_file.flush() 77 78 parser = AIDHeaderParser(temp_file.name) 79 oem_ranges = parser.oem_ranges 80 aids = parser.aids 81 82 self.assertTrue((2900, 2999) in oem_ranges) 83 self.assertFalse((5000, 6000) in oem_ranges) 84 85 for aid in aids: 86 self.assertTrue(aid.normalized_value in ['1000', '1001']) 87 self.assertFalse(aid.normalized_value in ['1', '2', '3']) 88 89 def test_aid_header_parser_good_unordered(self): 90 """Test AID Header Parser good unordered input file""" 91 92 with tempfile.NamedTemporaryFile() as temp_file: 93 temp_file.write( 94 textwrap.dedent(""" 95 #define AID_FOO 1000 96 #define AID_OEM_RESERVED_1_END 8000 97 #define AID_BAR 1001 98 #define SOMETHING "something" 99 #define AID_OEM_RESERVED_END 2999 100 #define AID_OEM_RESERVED_1_START 7000 101 #define AID_OEM_RESERVED_START 2900 102 """)) 103 temp_file.flush() 104 105 parser = AIDHeaderParser(temp_file.name) 106 oem_ranges = parser.oem_ranges 107 aids = parser.aids 108 109 self.assertTrue((2900, 2999) in oem_ranges) 110 self.assertFalse((5000, 6000) in oem_ranges) 111 112 for aid in aids: 113 self.assertTrue(aid.normalized_value in ['1000', '1001']) 114 self.assertFalse(aid.normalized_value in ['1', '2', '3']) 115 116 def test_aid_header_parser_bad_aid(self): 117 """Test AID Header Parser bad aid input file""" 118 119 with tempfile.NamedTemporaryFile() as temp_file: 120 temp_file.write( 121 textwrap.dedent(""" 122 #define AID_FOO "bad" 123 """)) 124 temp_file.flush() 125 126 with self.assertRaises(SystemExit): 127 AIDHeaderParser(temp_file.name) 128 129 def test_aid_header_parser_bad_oem_range(self): 130 """Test AID Header Parser bad oem range input file""" 131 132 with tempfile.NamedTemporaryFile() as temp_file: 133 temp_file.write( 134 textwrap.dedent(""" 135 #define AID_OEM_RESERVED_START 2900 136 #define AID_OEM_RESERVED_END 1800 137 """)) 138 temp_file.flush() 139 140 with self.assertRaises(SystemExit): 141 AIDHeaderParser(temp_file.name) 142 143 def test_aid_header_parser_bad_oem_range_no_end(self): 144 """Test AID Header Parser bad oem range (no end) input file""" 145 146 with tempfile.NamedTemporaryFile() as temp_file: 147 temp_file.write( 148 textwrap.dedent(""" 149 #define AID_OEM_RESERVED_START 2900 150 """)) 151 temp_file.flush() 152 153 with self.assertRaises(SystemExit): 154 AIDHeaderParser(temp_file.name) 155 156 def test_aid_header_parser_bad_oem_range_no_start(self): 157 """Test AID Header Parser bad oem range (no start) input file""" 158 159 with tempfile.NamedTemporaryFile() as temp_file: 160 temp_file.write( 161 textwrap.dedent(""" 162 #define AID_OEM_RESERVED_END 2900 163 """)) 164 temp_file.flush() 165 166 with self.assertRaises(SystemExit): 167 AIDHeaderParser(temp_file.name) 168 169 def test_aid_header_parser_bad_oem_range_mismatch_start_end(self): 170 """Test AID Header Parser bad oem range mismatched input file""" 171 172 with tempfile.NamedTemporaryFile() as temp_file: 173 temp_file.write( 174 textwrap.dedent(""" 175 #define AID_OEM_RESERVED_START 2900 176 #define AID_OEM_RESERVED_2_END 2900 177 """)) 178 temp_file.flush() 179 180 with self.assertRaises(SystemExit): 181 AIDHeaderParser(temp_file.name) 182 183 def test_aid_header_parser_bad_duplicate_ranges(self): 184 """Test AID Header Parser exits cleanly on duplicate AIDs""" 185 186 with tempfile.NamedTemporaryFile() as temp_file: 187 temp_file.write( 188 textwrap.dedent(""" 189 #define AID_FOO 100 190 #define AID_BAR 100 191 """)) 192 temp_file.flush() 193 194 with self.assertRaises(SystemExit): 195 AIDHeaderParser(temp_file.name) 196 197 def test_aid_header_parser_no_bad_aids(self): 198 """Test AID Header Parser that it doesn't contain: 199 Ranges, ie things the end with "_START" or "_END" 200 AID_APP 201 AID_USER 202 For more details see: 203 - https://android-review.googlesource.com/#/c/313024 204 - https://android-review.googlesource.com/#/c/313169 205 """ 206 207 with tempfile.NamedTemporaryFile() as temp_file: 208 temp_file.write( 209 textwrap.dedent(""" 210 #define AID_APP 10000 /* TODO: switch users over to AID_APP_START */ 211 #define AID_APP_START 10000 /* first app user */ 212 #define AID_APP_END 19999 /* last app user */ 213 214 #define AID_CACHE_GID_START 20000 /* start of gids for apps to mark cached data */ 215 #define AID_CACHE_GID_END 29999 /* end of gids for apps to mark cached data */ 216 217 #define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */ 218 #define AID_SHARED_GID_END 59999 /* end of gids for apps in each user to share */ 219 220 #define AID_ISOLATED_START 99000 /* start of uids for fully isolated sandboxed processes */ 221 #define AID_ISOLATED_END 99999 /* end of uids for fully isolated sandboxed processes */ 222 223 #define AID_USER 100000 /* TODO: switch users over to AID_USER_OFFSET */ 224 #define AID_USER_OFFSET 100000 /* offset for uid ranges for each user */ 225 """)) 226 temp_file.flush() 227 228 parser = AIDHeaderParser(temp_file.name) 229 aids = parser.aids 230 231 bad_aids = ['_START', '_END', 'AID_APP', 'AID_USER'] 232 233 for aid in aids: 234 self.assertFalse( 235 any(bad in aid.identifier for bad in bad_aids), 236 'Not expecting keywords "%s" in aids "%s"' % 237 (str(bad_aids), str([tmp.identifier for tmp in aids]))) 238 239 def test_fs_config_file_parser_good(self): 240 """Test FSConfig Parser good input file""" 241 242 with tempfile.NamedTemporaryFile() as temp_file: 243 temp_file.write( 244 textwrap.dedent(""" 245 [/system/bin/file] 246 user: AID_FOO 247 group: AID_SYSTEM 248 mode: 0777 249 caps: BLOCK_SUSPEND 250 251 [/vendor/path/dir/] 252 user: AID_FOO 253 group: AID_SYSTEM 254 mode: 0777 255 caps: 0 256 257 [AID_OEM1] 258 # 5001 in base16 259 value: 0x1389 260 """)) 261 temp_file.flush() 262 263 parser = FSConfigFileParser([temp_file.name], [(5000, 5999)]) 264 files = parser.files 265 dirs = parser.dirs 266 aids = parser.aids 267 268 self.assertEquals(len(files), 1) 269 self.assertEquals(len(dirs), 1) 270 self.assertEquals(len(aids), 1) 271 272 aid = aids[0] 273 fcap = files[0] 274 dcap = dirs[0] 275 276 self.assertEqual(fcap, 277 FSConfig('0777', 'AID_FOO', 'AID_SYSTEM', 278 '(1ULL << CAP_BLOCK_SUSPEND)', 279 '/system/bin/file', temp_file.name)) 280 281 self.assertEqual(dcap, 282 FSConfig('0777', 'AID_FOO', 'AID_SYSTEM', '(0)', 283 '/vendor/path/dir/', temp_file.name)) 284 285 self.assertEqual(aid, AID('AID_OEM1', '0x1389', temp_file.name)) 286 287 def test_fs_config_file_parser_bad(self): 288 """Test FSConfig Parser bad input file""" 289 290 with tempfile.NamedTemporaryFile() as temp_file: 291 temp_file.write( 292 textwrap.dedent(""" 293 [/system/bin/file] 294 caps: BLOCK_SUSPEND 295 """)) 296 temp_file.flush() 297 298 with self.assertRaises(SystemExit): 299 FSConfigFileParser([temp_file.name], [(5000, 5999)]) 300 301 def test_fs_config_file_parser_bad_aid_range(self): 302 """Test FSConfig Parser bad aid range value input file""" 303 304 with tempfile.NamedTemporaryFile() as temp_file: 305 temp_file.write( 306 textwrap.dedent(""" 307 [AID_OEM1] 308 value: 25 309 """)) 310 temp_file.flush() 311 312 with self.assertRaises(SystemExit): 313 FSConfigFileParser([temp_file.name], [(5000, 5999)]) 314