1 #!/usr/bin/env python 2 # Copyright 2013 The Chromium Authors. All rights reserved. 3 # Use of this source code is governed by a BSD-style license that can be 4 # found in the LICENSE file. 5 6 import functools 7 import os 8 9 from compiled_file_system import Cache, CompiledFileSystem 10 from copy import deepcopy 11 from environment import GetAppVersion 12 from file_system import FileNotFoundError 13 from mock_file_system import MockFileSystem 14 from object_store_creator import ObjectStoreCreator 15 from test_file_system import TestFileSystem 16 from test_object_store import TestObjectStore 17 import unittest 18 19 _TEST_DATA = { 20 '404.html': '404.html contents', 21 'apps': { 22 'a11y.html': 'a11y.html contents', 23 'about_apps.html': 'about_apps.html contents', 24 'fakedir': { 25 'file.html': 'file.html contents' 26 }, 27 'deepdir': { 28 'deepfile.html': 'deepfile.html contents', 29 'deeper': { 30 'deepest.html': 'deepest.html contents', 31 }, 32 } 33 }, 34 'extensions': { 35 'activeTab.html': 'activeTab.html contents', 36 'alarms.html': 'alarms.html contents' 37 } 38 } 39 40 identity = lambda _, x: x 41 42 def _GetTestCompiledFsCreator(): 43 '''Returns a function which creates CompiledFileSystem views of 44 TestFileSystems backed by _TEST_DATA. 45 ''' 46 return functools.partial( 47 CompiledFileSystem.Factory( 48 ObjectStoreCreator(start_empty=False, 49 store_type=TestObjectStore, 50 disable_wrappers=True), 51 ).Create, 52 TestFileSystem(deepcopy(_TEST_DATA))) 53 54 class CompiledFileSystemTest(unittest.TestCase): 55 def testPopulateNamespace(self): 56 def CheckNamespace(expected_file, expected_list, fs): 57 self.assertEqual(expected_file, fs._file_object_store.namespace) 58 self.assertEqual(expected_list, fs._list_object_store.namespace) 59 compiled_fs_creator = _GetTestCompiledFsCreator() 60 f = lambda x: x 61 CheckNamespace( 62 'class=CompiledFileSystem&' 63 'category=CompiledFileSystemTest/TestFileSystem/file&' 64 'app_version=%s' % GetAppVersion(), 65 'class=CompiledFileSystem&' 66 'category=CompiledFileSystemTest/TestFileSystem/list&' 67 'app_version=%s' % GetAppVersion(), 68 compiled_fs_creator(f, CompiledFileSystemTest)) 69 CheckNamespace( 70 'class=CompiledFileSystem&' 71 'category=CompiledFileSystemTest/TestFileSystem/foo/file&' 72 'app_version=%s' % GetAppVersion(), 73 'class=CompiledFileSystem&' 74 'category=CompiledFileSystemTest/TestFileSystem/foo/list&' 75 'app_version=%s' % GetAppVersion(), 76 compiled_fs_creator(f, CompiledFileSystemTest, category='foo')) 77 78 def testPopulateFromFile(self): 79 def Sleepy(key, val): 80 return '%s%s' % ('Z' * len(key), 'z' * len(val)) 81 compiled_fs = _GetTestCompiledFsCreator()(Sleepy, CompiledFileSystemTest) 82 self.assertEqual('ZZZZZZZZzzzzzzzzzzzzzzzzz', 83 compiled_fs.GetFromFile('404.html').Get()) 84 self.assertEqual('ZZZZZZZZZZZZZZzzzzzzzzzzzzzzzzzz', 85 compiled_fs.GetFromFile('apps/a11y.html').Get()) 86 self.assertEqual('ZZZZZZZZZZZZZZZZZZZZZZzzzzzzzzzzzzzzzzzz', 87 compiled_fs.GetFromFile('apps/fakedir/file.html').Get()) 88 89 def testPopulateFromFileListing(self): 90 def strip_ext(_, files): 91 return [os.path.splitext(f)[0] for f in files] 92 compiled_fs = _GetTestCompiledFsCreator()(strip_ext, CompiledFileSystemTest) 93 expected_top_listing = [ 94 '404', 95 'apps/a11y', 96 'apps/about_apps', 97 'apps/deepdir/deeper/deepest', 98 'apps/deepdir/deepfile', 99 'apps/fakedir/file', 100 'extensions/activeTab', 101 'extensions/alarms' 102 ] 103 self.assertEqual(expected_top_listing, 104 sorted(compiled_fs.GetFromFileListing('').Get())) 105 expected_apps_listing = [ 106 'a11y', 107 'about_apps', 108 'deepdir/deeper/deepest', 109 'deepdir/deepfile', 110 'fakedir/file', 111 ] 112 self.assertEqual(expected_apps_listing, 113 sorted(compiled_fs.GetFromFileListing('apps/').Get())) 114 self.assertEqual(['file',], 115 compiled_fs.GetFromFileListing('apps/fakedir/').Get()) 116 self.assertEqual(['deeper/deepest', 'deepfile'], 117 sorted(compiled_fs.GetFromFileListing( 118 'apps/deepdir/').Get())) 119 self.assertEqual(['deepest'], 120 compiled_fs.GetFromFileListing( 121 'apps/deepdir/deeper/').Get()) 122 123 def testCaching(self): 124 compiled_fs = _GetTestCompiledFsCreator()(Cache(identity), 125 CompiledFileSystemTest) 126 self.assertEqual('404.html contents', 127 compiled_fs.GetFromFile('404.html').Get()) 128 self.assertEqual(set(('file.html',)), 129 set(compiled_fs.GetFromFileListing('apps/fakedir/').Get())) 130 131 compiled_fs._file_system._path_values['404.html'] = 'boom' 132 compiled_fs._file_system._path_values['apps/fakedir/'] = [ 133 'file.html', 'boom.html'] 134 self.assertEqual('404.html contents', 135 compiled_fs.GetFromFile('404.html').Get()) 136 self.assertEqual(set(('file.html',)), 137 set(compiled_fs.GetFromFileListing('apps/fakedir/').Get())) 138 139 compiled_fs._file_system.IncrementStat() 140 self.assertEqual('boom', compiled_fs.GetFromFile('404.html').Get()) 141 self.assertEqual(set(('file.html', 'boom.html')), 142 set(compiled_fs.GetFromFileListing('apps/fakedir/').Get())) 143 144 def testFailures(self): 145 compiled_fs = _GetTestCompiledFsCreator()(identity, CompiledFileSystemTest) 146 self.assertRaises(FileNotFoundError, 147 compiled_fs.GetFromFile('405.html').Get) 148 # TODO(kalman): would be nice to test this fails since apps/ is a dir. 149 compiled_fs.GetFromFile('apps') 150 #self.assertRaises(SomeError, compiled_fs.GetFromFile, 'apps/') 151 self.assertRaises(FileNotFoundError, 152 compiled_fs.GetFromFileListing('nodir/').Get) 153 # TODO(kalman): likewise, not a FileNotFoundError. 154 self.assertRaises(FileNotFoundError, 155 compiled_fs.GetFromFileListing('404.html/').Get) 156 157 def testCorrectFutureBehaviour(self): 158 # Tests that the underlying FileSystem's Read Future has had Get() called 159 # on it before the Future is resolved, but the underlying Future isn't 160 # resolved until Get is. 161 mock_fs = MockFileSystem(TestFileSystem(_TEST_DATA)) 162 compiled_fs = CompiledFileSystem.Factory( 163 ObjectStoreCreator.ForTest()).Create( 164 mock_fs, lambda path, contents: contents, type(self)) 165 166 self.assertTrue(*mock_fs.CheckAndReset()) 167 future = compiled_fs.GetFromFile('404.html') 168 self.assertTrue(*mock_fs.CheckAndReset(stat_count=1, read_count=1)) 169 future.Get() 170 self.assertTrue(*mock_fs.CheckAndReset(read_resolve_count=1)) 171 172 future = compiled_fs.GetFromFileListing('apps/') 173 # Current behaviour is to have read=2 and read_resolve=1 because the first 174 # level is read eagerly, then all of the second is read (in parallel). If 175 # it weren't eager (and it may be worth experimenting with that) then it'd 176 # be read=1 and read_resolve=0. 177 self.assertTrue(*mock_fs.CheckAndReset(stat_count=1, 178 read_count=2, 179 read_resolve_count=1)) 180 future.Get() 181 # It's doing 1 more level 'deeper' (already read 'fakedir' and 'deepdir' 182 # though not resolved), so that's 1 more read/resolve + the resolve from 183 # the first read. 184 self.assertTrue(*mock_fs.CheckAndReset(read_count=1, read_resolve_count=2)) 185 186 # Even though the directory is 1 layer deep the caller has no way of 187 # determining that ahead of time (though perhaps the API could give some 188 # kind of clue, if we really cared). 189 future = compiled_fs.GetFromFileListing('extensions/') 190 self.assertTrue(*mock_fs.CheckAndReset(stat_count=1, 191 read_count=1, 192 read_resolve_count=1)) 193 future.Get() 194 self.assertTrue(*mock_fs.CheckAndReset()) 195 196 # Similar configuration to the 'apps/' case but deeper. 197 future = compiled_fs.GetFromFileListing('') 198 self.assertTrue(*mock_fs.CheckAndReset(stat_count=1, 199 read_count=2, 200 read_resolve_count=1)) 201 future.Get() 202 self.assertTrue(*mock_fs.CheckAndReset(read_count=2, read_resolve_count=3)) 203 204 def testSkipNotFound(self): 205 mock_fs = MockFileSystem(TestFileSystem(_TEST_DATA)) 206 compiled_fs = CompiledFileSystem.Factory( 207 ObjectStoreCreator.ForTest()).Create( 208 mock_fs, Cache(lambda path, contents: contents), type(self)) 209 210 future = compiled_fs.GetFromFile('no_file', skip_not_found=True) 211 # If the file doesn't exist, then the file system is not read. 212 self.assertTrue(*mock_fs.CheckAndReset(read_count=1, stat_count=1)) 213 self.assertEqual(None, future.Get()) 214 self.assertTrue(*mock_fs.CheckAndReset(read_resolve_count=1)) 215 future = compiled_fs.GetFromFile('no_file', skip_not_found=True) 216 self.assertTrue(*mock_fs.CheckAndReset(stat_count=1)) 217 self.assertEqual(None, future.Get()) 218 # The result for a non-existent file should still be cached. 219 self.assertTrue(*mock_fs.CheckAndReset()) 220 future = compiled_fs.GetFromFile('no_file') 221 self.assertRaises(FileNotFoundError, future.Get) 222 223 224 if __name__ == '__main__': 225 unittest.main() 226