| OLD | NEW |
| 1 # Copyright 2013 The Chromium Authors. All rights reserved. | 1 # Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 from file_system import FileSystem, FileNotFoundError, StatInfo | 5 from file_system import FileSystem, FileNotFoundError, StatInfo |
| 6 from future import Future | 6 from future import Future |
| 7 | 7 |
| 8 class TestFileSystem(FileSystem): | 8 class TestFileSystem(FileSystem): |
| 9 '''A FileSystem backed by an object. Create with an object representing file | 9 '''A FileSystem backed by an object. Create with an object representing file |
| 10 paths such that {'a': {'b': 'hello'}} will resolve Read('a/b') as 'hello', | 10 paths such that {'a': {'b': 'hello'}} will resolve Read('a/b') as 'hello', |
| 11 Read('a/') as ['b'], and Stat determined by a value incremented via | 11 Read('a/') as ['b'], and Stat determined by a value incremented via |
| 12 IncrementStat. | 12 IncrementStat. |
| 13 ''' | 13 ''' |
| 14 |
| 15 # TODO(kalman): this method would be unnecessary if we injected paths properly |
| 16 # in ServerInstance. |
| 17 @staticmethod |
| 18 def MoveTo(base, obj): |
| 19 '''Returns an object as |obj| moved to |prefix|. That is, |
| 20 MoveTo('foo/bar', {'a': 'b'}) -> {'foo': {'bar': {'a': 'b'}}} |
| 21 ''' |
| 22 result = {} |
| 23 leaf = result |
| 24 for k in base.split('/'): |
| 25 leaf[k] = {} |
| 26 leaf = leaf[k] |
| 27 leaf.update(obj) |
| 28 return result |
| 29 |
| 14 def __init__(self, obj): | 30 def __init__(self, obj): |
| 15 self._obj = obj | 31 self._obj = obj |
| 16 self._stat = 0 | 32 self._global_stat = 0 |
| 33 self._path_stats = {} |
| 34 self._read_count = 0 |
| 35 self._stat_count = 0 |
| 36 |
| 37 # |
| 38 # FileSystem implementation. |
| 39 # |
| 17 | 40 |
| 18 def Read(self, paths, binary=False): | 41 def Read(self, paths, binary=False): |
| 42 self._read_count += 1 |
| 43 return self._ReadImpl(paths, binary=binary) |
| 44 |
| 45 def _ReadImpl(self, paths, binary=False): |
| 19 try: | 46 try: |
| 20 result = {} | 47 result = {} |
| 21 for path in paths: | 48 for path in paths: |
| 22 result[path] = self._ResolvePath(path) | 49 result[path] = self._ResolvePath(path) |
| 23 return Future(value=result) | 50 return Future(value=result) |
| 24 except FileNotFoundError as error: | 51 except FileNotFoundError as error: |
| 25 return Future(error=error) | 52 return Future(error=error) |
| 26 | 53 |
| 27 def _ResolvePath(self, path): | 54 def _ResolvePath(self, path): |
| 28 def Resolve(parts): | 55 def Resolve(parts): |
| (...skipping 10 matching lines...) Expand all Loading... |
| 39 | 66 |
| 40 def GetPaths(obj): | 67 def GetPaths(obj): |
| 41 '''Lists the paths within |obj|; this is basially keys() but with | 68 '''Lists the paths within |obj|; this is basially keys() but with |
| 42 directory paths (i.e. dicts) with a trailing /. | 69 directory paths (i.e. dicts) with a trailing /. |
| 43 ''' | 70 ''' |
| 44 def ToPath(k, v): | 71 def ToPath(k, v): |
| 45 if isinstance(v, basestring): | 72 if isinstance(v, basestring): |
| 46 return k | 73 return k |
| 47 if isinstance(v, dict): | 74 if isinstance(v, dict): |
| 48 return '%s/' % k | 75 return '%s/' % k |
| 49 raise ValueError('Cannot convert type % to path', type(v)) | 76 raise ValueError('Cannot convert type %s to path', type(v)) |
| 50 return [ToPath(k, v) for k, v in obj.items()] | 77 return [ToPath(k, v) for k, v in obj.items()] |
| 51 | 78 |
| 52 path = path.lstrip('/') | 79 path = path.lstrip('/') |
| 53 | 80 |
| 54 if path == '': | 81 if path == '': |
| 55 return GetPaths(self._obj) | 82 return GetPaths(self._obj) |
| 56 | 83 |
| 57 parts = path.split('/') | 84 parts = path.split('/') |
| 58 if parts[-1] != '': | 85 if parts[-1] != '': |
| 59 file_contents = Resolve(parts) | 86 file_contents = Resolve(parts) |
| 60 if not isinstance(file_contents, basestring): | 87 if not isinstance(file_contents, basestring): |
| 61 raise FileNotFoundError( | 88 raise FileNotFoundError( |
| 62 '%s (%s) did not resolve to a string, instead %s' % | 89 '%s (%s) did not resolve to a string, instead %s' % |
| 63 (path, parts, file_contents)) | 90 (path, parts, file_contents)) |
| 64 return file_contents | 91 return file_contents |
| 65 | 92 |
| 66 dir_contents = Resolve(parts[:-1]) | 93 dir_contents = Resolve(parts[:-1]) |
| 67 if not isinstance(dir_contents, dict): | 94 if not isinstance(dir_contents, dict): |
| 68 raise FileNotFoundError( | 95 raise FileNotFoundError( |
| 69 '%s (%s) did not resolve to a dict, instead %s' % | 96 '%s (%s) did not resolve to a dict, instead %s' % |
| 70 (path, parts, dir_contents)) | 97 (path, parts, dir_contents)) |
| 71 | 98 |
| 72 return GetPaths(dir_contents) | 99 return GetPaths(dir_contents) |
| 73 | 100 |
| 74 def Stat(self, path): | 101 def Stat(self, path): |
| 75 read_result = self.ReadSingle(path) | 102 self._stat_count += 1 |
| 76 stat_result = StatInfo(str(self._stat)) | 103 return self._StatImpl(path) |
| 104 |
| 105 def _StatImpl(self, path): |
| 106 read_result = self._ReadImpl([path]).Get()[path] |
| 107 stat_result = StatInfo(self._SinglePathStat(path)) |
| 77 if isinstance(read_result, list): | 108 if isinstance(read_result, list): |
| 78 stat_result.child_versions = dict((file_result, str(self._stat)) | 109 stat_result.child_versions = dict( |
| 79 for file_result in read_result) | 110 (file_result, self._SinglePathStat('%s%s' % (path, file_result))) |
| 111 for file_result in read_result) |
| 80 return stat_result | 112 return stat_result |
| 81 | 113 |
| 82 def IncrementStat(self): | 114 def _SinglePathStat(self, path): |
| 83 self._stat += 1 | 115 return str(self._global_stat + self._path_stats.get(path, 0)) |
| 116 |
| 117 # |
| 118 # Testing methods. |
| 119 # |
| 120 |
| 121 def IncrementStat(self, path=None): |
| 122 if path is not None: |
| 123 self._path_stats[path] = self._path_stats.get(path, 0) + 1 |
| 124 else: |
| 125 self._global_stat += 1 |
| 126 |
| 127 def CheckAndReset(self, stat_count=0, read_count=0): |
| 128 try: |
| 129 return (self._read_count == read_count and |
| 130 self._stat_count == stat_count) |
| 131 finally: |
| 132 self._read_count = 0 |
| 133 self._stat_count = 0 |
| OLD | NEW |