1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#!/usr/bin/env python
2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved.
3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)# found in the LICENSE file.
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
64e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)import functools
74e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)import os
84e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccifrom compiled_file_system import Cache, CompiledFileSystem
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)from copy import deepcopy
11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)from environment import GetAppVersion
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from file_system import FileNotFoundError
134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)from mock_file_system import MockFileSystem
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)from object_store_creator import ObjectStoreCreator
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)from test_file_system import TestFileSystem
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)from test_object_store import TestObjectStore
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import unittest
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)_TEST_DATA = {
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  '404.html': '404.html contents',
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  'apps': {
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    'a11y.html': 'a11y.html contents',
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    'about_apps.html': 'about_apps.html contents',
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    'fakedir': {
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      'file.html': 'file.html contents'
264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    },
274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    'deepdir': {
284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      'deepfile.html': 'deepfile.html contents',
294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      'deeper': {
304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        'deepest.html': 'deepest.html contents',
314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      },
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  },
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  'extensions': {
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    'activeTab.html': 'activeTab.html contents',
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    'alarms.html': 'alarms.html contents'
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
40a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)identity = lambda _, x: x
41a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)def _GetTestCompiledFsCreator():
434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  '''Returns a function which creates CompiledFileSystem views of
444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  TestFileSystems backed by _TEST_DATA.
454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  '''
464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return functools.partial(
474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      CompiledFileSystem.Factory(
484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          ObjectStoreCreator(start_empty=False,
494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                             store_type=TestObjectStore,
504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                             disable_wrappers=True),
514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      ).Create,
524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      TestFileSystem(deepcopy(_TEST_DATA)))
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class CompiledFileSystemTest(unittest.TestCase):
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  def testPopulateNamespace(self):
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    def CheckNamespace(expected_file, expected_list, fs):
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      self.assertEqual(expected_file, fs._file_object_store.namespace)
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      self.assertEqual(expected_list, fs._list_object_store.namespace)
594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    compiled_fs_creator = _GetTestCompiledFsCreator()
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    f = lambda x: x
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    CheckNamespace(
62ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        'class=CompiledFileSystem&'
63ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch            'category=CompiledFileSystemTest/TestFileSystem/file&'
64ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch            'app_version=%s' % GetAppVersion(),
65ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        'class=CompiledFileSystem&'
66ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch            'category=CompiledFileSystemTest/TestFileSystem/list&'
67ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch            'app_version=%s' % GetAppVersion(),
684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        compiled_fs_creator(f, CompiledFileSystemTest))
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    CheckNamespace(
70ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        'class=CompiledFileSystem&'
71ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch            'category=CompiledFileSystemTest/TestFileSystem/foo/file&'
72ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch            'app_version=%s' % GetAppVersion(),
73ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        'class=CompiledFileSystem&'
74ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch            'category=CompiledFileSystemTest/TestFileSystem/foo/list&'
75ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch            'app_version=%s' % GetAppVersion(),
764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        compiled_fs_creator(f, CompiledFileSystemTest, category='foo'))
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  def testPopulateFromFile(self):
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    def Sleepy(key, val):
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return '%s%s' % ('Z' * len(key), 'z' * len(val))
814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    compiled_fs = _GetTestCompiledFsCreator()(Sleepy, CompiledFileSystemTest)
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    self.assertEqual('ZZZZZZZZzzzzzzzzzzzzzzzzz',
834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     compiled_fs.GetFromFile('404.html').Get())
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    self.assertEqual('ZZZZZZZZZZZZZZzzzzzzzzzzzzzzzzzz',
854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     compiled_fs.GetFromFile('apps/a11y.html').Get())
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self.assertEqual('ZZZZZZZZZZZZZZZZZZZZZZzzzzzzzzzzzzzzzzzz',
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     compiled_fs.GetFromFile('apps/fakedir/file.html').Get())
884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  def testPopulateFromFileListing(self):
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    def strip_ext(_, files):
914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      return [os.path.splitext(f)[0] for f in files]
924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    compiled_fs = _GetTestCompiledFsCreator()(strip_ext, CompiledFileSystemTest)
934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    expected_top_listing = [
944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      '404',
954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      'apps/a11y',
964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      'apps/about_apps',
974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      'apps/deepdir/deeper/deepest',
984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      'apps/deepdir/deepfile',
994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      'apps/fakedir/file',
1004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      'extensions/activeTab',
1014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      'extensions/alarms'
1024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    ]
1034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self.assertEqual(expected_top_listing,
1044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     sorted(compiled_fs.GetFromFileListing('').Get()))
1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    expected_apps_listing = [
1064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      'a11y',
1074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      'about_apps',
1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      'deepdir/deeper/deepest',
1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      'deepdir/deepfile',
1104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      'fakedir/file',
1114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    ]
1124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self.assertEqual(expected_apps_listing,
1134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     sorted(compiled_fs.GetFromFileListing('apps/').Get()))
1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self.assertEqual(['file',],
1154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     compiled_fs.GetFromFileListing('apps/fakedir/').Get())
1164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self.assertEqual(['deeper/deepest', 'deepfile'],
1174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     sorted(compiled_fs.GetFromFileListing(
1184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                         'apps/deepdir/').Get()))
1194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self.assertEqual(['deepest'],
1204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     compiled_fs.GetFromFileListing(
1214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                         'apps/deepdir/deeper/').Get())
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  def testCaching(self):
1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    compiled_fs = _GetTestCompiledFsCreator()(Cache(identity),
1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                              CompiledFileSystemTest)
1264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self.assertEqual('404.html contents',
1274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     compiled_fs.GetFromFile('404.html').Get())
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    self.assertEqual(set(('file.html',)),
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     set(compiled_fs.GetFromFileListing('apps/fakedir/').Get()))
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    compiled_fs._file_system._path_values['404.html'] = 'boom'
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    compiled_fs._file_system._path_values['apps/fakedir/'] = [
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'file.html', 'boom.html']
1344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self.assertEqual('404.html contents',
1354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     compiled_fs.GetFromFile('404.html').Get())
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    self.assertEqual(set(('file.html',)),
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     set(compiled_fs.GetFromFileListing('apps/fakedir/').Get()))
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    compiled_fs._file_system.IncrementStat()
1404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self.assertEqual('boom', compiled_fs.GetFromFile('404.html').Get())
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    self.assertEqual(set(('file.html', 'boom.html')),
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     set(compiled_fs.GetFromFileListing('apps/fakedir/').Get()))
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  def testFailures(self):
1454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    compiled_fs = _GetTestCompiledFsCreator()(identity, CompiledFileSystemTest)
1464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self.assertRaises(FileNotFoundError,
1474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                      compiled_fs.GetFromFile('405.html').Get)
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    # TODO(kalman): would be nice to test this fails since apps/ is a dir.
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    compiled_fs.GetFromFile('apps')
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    #self.assertRaises(SomeError, compiled_fs.GetFromFile, 'apps/')
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    self.assertRaises(FileNotFoundError,
1524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                      compiled_fs.GetFromFileListing('nodir/').Get)
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    # TODO(kalman): likewise, not a FileNotFoundError.
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    self.assertRaises(FileNotFoundError,
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      compiled_fs.GetFromFileListing('404.html/').Get)
1564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  def testCorrectFutureBehaviour(self):
1584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    # Tests that the underlying FileSystem's Read Future has had Get() called
1594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    # on it before the Future is resolved, but the underlying Future isn't
1604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    # resolved until Get is.
1614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    mock_fs = MockFileSystem(TestFileSystem(_TEST_DATA))
1624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    compiled_fs = CompiledFileSystem.Factory(
1634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        ObjectStoreCreator.ForTest()).Create(
1644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            mock_fs, lambda path, contents: contents, type(self))
1654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self.assertTrue(*mock_fs.CheckAndReset())
1674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    future = compiled_fs.GetFromFile('404.html')
1684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self.assertTrue(*mock_fs.CheckAndReset(stat_count=1, read_count=1))
1694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    future.Get()
1704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self.assertTrue(*mock_fs.CheckAndReset(read_resolve_count=1))
1714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    future = compiled_fs.GetFromFileListing('apps/')
1734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    # Current behaviour is to have read=2 and read_resolve=1 because the first
1744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    # level is read eagerly, then all of the second is read (in parallel). If
1754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    # it weren't eager (and it may be worth experimenting with that) then it'd
1764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    # be read=1 and read_resolve=0.
1774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self.assertTrue(*mock_fs.CheckAndReset(stat_count=1,
1784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                           read_count=2,
1794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                           read_resolve_count=1))
1804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    future.Get()
1814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    # It's doing 1 more level 'deeper' (already read 'fakedir' and 'deepdir'
1824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    # though not resolved), so that's 1 more read/resolve + the resolve from
1834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    # the first read.
1844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self.assertTrue(*mock_fs.CheckAndReset(read_count=1, read_resolve_count=2))
1854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    # Even though the directory is 1 layer deep the caller has no way of
1874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    # determining that ahead of time (though perhaps the API could give some
1884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    # kind of clue, if we really cared).
1894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    future = compiled_fs.GetFromFileListing('extensions/')
1904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self.assertTrue(*mock_fs.CheckAndReset(stat_count=1,
1914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                           read_count=1,
1924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                           read_resolve_count=1))
1934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    future.Get()
1944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self.assertTrue(*mock_fs.CheckAndReset())
1954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    # Similar configuration to the 'apps/' case but deeper.
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    future = compiled_fs.GetFromFileListing('')
1984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self.assertTrue(*mock_fs.CheckAndReset(stat_count=1,
1994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                           read_count=2,
2004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                           read_resolve_count=1))
2014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    future.Get()
2024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self.assertTrue(*mock_fs.CheckAndReset(read_count=2, read_resolve_count=3))
2034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def testSkipNotFound(self):
2051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    mock_fs = MockFileSystem(TestFileSystem(_TEST_DATA))
2061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    compiled_fs = CompiledFileSystem.Factory(
2071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        ObjectStoreCreator.ForTest()).Create(
2081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            mock_fs, Cache(lambda path, contents: contents), type(self))
2091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    future = compiled_fs.GetFromFile('no_file', skip_not_found=True)
2111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    # If the file doesn't exist, then the file system is not read.
2121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self.assertTrue(*mock_fs.CheckAndReset(read_count=1, stat_count=1))
2131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self.assertEqual(None, future.Get())
2141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self.assertTrue(*mock_fs.CheckAndReset(read_resolve_count=1))
2151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    future = compiled_fs.GetFromFile('no_file', skip_not_found=True)
2161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self.assertTrue(*mock_fs.CheckAndReset(stat_count=1))
2171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self.assertEqual(None, future.Get())
2181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    # The result for a non-existent file should still be cached.
2191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self.assertTrue(*mock_fs.CheckAndReset())
2201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    future = compiled_fs.GetFromFile('no_file')
2211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self.assertRaises(FileNotFoundError, future.Get)
2224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)if __name__ == '__main__':
225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  unittest.main()
226