2 # Copyright (c) 2012 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.
10 from caching_file_system import CachingFileSystem
11 from file_system import FileSystem, StatInfo
12 from future import Future
13 from local_file_system import LocalFileSystem
14 from mock_file_system import MockFileSystem
15 from object_store_creator import ObjectStoreCreator
16 from test_file_system import TestFileSystem
17 from test_object_store import TestObjectStore
20 return LocalFileSystem(
21 os.path.join(sys.path[0], 'test_data', 'file_system'))
23 class CachingFileSystemTest(unittest.TestCase):
25 # Use this to make sure that every time _CreateCachingFileSystem is called
26 # the underlying object store data is the same, within each test.
27 self._object_store_dbs = {}
29 def _CreateCachingFileSystem(self, fs, start_empty=False):
30 def store_type_constructor(namespace, start_empty=False):
31 '''Returns an ObjectStore backed onto test-lifetime-persistent objects
32 in |_object_store_dbs|.
34 if namespace not in self._object_store_dbs:
35 self._object_store_dbs[namespace] = {}
36 db = self._object_store_dbs[namespace]
39 return TestObjectStore(namespace, init=db)
40 object_store_creator = ObjectStoreCreator(start_empty=start_empty,
41 store_type=store_type_constructor)
42 return CachingFileSystem(fs, object_store_creator)
44 def testReadFiles(self):
45 file_system = self._CreateCachingFileSystem(
46 _CreateLocalFs(), start_empty=False)
48 './test1.txt': 'test1\n',
49 './test2.txt': 'test2\n',
50 './test3.txt': 'test3\n',
54 file_system.Read(['./test1.txt', './test2.txt', './test3.txt']).Get())
56 def testListDir(self):
57 file_system = self._CreateCachingFileSystem(
58 _CreateLocalFs(), start_empty=False)
59 expected = ['dir/'] + ['file%d.html' % i for i in range(7)]
60 file_system._read_object_store.Set(
62 (expected, file_system.Stat('list/').version))
63 self.assertEqual(expected, sorted(file_system.ReadSingle('list/').Get()))
65 expected.remove('file0.html')
66 file_system._read_object_store.Set(
68 (expected, file_system.Stat('list/').version))
69 self.assertEqual(expected, sorted(file_system.ReadSingle('list/').Get()))
71 def testCaching(self):
72 test_fs = TestFileSystem({
74 'bob0': 'bob/bob0 contents',
75 'bob1': 'bob/bob1 contents',
76 'bob2': 'bob/bob2 contents',
77 'bob3': 'bob/bob3 contents',
80 mock_fs = MockFileSystem(test_fs)
81 def create_empty_caching_fs():
82 return self._CreateCachingFileSystem(mock_fs, start_empty=True)
84 file_system = create_empty_caching_fs()
86 # The stat/read should happen before resolving the Future, and resolving
87 # the future shouldn't do any additional work.
88 get_future = file_system.ReadSingle('bob/bob0')
89 self.assertTrue(*mock_fs.CheckAndReset(read_count=1, stat_count=1))
90 self.assertEqual('bob/bob0 contents', get_future.Get())
91 self.assertTrue(*mock_fs.CheckAndReset(read_resolve_count=1))
93 # Resource has been cached, so test resource is not re-fetched.
94 self.assertEqual('bob/bob0 contents',
95 file_system.ReadSingle('bob/bob0').Get())
96 self.assertTrue(*mock_fs.CheckAndReset())
98 # Test if the Stat version is the same the resource is not re-fetched.
99 file_system = create_empty_caching_fs()
100 self.assertEqual('bob/bob0 contents',
101 file_system.ReadSingle('bob/bob0').Get())
102 self.assertTrue(*mock_fs.CheckAndReset(stat_count=1))
104 # Test if there is a newer version, the resource is re-fetched.
105 file_system = create_empty_caching_fs()
106 test_fs.IncrementStat();
107 future = file_system.ReadSingle('bob/bob0')
108 self.assertTrue(*mock_fs.CheckAndReset(read_count=1, stat_count=1))
109 self.assertEqual('bob/bob0 contents', future.Get())
110 self.assertTrue(*mock_fs.CheckAndReset(read_resolve_count=1))
112 # Test directory and subdirectory stats are cached.
113 file_system = create_empty_caching_fs()
114 file_system._stat_object_store.Del('bob/bob0')
115 file_system._read_object_store.Del('bob/bob0')
116 file_system._stat_object_store.Del('bob/bob1')
117 test_fs.IncrementStat();
118 futures = (file_system.ReadSingle('bob/bob1'),
119 file_system.ReadSingle('bob/bob0'))
120 self.assertTrue(*mock_fs.CheckAndReset(read_count=2, stat_count=1))
121 self.assertEqual(('bob/bob1 contents', 'bob/bob0 contents'),
122 tuple(future.Get() for future in futures))
123 self.assertTrue(*mock_fs.CheckAndReset(read_resolve_count=2))
124 self.assertEqual('bob/bob1 contents',
125 file_system.ReadSingle('bob/bob1').Get())
126 self.assertTrue(*mock_fs.CheckAndReset())
128 # Test a more recent parent directory doesn't force a refetch of children.
129 file_system = create_empty_caching_fs()
130 file_system._read_object_store.Del('bob/bob0')
131 file_system._read_object_store.Del('bob/bob1')
132 futures = (file_system.ReadSingle('bob/bob1'),
133 file_system.ReadSingle('bob/bob2'),
134 file_system.ReadSingle('bob/bob3'))
135 self.assertTrue(*mock_fs.CheckAndReset(read_count=3, stat_count=1))
137 ('bob/bob1 contents', 'bob/bob2 contents', 'bob/bob3 contents'),
138 tuple(future.Get() for future in futures))
139 self.assertTrue(*mock_fs.CheckAndReset(read_resolve_count=3))
141 test_fs.IncrementStat(path='bob/')
142 file_system = create_empty_caching_fs()
143 self.assertEqual('bob/bob1 contents',
144 file_system.ReadSingle('bob/bob1').Get())
145 self.assertEqual('bob/bob2 contents',
146 file_system.ReadSingle('bob/bob2').Get())
147 self.assertEqual('bob/bob3 contents',
148 file_system.ReadSingle('bob/bob3').Get())
149 self.assertTrue(*mock_fs.CheckAndReset(stat_count=1))
151 file_system = create_empty_caching_fs()
152 file_system._stat_object_store.Del('bob/bob0')
153 future = file_system.ReadSingle('bob/bob0')
154 self.assertTrue(*mock_fs.CheckAndReset(read_count=1, stat_count=1))
155 self.assertEqual('bob/bob0 contents', future.Get())
156 self.assertTrue(*mock_fs.CheckAndReset(read_resolve_count=1))
157 self.assertEqual('bob/bob0 contents',
158 file_system.ReadSingle('bob/bob0').Get())
159 self.assertTrue(*mock_fs.CheckAndReset())
161 def testCachedStat(self):
162 test_fs = TestFileSystem({
164 'bob0': 'bob/bob0 contents',
165 'bob1': 'bob/bob1 contents'
168 mock_fs = MockFileSystem(test_fs)
170 file_system = self._CreateCachingFileSystem(mock_fs, start_empty=False)
172 self.assertEqual(StatInfo('0'), file_system.Stat('bob/bob0'))
173 self.assertTrue(*mock_fs.CheckAndReset(stat_count=1))
174 self.assertEqual(StatInfo('0'), file_system.Stat('bob/bob0'))
175 self.assertTrue(*mock_fs.CheckAndReset())
177 # Caching happens on a directory basis, so reading other files from that
178 # directory won't result in a stat.
179 self.assertEqual(StatInfo('0'), file_system.Stat('bob/bob1'))
181 StatInfo('0', child_versions={'bob0': '0', 'bob1': '0'}),
182 file_system.Stat('bob/'))
183 self.assertTrue(*mock_fs.CheckAndReset())
185 # Even though the stat is bumped, the object store still has it cached so
187 test_fs.IncrementStat()
188 self.assertEqual(StatInfo('0'), file_system.Stat('bob/bob0'))
189 self.assertEqual(StatInfo('0'), file_system.Stat('bob/bob1'))
191 StatInfo('0', child_versions={'bob0': '0', 'bob1': '0'}),
192 file_system.Stat('bob/'))
193 self.assertTrue(*mock_fs.CheckAndReset())
195 def testFreshStat(self):
196 test_fs = TestFileSystem({
198 'bob0': 'bob/bob0 contents',
199 'bob1': 'bob/bob1 contents'
202 mock_fs = MockFileSystem(test_fs)
204 def run_expecting_stat(stat):
206 file_system = self._CreateCachingFileSystem(mock_fs, start_empty=True)
208 StatInfo(stat, child_versions={'bob0': stat, 'bob1': stat}),
209 file_system.Stat('bob/'))
210 self.assertTrue(*mock_fs.CheckAndReset(stat_count=1))
211 self.assertEqual(StatInfo(stat), file_system.Stat('bob/bob0'))
212 self.assertEqual(StatInfo(stat), file_system.Stat('bob/bob0'))
213 self.assertTrue(*mock_fs.CheckAndReset())
217 run_expecting_stat('0')
218 test_fs.IncrementStat()
219 run_expecting_stat('1')
221 if __name__ == '__main__':