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

Side by Side Diff: pkg/analysis_server/test/source/caching_put_package_map_provider_test.dart

Issue 941883002: cache pub list results (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: merge Created 5 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
(Empty)
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 library test.source.caching_pub_package_map_provider;
6
7 import 'dart:convert';
8 import 'dart:io' as io;
9
10 import 'package:analysis_server/src/source/caching_pub_package_map_provider.dart ';
11 import 'package:analyzer/file_system/file_system.dart';
12 import 'package:analyzer/file_system/memory_file_system.dart';
13 import 'package:analyzer/source/package_map_provider.dart';
14 import 'package:analyzer/src/generated/engine.dart';
15 import 'package:analyzer/src/generated/sdk_io.dart';
16 import 'package:unittest/unittest.dart';
17
18 main() {
19 groupSep = ' | ';
20
21 group('CachingPubPackageMapProvider', () {
22 MemoryResourceProvider resProvider;
23 _MockPubListRunner mockRunner;
24 bool writeFileException;
25
26 Map result1 = {
27 'packages': {
28 'foo': '/tmp/proj1/packages/foo'
29 },
30 'input_files': ['/tmp/proj1/pubspec.yaml']
31 };
32
33 Map result1error = {
34 'input_files': ['/tmp/proj1/pubspec.lock']
35 };
36
37 Map result2 = {
38 'packages': {
39 'bar': '/tmp/proj2/packages/bar'
40 },
41 'input_files': ['/tmp/proj2/pubspec.yaml']
42 };
43
44 Folder newProj(Map result) {
45 Map packages = result['packages'];
46 packages.forEach((String name, String path) {
47 resProvider.newFolder(path);
48 });
49 List<String> inputFiles = result['input_files'];
50 for (String path in inputFiles) {
51 resProvider.newFile(path, '');
52 }
53 return resProvider.getResource(inputFiles[0]).parent;
54 }
55
56 int mockWriteFile(File cacheFile, String content) {
57 if (writeFileException) {
58 throw 'simulated write failure: $cacheFile';
59 }
60 if (!cacheFile.exists) {
61 resProvider.newFolder(cacheFile.parent.path);
62 resProvider.newFile(cacheFile.path, content);
63 } else {
64 resProvider.modifyFile(cacheFile.path, content);
65 }
66 Resource res = resProvider.getResource(cacheFile.path);
67 if (res is File) {
68 return res.createSource().modificationStamp;
69 }
70 throw 'expected file, but found $res';
71 }
72
73 CachingPubPackageMapProvider newPkgProvider() {
74 return new CachingPubPackageMapProvider(
75 resProvider,
76 DirectoryBasedDartSdk.defaultSdk,
77 mockRunner.runPubList,
78 mockWriteFile);
79 }
80
81 setUp(() {
82 resProvider = new MemoryResourceProvider();
83 resProvider.newFolder('/tmp/proj/packages/foo');
84 mockRunner = new _MockPubListRunner();
85 writeFileException = false;
86 });
87
88 group('computePackageMap', () {
89
90 // Assert pub list called once and results are cached in memory
91 test('cache memory', () {
92 expect(mockRunner.runCount, 0);
93
94 Folder folder1 = newProj(result1);
95 CachingPubPackageMapProvider pkgProvider = newPkgProvider();
96 mockRunner.nextResult = JSON.encode(result1);
97 PackageMapInfo info = pkgProvider.computePackageMap(folder1);
98 expect(mockRunner.runCount, 1);
99 _assertInfo(info, result1);
100
101 info = pkgProvider.computePackageMap(folder1);
102 expect(mockRunner.runCount, 1);
103 _assertInfo(info, result1);
104 });
105
106 // Assert pub list called once and results are cached on disk
107 test('cache disk', () {
108 expect(mockRunner.runCount, 0);
109
110 Folder folder1 = newProj(result1);
111 CachingPubPackageMapProvider pkgProvider1 = newPkgProvider();
112 mockRunner.nextResult = JSON.encode(result1);
113 PackageMapInfo info = pkgProvider1.computePackageMap(folder1);
114 expect(mockRunner.runCount, 1);
115 _assertInfo(info, result1);
116
117 CachingPubPackageMapProvider pkgProvider2 = newPkgProvider();
118 info = pkgProvider2.computePackageMap(folder1);
119 expect(mockRunner.runCount, 1);
120 _assertInfo(info, result1);
121 });
122
123 // Assert pub list called even if cache file is corrupted
124 test('corrupt cache file', () {
125 expect(mockRunner.runCount, 0);
126
127 Folder folder1 = newProj(result1);
128 CachingPubPackageMapProvider pkgProvider1 = newPkgProvider();
129 resProvider.newFile(pkgProvider1.cacheFile.path, 'corrupt content');
130 mockRunner.nextResult = JSON.encode(result1);
131 PackageMapInfo info = pkgProvider1.computePackageMap(folder1);
132 expect(mockRunner.runCount, 1);
133 _assertInfo(info, result1);
134
135 CachingPubPackageMapProvider pkgProvider2 = newPkgProvider();
136 info = pkgProvider2.computePackageMap(folder1);
137 expect(mockRunner.runCount, 1);
138 _assertInfo(info, result1);
139 });
140
141 // Assert gracefully continue even if write to file fails
142 test('failed write to cache file', () {
143 expect(mockRunner.runCount, 0);
144
145 Folder folder1 = newProj(result1);
146 CachingPubPackageMapProvider pkgProvider = newPkgProvider();
147 mockRunner.nextResult = JSON.encode(result1);
148 writeFileException = true;
149 PackageMapInfo info = pkgProvider.computePackageMap(folder1);
150 expect(mockRunner.runCount, 1);
151 _assertInfo(info, result1);
152
153 info = pkgProvider.computePackageMap(folder1);
154 expect(mockRunner.runCount, 1);
155 _assertInfo(info, result1);
156 });
157
158 // Assert modification in one shows up in the other
159 test('shared disk cache', () {
160 expect(mockRunner.runCount, 0);
161
162 Folder folder1 = newProj(result1);
163 CachingPubPackageMapProvider pkgProvider1 = newPkgProvider();
164 mockRunner.nextResult = JSON.encode(result1);
165 PackageMapInfo info = pkgProvider1.computePackageMap(folder1);
166 expect(mockRunner.runCount, 1);
167 _assertInfo(info, result1);
168
169 Folder folder2 = newProj(result2);
170 CachingPubPackageMapProvider pkgProvider2 = newPkgProvider();
171 mockRunner.nextResult = JSON.encode(result2);
172 info = pkgProvider2.computePackageMap(folder2);
173 expect(mockRunner.runCount, 2);
174 _assertInfo(info, result2);
175
176 info = pkgProvider1.computePackageMap(folder2);
177 expect(mockRunner.runCount, 2);
178 _assertInfo(info, result2);
179 });
180
181 // Assert pub list called again if input file modified
182 test('input file changed', () {
183 expect(mockRunner.runCount, 0);
184
185 Folder folder1 = newProj(result1);
186 CachingPubPackageMapProvider pkgProvider = newPkgProvider();
187 mockRunner.nextResult = JSON.encode(result1);
188 PackageMapInfo info = pkgProvider.computePackageMap(folder1);
189 expect(mockRunner.runCount, 1);
190 _assertInfo(info, result1);
191
192 resProvider.modifyFile(info.dependencies.first, 'new content');
193 mockRunner.nextResult = JSON.encode(result1);
194 info = pkgProvider.computePackageMap(folder1);
195 expect(mockRunner.runCount, 2);
196 _assertInfo(info, result1);
197 });
198
199 // Assert pub list called again if input file modified
200 // after reloading package provider cache from disk
201 test('input file changed 2', () {
202 expect(mockRunner.runCount, 0);
203
204 Folder folder1 = newProj(result1);
205 CachingPubPackageMapProvider pkgProvider1 = newPkgProvider();
206 mockRunner.nextResult = JSON.encode(result1);
207 PackageMapInfo info = pkgProvider1.computePackageMap(folder1);
208 expect(mockRunner.runCount, 1);
209 _assertInfo(info, result1);
210
211 resProvider.modifyFile(info.dependencies.first, 'new content');
212 mockRunner.nextResult = JSON.encode(result1);
213 CachingPubPackageMapProvider pkgProvider2 = newPkgProvider();
214 info = pkgProvider2.computePackageMap(folder1);
215 expect(mockRunner.runCount, 2);
216 _assertInfo(info, result1);
217 });
218
219 // Assert pub list called again if input file deleted
220 test('input file deleted', () {
221 expect(mockRunner.runCount, 0);
222
223 Folder folder1 = newProj(result1);
224 CachingPubPackageMapProvider pkgProvider = newPkgProvider();
225 mockRunner.nextResult = JSON.encode(result1);
226 PackageMapInfo info = pkgProvider.computePackageMap(folder1);
227 expect(mockRunner.runCount, 1);
228 _assertInfo(info, result1);
229
230 resProvider.deleteFile(info.dependencies.first);
231 mockRunner.nextResult = JSON.encode(result1);
232 info = pkgProvider.computePackageMap(folder1);
233 expect(mockRunner.runCount, 2);
234 _assertInfo(info, result1);
235 });
236
237 // Assert pub list not called if folder does not exist
238 // and returns same cached result if folder restored as before
239 test('project removed then restored', () {
240 expect(mockRunner.runCount, 0);
241
242 Folder folder1 = newProj(result1);
243 CachingPubPackageMapProvider pkgProvider = newPkgProvider();
244 mockRunner.nextResult = JSON.encode(result1);
245 PackageMapInfo info = pkgProvider.computePackageMap(folder1);
246 expect(mockRunner.runCount, 1);
247 _assertInfo(info, result1);
248
249 _RestorePoint restorePoint = new _RestorePoint(resProvider, folder1);
250 resProvider.deleteFolder(folder1.path);
251 info = pkgProvider.computePackageMap(folder1);
252 expect(mockRunner.runCount, 1);
253 _assertError(info, result1error);
254
255 restorePoint.restore();
256 info = pkgProvider.computePackageMap(folder1);
257 expect(mockRunner.runCount, 1);
258 _assertInfo(info, result1);
259 });
260
261 // Assert pub list *is* run again
262 // if dependency has changed during execution
263 test('dependency changed during execution', () {
264 expect(mockRunner.runCount, 0);
265
266 Folder folder1 = newProj(result1);
267 Resource pubspecFile = folder1.getChild('pubspec.yaml');
268 expect(pubspecFile.exists, isTrue);
269 CachingPubPackageMapProvider pkgProvider = newPkgProvider();
270 mockRunner.nextResultFunction = () {
271 resProvider.modifyFile(pubspecFile.path, 'new content');
272 return JSON.encode(result1);
273 };
274 mockRunner.nextResult = JSON.encode(result1);
275 PackageMapInfo info = pkgProvider.computePackageMap(folder1);
276 expect(mockRunner.runCount, 2);
277 _assertInfo(info, result1);
278 });
279 });
280 });
281 }
282
283 _assertError(PackageMapInfo info, Map expected) {
284 expect(info.packageMap, isNull);
285 List<String> expectedFiles = expected['input_files'];
286 expect(info.dependencies, hasLength(expectedFiles.length));
287 for (String path in expectedFiles) {
288 expect(info.dependencies, contains(path));
289 }
290 }
291
292 _assertInfo(PackageMapInfo info, Map expected) {
293 Map<String, String> expectedPackages = expected['packages'];
294 expect(info.packageMap, hasLength(expectedPackages.length));
295 for (String key in expectedPackages.keys) {
296 List<Folder> packageList = info.packageMap[key];
297 expect(packageList, hasLength(1));
298 expect(packageList[0].path, expectedPackages[key]);
299 }
300 List<String> expectedFiles = expected['input_files'];
301 expect(info.dependencies, hasLength(expectedFiles.length));
302 for (String path in expectedFiles) {
303 expect(info.dependencies, contains(path));
304 }
305 }
306
307
308 typedef String MockResultFunction();
309
310 /**
311 * Mock for simulating and tracking execution of pub list
312 */
313 class _MockPubListRunner {
314 int runCount = 0;
315 List nextResults = [];
316
317 void set nextResult(String result) {
318 nextResults.add(result);
319 }
320
321 void set nextResultFunction(MockResultFunction resultFunction) {
322 nextResults.add(resultFunction);
323 }
324
325 io.ProcessResult runPubList(Folder folder) {
326 if (nextResults.isEmpty) {
327 throw 'missing nextResult';
328 }
329 var result = nextResults.removeAt(0);
330 if (result is MockResultFunction) {
331 result = result();
332 }
333 ++runCount;
334 return new _MockResult(result);
335 }
336 }
337
338 class _MockResult implements io.ProcessResult {
339 String result;
340
341 _MockResult(this.result);
342
343 @override
344 int get exitCode => 0;
345
346 // TODO: implement stdout
347 @override
348 get stdout => result;
349
350 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
351 }
352
353 /**
354 * An object containing information to restore the state of a deleted
355 * folder and its content.
356 */
357 class _RestorePoint {
358 final MemoryResourceProvider provider;
359 final List<String> _folderPaths = <String>[];
360 final List<String> _filePaths = <String>[];
361 final List<TimestampedData> _fileContents = <TimestampedData>[];
362
363 /**
364 * Construct a new instance that captures the current state of the folder
365 * and all of its contained files and folders.
366 */
367 _RestorePoint(this.provider, Folder folder) {
368 record(folder);
369 }
370
371 /**
372 * Capture the current state of the folder
373 * and all of its contained files and folders.
374 */
375 void record(Folder folder) {
376 _folderPaths.add(folder.path);
377 for (Resource child in folder.getChildren()) {
378 if (child is Folder) {
379 record(child);
380 } else if (child is File) {
381 _filePaths.add(child.path);
382 _fileContents.add(child.createSource().contents);
383 } else {
384 throw 'unknown resource: $child';
385 }
386 }
387 }
388
389 /**
390 * Restore the original files and folders.
391 */
392 void restore() {
393 for (String path in _folderPaths) {
394 provider.newFolder(path);
395 }
396 int fileCount = _filePaths.length;
397 for (int fileIndex = 0; fileIndex < fileCount; ++fileIndex) {
398 String path = _filePaths[fileIndex];
399 TimestampedData content = _fileContents[fileIndex];
400 provider.newFile(path, content.data, content.modificationTime);
401 }
402 }
403 }
OLDNEW
« no previous file with comments | « pkg/analysis_server/test/context_manager_test.dart ('k') | pkg/analysis_server/test/source/test_all.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698