| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2013 The LUCI Authors. All rights reserved. | 2 # Copyright 2013 The LUCI Authors. All rights reserved. |
| 3 # Use of this source code is governed under the Apache License, Version 2.0 | 3 # Use of this source code is governed under the Apache License, Version 2.0 |
| 4 # that can be found in the LICENSE file. | 4 # that can be found in the LICENSE file. |
| 5 | 5 |
| 6 # pylint: disable=W0212,W0223,W0231,W0613 | 6 # pylint: disable=W0212,W0223,W0231,W0613 |
| 7 | 7 |
| 8 import base64 | 8 import base64 |
| 9 import collections | 9 import collections |
| 10 import hashlib | 10 import hashlib |
| (...skipping 1230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1241 # Max: 100 bytes, 2 items | 1241 # Max: 100 bytes, 2 items |
| 1242 # Min free disk: 1000 bytes. | 1242 # Min free disk: 1000 bytes. |
| 1243 self._policies = isolateserver.CachePolicies(100, 1000, 2) | 1243 self._policies = isolateserver.CachePolicies(100, 1000, 2) |
| 1244 def get_free_space(p): | 1244 def get_free_space(p): |
| 1245 self.assertEqual(p, self.tempdir) | 1245 self.assertEqual(p, self.tempdir) |
| 1246 return self._free_disk | 1246 return self._free_disk |
| 1247 self.mock(file_path, 'get_free_space', get_free_space) | 1247 self.mock(file_path, 'get_free_space', get_free_space) |
| 1248 # TODO(maruel): Test the following. | 1248 # TODO(maruel): Test the following. |
| 1249 #cache.touch() | 1249 #cache.touch() |
| 1250 | 1250 |
| 1251 self.now = 0.0 |
| 1252 |
| 1251 def get_cache(self): | 1253 def get_cache(self): |
| 1252 return isolateserver.DiskCache(self.tempdir, self._policies, self._algo) | 1254 return isolateserver.DiskCache( |
| 1255 self.tempdir, self._policies, self._algo, time_fn=lambda: self.now) |
| 1253 | 1256 |
| 1254 def to_hash(self, content): | 1257 def to_hash(self, content): |
| 1255 return self._algo(content).hexdigest(), content | 1258 return self._algo(content).hexdigest(), content |
| 1256 | 1259 |
| 1257 def test_read_evict(self): | 1260 def test_read_evict(self): |
| 1258 self._free_disk = 1100 | 1261 self._free_disk = 1100 |
| 1259 h_a = self.to_hash('a')[0] | 1262 h_a = self.to_hash('a')[0] |
| 1260 with self.get_cache() as cache: | 1263 with self.get_cache() as cache: |
| 1261 cache.write(h_a, 'a') | 1264 cache.write(h_a, 'a') |
| 1262 with cache.getfileobj(h_a) as f: | 1265 with cache.getfileobj(h_a) as f: |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1284 cache.write(*self.to_hash(i)) | 1287 cache.write(*self.to_hash(i)) |
| 1285 # Mapping more content than the amount of free disk required. | 1288 # Mapping more content than the amount of free disk required. |
| 1286 with self.assertRaises(isolateserver.Error): | 1289 with self.assertRaises(isolateserver.Error): |
| 1287 cache.write(*self.to_hash('e')) | 1290 cache.write(*self.to_hash('e')) |
| 1288 | 1291 |
| 1289 def test_cleanup(self): | 1292 def test_cleanup(self): |
| 1290 # Inject an item without a state.json. It will be deleted on cleanup. | 1293 # Inject an item without a state.json. It will be deleted on cleanup. |
| 1291 h_a = self.to_hash('a')[0] | 1294 h_a = self.to_hash('a')[0] |
| 1292 isolateserver.file_write(os.path.join(self.tempdir, h_a), 'a') | 1295 isolateserver.file_write(os.path.join(self.tempdir, h_a), 'a') |
| 1293 cache = self.get_cache() | 1296 cache = self.get_cache() |
| 1294 self.assertEqual([], sorted(cache._lru._items.iteritems())) | 1297 self.assertEqual([], sorted(cache._lru.iteritems())) |
| 1295 self.assertEqual( | 1298 self.assertEqual(sorted([h_a]), sorted(os.listdir(self.tempdir))) |
| 1296 sorted([h_a, u'state.json']), sorted(os.listdir(self.tempdir))) | |
| 1297 cache.cleanup() | 1299 cache.cleanup() |
| 1298 self.assertEqual([u'state.json'], os.listdir(self.tempdir)) | 1300 self.assertEqual([], os.listdir(self.tempdir)) |
| 1299 | 1301 |
| 1300 def test_policies_active_trimming(self): | 1302 def test_policies_active_trimming(self): |
| 1301 # Start with a larger cache, add many object. | 1303 # Start with a larger cache, add many object. |
| 1302 # Reload the cache with smaller policies, the cache should be trimmed on | 1304 # Reload the cache with smaller policies, the cache should be trimmed on |
| 1303 # load. | 1305 # load. |
| 1304 h_a = self.to_hash('a')[0] | 1306 h_a = self.to_hash('a')[0] |
| 1305 h_b = self.to_hash('b')[0] | 1307 h_b = self.to_hash('b')[0] |
| 1306 h_c = self.to_hash('c')[0] | 1308 h_c = self.to_hash('c')[0] |
| 1307 h_large, large = self.to_hash('b' * 99) | 1309 h_large, large = self.to_hash('b' * 99) |
| 1308 | 1310 |
| 1309 # Max policies is 100 bytes, 2 items, 1000 bytes free space. | 1311 # Max policies is 100 bytes, 2 items, 1000 bytes free space. |
| 1310 self._free_disk = 1101 | 1312 self._free_disk = 1101 |
| 1311 with self.get_cache() as cache: | 1313 with self.get_cache() as cache: |
| 1312 cache.write(h_a, 'a') | 1314 cache.write(h_a, 'a') |
| 1313 cache.write(h_large, large) | 1315 cache.write(h_large, large) |
| 1314 # Cache (size and # items) is not enforced while adding items. The | 1316 # Cache (size and # items) is not enforced while adding items. The |
| 1315 # rationale is that a task may request more data than the size of the | 1317 # rationale is that a task may request more data than the size of the |
| 1316 # cache policies. As long as there is free space, this is fine. | 1318 # cache policies. As long as there is free space, this is fine. |
| 1317 cache.write(h_b, 'b') | 1319 cache.write(h_b, 'b') |
| 1318 expected = sorted(((h_a, 1), (h_large, len(large)), (h_b, 1))) | 1320 expected = sorted(((h_a, 1), (h_large, len(large)), (h_b, 1))) |
| 1319 self.assertEqual(expected, sorted(cache._lru._items.iteritems())) | 1321 self.assertEqual(expected, sorted(cache._sizes())) |
| 1320 self.assertEqual(h_a, cache._protected) | 1322 self.assertEqual(h_a, cache._protected) |
| 1321 self.assertEqual(1000, cache._free_disk) | 1323 self.assertEqual(1000, cache._free_disk) |
| 1322 self.assertEqual(0, cache.initial_number_items) | 1324 self.assertEqual(0, cache.initial_number_items) |
| 1323 self.assertEqual(0, cache.initial_size) | 1325 self.assertEqual(0, cache.initial_size) |
| 1324 # Free disk is enforced, because otherwise we assume the task wouldn't | 1326 # Free disk is enforced, because otherwise we assume the task wouldn't |
| 1325 # be able to start. In this case, it throws an exception since all items | 1327 # be able to start. In this case, it throws an exception since all items |
| 1326 # are protected. The item is added since it's detected after the fact. | 1328 # are protected. The item is added since it's detected after the fact. |
| 1327 with self.assertRaises(isolateserver.Error): | 1329 with self.assertRaises(isolateserver.Error): |
| 1328 cache.write(h_c, 'c') | 1330 cache.write(h_c, 'c') |
| 1329 | 1331 |
| 1330 # At this point, after the implicit trim in __exit__(), h_a and h_large were | 1332 # At this point, after the implicit trim in __exit__(), h_a and h_large were |
| 1331 # evicted. | 1333 # evicted. |
| 1332 self.assertEqual( | 1334 self.assertEqual( |
| 1333 sorted([h_b, h_c, u'state.json']), sorted(os.listdir(self.tempdir))) | 1335 set([h_b[:2], h_c[:2], u'state.json']), |
| 1336 set(os.listdir(self.tempdir))) |
| 1334 | 1337 |
| 1335 # Allow 3 items and 101 bytes so h_large is kept. | 1338 # Allow 3 items and 101 bytes so h_large is kept. |
| 1336 self._policies = isolateserver.CachePolicies(101, 1000, 3) | 1339 self._policies = isolateserver.CachePolicies(101, 1000, 3) |
| 1337 with self.get_cache() as cache: | 1340 with self.get_cache() as cache: |
| 1338 cache.write(h_large, large) | 1341 cache.write(h_large, large) |
| 1339 self.assertEqual(2, cache.initial_number_items) | 1342 self.assertEqual(2, cache.initial_number_items) |
| 1340 self.assertEqual(2, cache.initial_size) | 1343 self.assertEqual(2, cache.initial_size) |
| 1341 | 1344 |
| 1342 self.assertEqual( | 1345 self.assertEqual( |
| 1343 sorted([h_b, h_c, h_large, u'state.json']), | 1346 set([h_b[:2], h_c[:2], h_large[:2], u'state.json']), |
| 1344 sorted(os.listdir(self.tempdir))) | 1347 set(os.listdir(self.tempdir))) |
| 1345 | 1348 |
| 1346 # Assert that trimming is done in constructor too. | 1349 # Assert that trimming is done in constructor too. |
| 1347 self._policies = isolateserver.CachePolicies(100, 1000, 2) | 1350 self._policies = isolateserver.CachePolicies(100, 1000, 2) |
| 1348 with self.get_cache() as cache: | 1351 with self.get_cache() as cache: |
| 1349 expected = collections.OrderedDict([(h_c, 1), (h_large, len(large))]) | 1352 self.assertEqual( |
| 1350 self.assertEqual(expected, cache._lru._items) | 1353 [(h_c, 1), (h_large, len(large))], |
| 1354 list(cache._sizes())) |
| 1351 self.assertEqual(None, cache._protected) | 1355 self.assertEqual(None, cache._protected) |
| 1352 self.assertEqual(1101, cache._free_disk) | 1356 self.assertEqual(1101, cache._free_disk) |
| 1353 self.assertEqual(2, cache.initial_number_items) | 1357 self.assertEqual(2, cache.initial_number_items) |
| 1354 self.assertEqual(100, cache.initial_size) | 1358 self.assertEqual(100, cache.initial_size) |
| 1355 | 1359 |
| 1360 def test_timestamp(self): |
| 1361 self._free_disk = 1100 |
| 1362 cache = self.get_cache() |
| 1363 with cache: |
| 1364 self.now = 1 |
| 1365 cache.write('deadbeef', '1') |
| 1366 |
| 1367 self.now = 2 |
| 1368 cache.write('badcoffee', '2') |
| 1369 |
| 1370 self.assertEqual( |
| 1371 [ |
| 1372 ('deadbeef', [1, 1]), |
| 1373 ('badcoffee', [1, 2]), |
| 1374 ], |
| 1375 cache._lru.items() |
| 1376 ) |
| 1377 |
| 1378 loaded = self.get_cache() |
| 1379 self.assertEqual(cache._lru, loaded._lru) |
| 1380 |
| 1356 | 1381 |
| 1357 def clear_env_vars(): | 1382 def clear_env_vars(): |
| 1358 for e in ('ISOLATE_DEBUG', 'ISOLATE_SERVER'): | 1383 for e in ('ISOLATE_DEBUG', 'ISOLATE_SERVER'): |
| 1359 os.environ.pop(e, None) | 1384 os.environ.pop(e, None) |
| 1360 | 1385 |
| 1361 | 1386 |
| 1362 if __name__ == '__main__': | 1387 if __name__ == '__main__': |
| 1363 fix_encoding.fix_encoding() | 1388 fix_encoding.fix_encoding() |
| 1364 if '-v' in sys.argv: | 1389 if '-v' in sys.argv: |
| 1365 unittest.TestCase.maxDiff = None | 1390 unittest.TestCase.maxDiff = None |
| 1366 logging.basicConfig( | 1391 logging.basicConfig( |
| 1367 level=(logging.DEBUG if '-v' in sys.argv else logging.CRITICAL)) | 1392 level=(logging.DEBUG if '-v' in sys.argv else logging.CRITICAL)) |
| 1368 clear_env_vars() | 1393 clear_env_vars() |
| 1369 unittest.main() | 1394 unittest.main() |
| OLD | NEW |