Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(481)

Side by Side Diff: chrome/common/extensions/docs/server2/test_file_system.py

Issue 151883009: Docserver: Make MockFileSystem not iterate over the entire file system as part (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 8
9 def MoveTo(base, obj): 9 def MoveTo(base, obj):
10 '''Returns an object as |obj| moved to |base|. That is, 10 '''Returns an object as |obj| moved to |base|. That is,
(...skipping 10 matching lines...) Expand all
21 21
22 def MoveAllTo(base, obj): 22 def MoveAllTo(base, obj):
23 '''Moves every value in |obj| to |base|. See MoveTo. 23 '''Moves every value in |obj| to |base|. See MoveTo.
24 ''' 24 '''
25 result = {} 25 result = {}
26 for key, value in obj.iteritems(): 26 for key, value in obj.iteritems():
27 result[key] = MoveTo(base, value) 27 result[key] = MoveTo(base, value)
28 return result 28 return result
29 29
30 30
31 def _List(file_system):
32 '''Returns a list of '/' separated paths derived from |file_system|.
33 For example, {'index.html': '', 'www': {'file.txt': ''}} would return
34 ['index.html', 'www/file.txt'].
35 '''
36 assert isinstance(file_system, dict)
37 result = {}
38 def update_result(item, path):
39 if isinstance(item, dict):
40 if path != '':
41 path += '/'
42 file_listing = [p if isinstance(content, basestring) else (p + '/')
43 for p, content in item.iteritems()]
44 # Support non-canonical paths until the server has purged all
Yoyo Zhou 2014/02/05 00:32:33 Sounds like there's a TODO in here.
not at google - send to devlin 2014/02/05 03:55:53 Done.
45 # non-canonical paths.
46 result[path], result['/' + path] = file_listing, file_listing
47 for subpath, subitem in item.iteritems():
48 update_result(subitem, path + subpath)
49 elif isinstance(item, basestring):
50 result[path] = item
51 # See above comment.
52 result['/' + path] = result[path]
Yoyo Zhou 2014/02/05 00:32:33 nit: this is written differently from the above
not at google - send to devlin 2014/02/05 03:55:53 Done.
53 else:
54 raise ValueError('Unsupported item type: %s' % type(item))
55 update_result(file_system, '')
56 return result
57
58
59 class _StatTracker(object):
60 '''Maintains the versions of paths in a file system. The versions of files
61 are changed either by |Increment| or |SetVersion|. The versions of
62 directories are derived from the versions of files within it.
63 '''
64
65 def __init__(self):
66 self._path_stats = {}
67 self._global_stat = 0
68
69 def Increment(self, path=None, by=1):
70 if path is None:
71 self._global_stat += by
72 else:
73 self.SetVersion(path, self._path_stats.get(path, 0) + by)
74
75 def SetVersion(self, path, new_version):
76 if path == '' or path.endswith('/'):
Yoyo Zhou 2014/02/05 00:32:33 path_util.IsDirectory
not at google - send to devlin 2014/02/05 03:55:53 Ah! Yeah so I did this and in fact it mooted the T
77 raise ValueError('Only files have an incrementable stat, '
78 'but "%s" is a directory' % path)
79
80 # Update version of that file.
81 self._path_stats[path] = new_version
82
83 # Update all parent directory versions as well.
84 slash_index = 0 # (deliberately including '' in the dir paths)
85 while slash_index != -1:
86 dir_path = path[:slash_index] + '/'
87 self._path_stats[dir_path] = max(self._path_stats.get(dir_path, 0),
88 new_version)
89 if dir_path == '/':
90 # Legacy support for '/' being the root of the file system rather
91 # than ''. Eventually when the path normalisation logic is complete
92 # this will be impossible and this logic will change slightly.
93 self._path_stats[''] = self._path_stats['/']
94 slash_index = path.find('/', slash_index + 1)
95
96 def GetVersion(self, path):
97 return self._global_stat + self._path_stats.get(path, 0)
98
99
31 class TestFileSystem(FileSystem): 100 class TestFileSystem(FileSystem):
32 '''A FileSystem backed by an object. Create with an object representing file 101 '''A FileSystem backed by an object. Create with an object representing file
33 paths such that {'a': {'b': 'hello'}} will resolve Read('a/b') as 'hello', 102 paths such that {'a': {'b': 'hello'}} will resolve Read('a/b') as 'hello',
34 Read('a/') as ['b'], and Stat determined by a value incremented via 103 Read('a/') as ['b'], and Stat determined by a value incremented via
35 IncrementStat. 104 IncrementStat.
36 ''' 105 '''
37 106
38 def __init__(self, obj, relative_to=None, identity=None): 107 def __init__(self, obj, relative_to=None, identity=None):
39 assert obj is not None 108 assert obj is not None
40 self._obj = obj if relative_to is None else MoveTo(relative_to, obj) 109 if relative_to is not None:
110 obj = MoveTo(relative_to, obj)
41 self._identity = identity or type(self).__name__ 111 self._identity = identity or type(self).__name__
42 self._path_stats = {} 112 self._path_values = _List(obj)
43 self._global_stat = 0 113 self._stat_tracker = _StatTracker()
44 114
45 # 115 #
46 # FileSystem implementation. 116 # FileSystem implementation.
47 # 117 #
48 118
49 def Read(self, paths): 119 def Read(self, paths):
50 test_fs = self 120 for path in paths:
51 class Delegate(object): 121 if path not in self._path_values:
52 def Get(self): 122 return FileNotFoundError.RaiseInFuture(path)
53 return dict((path, test_fs._ResolvePath(path)) for path in paths) 123 return Future(value=dict((k, v) for k, v in self._path_values.iteritems()
54 return Future(delegate=Delegate()) 124 if k in paths))
55 125
56 def Refresh(self): 126 def Refresh(self):
57 return Future(value=()) 127 return Future(value=())
58 128
59 def _ResolvePath(self, path):
60 def Resolve(parts):
61 '''Resolves |parts| of a path info |self._obj|.
62 '''
63 result = self._obj.get(parts[0])
64 for part in parts[1:]:
65 if not isinstance(result, dict):
66 raise FileNotFoundError(
67 '%s at %s did not resolve to a dict, instead %s' %
68 (path, part, result))
69 result = result.get(part)
70 return result
71
72 def GetPaths(obj):
73 '''Lists the paths within |obj|; this is basially keys() but with
74 directory paths (i.e. dicts) with a trailing /.
75 '''
76 def ToPath(k, v):
77 if isinstance(v, basestring):
78 return k
79 if isinstance(v, dict):
80 return '%s/' % k
81 raise ValueError('Cannot convert type %s to path', type(v))
82 return [ToPath(k, v) for k, v in obj.items()]
83
84 path = path.lstrip('/')
85
86 if path == '':
87 return GetPaths(self._obj)
88
89 parts = path.split('/')
90 if parts[-1] != '':
91 file_contents = Resolve(parts)
92 if not isinstance(file_contents, basestring):
93 raise FileNotFoundError(
94 '%s (%s) did not resolve to a string, instead %s' %
95 (path, parts, file_contents))
96 return file_contents
97
98 dir_contents = Resolve(parts[:-1])
99 if not isinstance(dir_contents, dict):
100 raise FileNotFoundError(
101 '%s (%s) did not resolve to a dict, instead %s' %
102 (path, parts, dir_contents))
103
104 return GetPaths(dir_contents)
105
106 def Stat(self, path): 129 def Stat(self, path):
107 read_result = self.Read([path]).Get().get(path) 130 read_result = self.ReadSingle(path).Get()
108 stat_result = StatInfo(self._SinglePathStat(path)) 131 stat_result = StatInfo(str(self._stat_tracker.GetVersion(path)))
109 if isinstance(read_result, list): 132 if isinstance(read_result, list):
110 stat_result.child_versions = dict( 133 stat_result.child_versions = dict(
111 (file_result, self._SinglePathStat('%s%s' % (path, file_result))) 134 (file_result,
135 str(self._stat_tracker.GetVersion('%s%s' % (path, file_result))))
112 for file_result in read_result) 136 for file_result in read_result)
113 return stat_result 137 return stat_result
114 138
115 def _SinglePathStat(self, path):
116 return str(self._global_stat + self._path_stats.get(path, 0))
117
118 # 139 #
119 # Testing methods. 140 # Testing methods.
120 # 141 #
121 142
122 def IncrementStat(self, path=None, by=1): 143 def IncrementStat(self, path=None, by=1):
123 if path is not None: 144 self._stat_tracker.Increment(path, by=by)
124 self._path_stats[path] = self._path_stats.get(path, 0) + by
125 else:
126 self._global_stat += by
127 145
128 def GetIdentity(self): 146 def GetIdentity(self):
129 return self._identity 147 return self._identity
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698