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

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: address comments and discussions 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/sdk_io.dart';
15 import 'package:unittest/unittest.dart';
16
17 main() {
18 groupSep = ' | ';
19
20 group('CachingPubPackageMapProvider', () {
21 MemoryResourceProvider resProvider;
22 _MockPubListRunner mockRunner;
23 bool writeFileException;
24
25 Map result1 = {
26 'packages': {
27 'foo': '/tmp/proj1/packages/foo'
28 },
29 'input_files': ['/tmp/proj1/pubspec.yaml']
30 };
31
32 Map result1error = {
33 'input_files': ['/tmp/proj1/pubspec.lock']
34 };
35
36 Map result2 = {
37 'packages': {
38 'bar': '/tmp/proj2/packages/bar'
39 },
40 'input_files': ['/tmp/proj2/pubspec.yaml']
41 };
42
43 Folder newProj(Map result) {
44 Map packages = result['packages'];
45 packages.forEach((String name, String path) {
46 resProvider.newFolder(path);
47 });
48 List<String> inputFiles = result['input_files'];
49 for (String path in inputFiles) {
50 resProvider.newFile(path, '');
51 }
52 return resProvider.getResource(inputFiles[0]).parent;
53 }
54
55 int mockWriteFile(File cacheFile, String content) {
56 if (writeFileException) {
57 throw 'simulated write failure: $cacheFile';
58 }
59 if (!cacheFile.exists) {
60 resProvider.newFolder(cacheFile.parent.path);
61 resProvider.newFile(cacheFile.path, content);
62 } else {
63 resProvider.modifyFile(cacheFile.path, content);
64 }
65 Resource res = resProvider.getResource(cacheFile.path);
66 if (res is File) {
67 return res.createSource().modificationStamp;
68 }
69 throw 'expected file, but found $res';
70 }
71
72 CachingPubPackageMapProvider newPkgProvider() {
73 return new CachingPubPackageMapProvider(
74 resProvider,
75 DirectoryBasedDartSdk.defaultSdk,
76 mockRunner.runPubList,
77 mockWriteFile);
78 }
79
80 setUp(() {
81 resProvider = new MemoryResourceProvider();
82 resProvider.newFolder('/tmp/proj/packages/foo');
83 mockRunner = new _MockPubListRunner();
84 writeFileException = false;
85 });
86
87 group('computePackageMap', () {
88
89 // Assert pub list called once and results are cached in memory
90 test('cache memory', () {
91 expect(mockRunner.runCount, 0);
92
93 Folder folder1 = newProj(result1);
94 CachingPubPackageMapProvider pkgProvider = newPkgProvider();
95 mockRunner.nextResult = JSON.encode(result1);
96 PackageMapInfo info = pkgProvider.computePackageMap(folder1);
97 expect(mockRunner.runCount, 1);
98 _assertInfo(info, result1);
99
100 info = pkgProvider.computePackageMap(folder1);
101 expect(mockRunner.runCount, 1);
102 _assertInfo(info, result1);
103 });
104
105 // Assert pub list called once and results are cached on disk
106 test('cache disk', () {
107 expect(mockRunner.runCount, 0);
108
109 Folder folder1 = newProj(result1);
110 CachingPubPackageMapProvider pkgProvider1 = newPkgProvider();
111 mockRunner.nextResult = JSON.encode(result1);
112 PackageMapInfo info = pkgProvider1.computePackageMap(folder1);
113 expect(mockRunner.runCount, 1);
114 _assertInfo(info, result1);
115
116 CachingPubPackageMapProvider pkgProvider2 = newPkgProvider();
117 info = pkgProvider2.computePackageMap(folder1);
118 expect(mockRunner.runCount, 1);
119 _assertInfo(info, result1);
120 });
121
122 // Assert pub list called even if cache file is corrupted
123 test('corrupt cache file', () {
124 expect(mockRunner.runCount, 0);
125
126 Folder folder1 = newProj(result1);
127 CachingPubPackageMapProvider pkgProvider1 = newPkgProvider();
128 resProvider.newFile(pkgProvider1.cacheFile.path, 'corrupt content');
129 mockRunner.nextResult = JSON.encode(result1);
130 PackageMapInfo info = pkgProvider1.computePackageMap(folder1);
131 expect(mockRunner.runCount, 1);
132 _assertInfo(info, result1);
133
134 CachingPubPackageMapProvider pkgProvider2 = newPkgProvider();
135 info = pkgProvider2.computePackageMap(folder1);
136 expect(mockRunner.runCount, 1);
137 _assertInfo(info, result1);
138 });
139
140 // Assert gracefully continue even if write to file fails
141 test('failed write to cache file', () {
142 expect(mockRunner.runCount, 0);
143
144 Folder folder1 = newProj(result1);
145 CachingPubPackageMapProvider pkgProvider = newPkgProvider();
146 mockRunner.nextResult = JSON.encode(result1);
147 writeFileException = true;
148 PackageMapInfo info = pkgProvider.computePackageMap(folder1);
149 expect(mockRunner.runCount, 1);
150 _assertInfo(info, result1);
151
152 info = pkgProvider.computePackageMap(folder1);
153 expect(mockRunner.runCount, 1);
154 _assertInfo(info, result1);
155 });
156
157 // Assert modification in one shows up in the other
158 test('shared disk cache', () {
159 expect(mockRunner.runCount, 0);
160
161 Folder folder1 = newProj(result1);
162 CachingPubPackageMapProvider pkgProvider1 = newPkgProvider();
163 mockRunner.nextResult = JSON.encode(result1);
164 PackageMapInfo info = pkgProvider1.computePackageMap(folder1);
165 expect(mockRunner.runCount, 1);
166 _assertInfo(info, result1);
167
168 Folder folder2 = newProj(result2);
169 CachingPubPackageMapProvider pkgProvider2 = newPkgProvider();
170 mockRunner.nextResult = JSON.encode(result2);
171 info = pkgProvider2.computePackageMap(folder2);
172 expect(mockRunner.runCount, 2);
173 _assertInfo(info, result2);
174
175 info = pkgProvider1.computePackageMap(folder2);
176 expect(mockRunner.runCount, 2);
177 _assertInfo(info, result2);
178 });
179
180 // Assert pub list called again if input file modified
181 test('input file changed', () {
182 expect(mockRunner.runCount, 0);
183
184 Folder folder1 = newProj(result1);
185 CachingPubPackageMapProvider pkgProvider = newPkgProvider();
186 mockRunner.nextResult = JSON.encode(result1);
187 PackageMapInfo info = pkgProvider.computePackageMap(folder1);
188 expect(mockRunner.runCount, 1);
189 _assertInfo(info, result1);
190
191 resProvider.modifyFile(info.dependencies.first, 'new content');
192 mockRunner.nextResult = JSON.encode(result1);
193 info = pkgProvider.computePackageMap(folder1);
194 expect(mockRunner.runCount, 2);
195 _assertInfo(info, result1);
196 });
197
198 // Assert pub list called again if input file modified
199 // after reloading package provider cache from disk
200 test('input file changed 2', () {
201 expect(mockRunner.runCount, 0);
202
203 Folder folder1 = newProj(result1);
204 CachingPubPackageMapProvider pkgProvider1 = newPkgProvider();
205 mockRunner.nextResult = JSON.encode(result1);
206 PackageMapInfo info = pkgProvider1.computePackageMap(folder1);
207 expect(mockRunner.runCount, 1);
208 _assertInfo(info, result1);
209
210 resProvider.modifyFile(info.dependencies.first, 'new content');
211 mockRunner.nextResult = JSON.encode(result1);
212 CachingPubPackageMapProvider pkgProvider2 = newPkgProvider();
213 info = pkgProvider2.computePackageMap(folder1);
214 expect(mockRunner.runCount, 2);
215 _assertInfo(info, result1);
216 });
217
218 // Assert pub list called again if input file deleted
219 test('input file deleted', () {
220 expect(mockRunner.runCount, 0);
221
222 Folder folder1 = newProj(result1);
223 CachingPubPackageMapProvider pkgProvider = newPkgProvider();
224 mockRunner.nextResult = JSON.encode(result1);
225 PackageMapInfo info = pkgProvider.computePackageMap(folder1);
226 expect(mockRunner.runCount, 1);
227 _assertInfo(info, result1);
228
229 resProvider.deleteFile(info.dependencies.first);
230 mockRunner.nextResult = JSON.encode(result1);
231 info = pkgProvider.computePackageMap(folder1);
232 expect(mockRunner.runCount, 2);
233 _assertInfo(info, result1);
234 });
235
236 // Assert pub list not called if folder does not exist
237 // and returns same cached result if folder restored as before
238 test('project removed then restored', () {
239 expect(mockRunner.runCount, 0);
240
241 Folder folder1 = newProj(result1);
242 CachingPubPackageMapProvider pkgProvider = newPkgProvider();
243 mockRunner.nextResult = JSON.encode(result1);
244 PackageMapInfo info = pkgProvider.computePackageMap(folder1);
245 expect(mockRunner.runCount, 1);
246 _assertInfo(info, result1);
247
248 var restorePoint = resProvider.clear();
249 info = pkgProvider.computePackageMap(folder1);
250 expect(mockRunner.runCount, 1);
251 _assertError(info, result1error);
252
253 resProvider.restore(restorePoint);
254 info = pkgProvider.computePackageMap(folder1);
255 expect(mockRunner.runCount, 1);
256 _assertInfo(info, result1);
257 });
258
259 // Assert pub list *is* run again
260 // if dependency has changed during execution
261 test('dependency changed during execution', () {
262 expect(mockRunner.runCount, 0);
263
264 Folder folder1 = newProj(result1);
265 Resource pubspecFile = folder1.getChild('pubspec.yaml');
266 expect(pubspecFile.exists, isTrue);
267 CachingPubPackageMapProvider pkgProvider = newPkgProvider();
268 mockRunner.nextResultFunction = () {
269 resProvider.modifyFile(pubspecFile.path, 'new content');
270 return JSON.encode(result1);
271 };
272 mockRunner.nextResult = JSON.encode(result1);
273 PackageMapInfo info = pkgProvider.computePackageMap(folder1);
274 expect(mockRunner.runCount, 2);
275 _assertInfo(info, result1);
276 });
277 });
278 });
279 }
280
281 _assertError(PackageMapInfo info, Map expected) {
282 expect(info.packageMap, isNull);
283 List<String> expectedFiles = expected['input_files'];
284 expect(info.dependencies, hasLength(expectedFiles.length));
285 for (String path in expectedFiles) {
286 expect(info.dependencies, contains(path));
287 }
288 }
289
290 _assertInfo(PackageMapInfo info, Map expected) {
291 Map<String, String> expectedPackages = expected['packages'];
292 expect(info.packageMap, hasLength(expectedPackages.length));
293 for (String key in expectedPackages.keys) {
294 List<Folder> packageList = info.packageMap[key];
295 expect(packageList, hasLength(1));
296 expect(packageList[0].path, expectedPackages[key]);
297 }
298 List<String> expectedFiles = expected['input_files'];
299 expect(info.dependencies, hasLength(expectedFiles.length));
300 for (String path in expectedFiles) {
301 expect(info.dependencies, contains(path));
302 }
303 }
304
305 typedef String MockResultFunction();
306
307 /**
308 * Mock for simulating and tracking execution of pub list
309 */
310 class _MockPubListRunner {
311 int runCount = 0;
312 List nextResults = [];
313
314 void set nextResult(String result) {
315 nextResults.add(result);
316 }
317
318 void set nextResultFunction(MockResultFunction resultFunction) {
319 nextResults.add(resultFunction);
320 }
321
322 io.ProcessResult runPubList(Folder folder) {
323 if (nextResults.isEmpty) {
324 throw 'missing nextResult';
325 }
326 var result = nextResults.removeAt(0);
327 if (result is MockResultFunction) {
328 result = result();
329 }
330 ++runCount;
331 return new _MockResult(result);
332 }
333 }
334
335 class _MockResult implements io.ProcessResult {
336 String result;
337
338 _MockResult(this.result);
339
340 @override
341 int get exitCode => 0;
342
343 // TODO: implement stdout
344 @override
345 get stdout => result;
346
347 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
348 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698