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 StatInfo
12 from local_file_system
import LocalFileSystem
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
19 return LocalFileSystem(
20 os
.path
.join(sys
.path
[0], 'test_data', 'file_system'))
22 class CachingFileSystemTest(unittest
.TestCase
):
24 # Use this to make sure that every time _CreateCachingFileSystem is called
25 # the underlying object store data is the same, within each test.
26 self
._object
_store
_dbs
= {}
28 def _CreateCachingFileSystem(self
, fs
, start_empty
=False):
29 def store_type_constructor(namespace
, start_empty
=False):
30 '''Returns an ObjectStore backed onto test-lifetime-persistent objects
31 in |_object_store_dbs|.
33 if namespace
not in self
._object
_store
_dbs
:
34 self
._object
_store
_dbs
[namespace
] = {}
35 db
= self
._object
_store
_dbs
[namespace
]
38 return TestObjectStore(namespace
, init
=db
)
39 object_store_creator
= ObjectStoreCreator(start_empty
=start_empty
,
40 store_type
=store_type_constructor
)
41 return CachingFileSystem(fs
, object_store_creator
)
43 def testReadFiles(self
):
44 file_system
= self
._CreateCachingFileSystem
(
45 _CreateLocalFs(), start_empty
=False)
47 './test1.txt': 'test1\n',
48 './test2.txt': 'test2\n',
49 './test3.txt': 'test3\n',
53 file_system
.Read(['./test1.txt', './test2.txt', './test3.txt']).Get())
55 def testListDir(self
):
56 file_system
= self
._CreateCachingFileSystem
(
57 _CreateLocalFs(), start_empty
=False)
58 expected
= ['dir/'] + ['file%d.html' % i
for i
in range(7)]
59 file_system
._read
_object
_store
.Set(
61 (expected
, file_system
.Stat('list/').version
))
62 self
.assertEqual(expected
, sorted(file_system
.ReadSingle('list/').Get()))
64 expected
.remove('file0.html')
65 file_system
._read
_object
_store
.Set(
67 (expected
, file_system
.Stat('list/').version
))
68 self
.assertEqual(expected
, sorted(file_system
.ReadSingle('list/').Get()))
70 def testCaching(self
):
71 test_fs
= TestFileSystem({
73 'bob0': 'bob/bob0 contents',
74 'bob1': 'bob/bob1 contents',
75 'bob2': 'bob/bob2 contents',
76 'bob3': 'bob/bob3 contents',
79 mock_fs
= MockFileSystem(test_fs
)
80 def create_empty_caching_fs():
81 return self
._CreateCachingFileSystem
(mock_fs
, start_empty
=True)
83 file_system
= create_empty_caching_fs()
85 # The stat/read should happen before resolving the Future, and resolving
86 # the future shouldn't do any additional work.
87 get_future
= file_system
.ReadSingle('bob/bob0')
88 self
.assertTrue(*mock_fs
.CheckAndReset(read_count
=1, stat_count
=1))
89 self
.assertEqual('bob/bob0 contents', get_future
.Get())
90 self
.assertTrue(*mock_fs
.CheckAndReset(read_resolve_count
=1))
92 # Resource has been cached, so test resource is not re-fetched.
93 self
.assertEqual('bob/bob0 contents',
94 file_system
.ReadSingle('bob/bob0').Get())
95 self
.assertTrue(*mock_fs
.CheckAndReset())
97 # Test if the Stat version is the same the resource is not re-fetched.
98 file_system
= create_empty_caching_fs()
99 self
.assertEqual('bob/bob0 contents',
100 file_system
.ReadSingle('bob/bob0').Get())
101 self
.assertTrue(*mock_fs
.CheckAndReset(stat_count
=1))
103 # Test if there is a newer version, the resource is re-fetched.
104 file_system
= create_empty_caching_fs()
105 test_fs
.IncrementStat();
106 future
= file_system
.ReadSingle('bob/bob0')
107 self
.assertTrue(*mock_fs
.CheckAndReset(read_count
=1, stat_count
=1))
108 self
.assertEqual('bob/bob0 contents', future
.Get())
109 self
.assertTrue(*mock_fs
.CheckAndReset(read_resolve_count
=1))
111 # Test directory and subdirectory stats are cached.
112 file_system
= create_empty_caching_fs()
113 file_system
._stat
_object
_store
.Del('bob/bob0')
114 file_system
._read
_object
_store
.Del('bob/bob0')
115 file_system
._stat
_object
_store
.Del('bob/bob1')
116 test_fs
.IncrementStat();
117 futures
= (file_system
.ReadSingle('bob/bob1'),
118 file_system
.ReadSingle('bob/bob0'))
119 self
.assertTrue(*mock_fs
.CheckAndReset(read_count
=2, stat_count
=1))
120 self
.assertEqual(('bob/bob1 contents', 'bob/bob0 contents'),
121 tuple(future
.Get() for future
in futures
))
122 self
.assertTrue(*mock_fs
.CheckAndReset(read_resolve_count
=2))
123 self
.assertEqual('bob/bob1 contents',
124 file_system
.ReadSingle('bob/bob1').Get())
125 self
.assertTrue(*mock_fs
.CheckAndReset())
127 # Test a more recent parent directory doesn't force a refetch of children.
128 file_system
= create_empty_caching_fs()
129 file_system
._read
_object
_store
.Del('bob/bob0')
130 file_system
._read
_object
_store
.Del('bob/bob1')
131 futures
= (file_system
.ReadSingle('bob/bob1'),
132 file_system
.ReadSingle('bob/bob2'),
133 file_system
.ReadSingle('bob/bob3'))
134 self
.assertTrue(*mock_fs
.CheckAndReset(read_count
=3, stat_count
=1))
136 ('bob/bob1 contents', 'bob/bob2 contents', 'bob/bob3 contents'),
137 tuple(future
.Get() for future
in futures
))
138 self
.assertTrue(*mock_fs
.CheckAndReset(read_resolve_count
=3))
140 test_fs
.IncrementStat(path
='bob/')
141 file_system
= create_empty_caching_fs()
142 self
.assertEqual('bob/bob1 contents',
143 file_system
.ReadSingle('bob/bob1').Get())
144 self
.assertEqual('bob/bob2 contents',
145 file_system
.ReadSingle('bob/bob2').Get())
146 self
.assertEqual('bob/bob3 contents',
147 file_system
.ReadSingle('bob/bob3').Get())
148 self
.assertTrue(*mock_fs
.CheckAndReset(stat_count
=1))
150 file_system
= create_empty_caching_fs()
151 file_system
._stat
_object
_store
.Del('bob/bob0')
152 future
= file_system
.ReadSingle('bob/bob0')
153 self
.assertTrue(*mock_fs
.CheckAndReset(read_count
=1, stat_count
=1))
154 self
.assertEqual('bob/bob0 contents', future
.Get())
155 self
.assertTrue(*mock_fs
.CheckAndReset(read_resolve_count
=1))
156 self
.assertEqual('bob/bob0 contents',
157 file_system
.ReadSingle('bob/bob0').Get())
158 self
.assertTrue(*mock_fs
.CheckAndReset())
160 def testCachedStat(self
):
161 test_fs
= TestFileSystem({
163 'bob0': 'bob/bob0 contents',
164 'bob1': 'bob/bob1 contents'
167 mock_fs
= MockFileSystem(test_fs
)
169 file_system
= self
._CreateCachingFileSystem
(mock_fs
, start_empty
=False)
171 self
.assertEqual(StatInfo('0'), file_system
.Stat('bob/bob0'))
172 self
.assertTrue(*mock_fs
.CheckAndReset(stat_count
=1))
173 self
.assertEqual(StatInfo('0'), file_system
.Stat('bob/bob0'))
174 self
.assertTrue(*mock_fs
.CheckAndReset())
176 # Caching happens on a directory basis, so reading other files from that
177 # directory won't result in a stat.
178 self
.assertEqual(StatInfo('0'), file_system
.Stat('bob/bob1'))
180 StatInfo('0', child_versions
={'bob0': '0', 'bob1': '0'}),
181 file_system
.Stat('bob/'))
182 self
.assertTrue(*mock_fs
.CheckAndReset())
184 # Even though the stat is bumped, the object store still has it cached so
186 test_fs
.IncrementStat()
187 self
.assertEqual(StatInfo('0'), file_system
.Stat('bob/bob0'))
188 self
.assertEqual(StatInfo('0'), file_system
.Stat('bob/bob1'))
190 StatInfo('0', child_versions
={'bob0': '0', 'bob1': '0'}),
191 file_system
.Stat('bob/'))
192 self
.assertTrue(*mock_fs
.CheckAndReset())
194 def testFreshStat(self
):
195 test_fs
= TestFileSystem({
197 'bob0': 'bob/bob0 contents',
198 'bob1': 'bob/bob1 contents'
201 mock_fs
= MockFileSystem(test_fs
)
203 def run_expecting_stat(stat
):
205 file_system
= self
._CreateCachingFileSystem
(mock_fs
, start_empty
=True)
207 StatInfo(stat
, child_versions
={'bob0': stat
, 'bob1': stat
}),
208 file_system
.Stat('bob/'))
209 self
.assertTrue(*mock_fs
.CheckAndReset(stat_count
=1))
210 self
.assertEqual(StatInfo(stat
), file_system
.Stat('bob/bob0'))
211 self
.assertEqual(StatInfo(stat
), file_system
.Stat('bob/bob0'))
212 self
.assertTrue(*mock_fs
.CheckAndReset())
216 run_expecting_stat('0')
217 test_fs
.IncrementStat()
218 run_expecting_stat('1')
220 if __name__
== '__main__':