blob: cd166b593a628d5cbc8c6479fbc4cd605253d081 [file] [log] [blame]
Greg Spencerf00c9022017-12-15 15:01:30 -08001// Copyright 2017 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Greg Spencerdf791272018-02-07 12:21:14 -08005import 'dart:async';
Greg Spencer8a2df392018-02-06 15:32:19 -08006import 'dart:convert';
7import 'dart:io' hide Platform;
Greg Spencerdf791272018-02-07 12:21:14 -08008import 'dart:typed_data';
Greg Spencerf00c9022017-12-15 15:01:30 -08009
10import 'package:mockito/mockito.dart';
11import 'package:test/test.dart';
12import 'package:path/path.dart' as path;
Greg Spencer8a2df392018-02-06 15:32:19 -080013import 'package:platform/platform.dart' show FakePlatform;
Greg Spencerf00c9022017-12-15 15:01:30 -080014
15import '../prepare_package.dart';
Greg Spencer8a2df392018-02-06 15:32:19 -080016import 'fake_process_manager.dart';
Greg Spencerf00c9022017-12-15 15:01:30 -080017
18void main() {
Alexandre Ardhuin7667db62018-03-14 06:24:49 +010019 const String testRef = 'deadbeefdeadbeefdeadbeefdeadbeefdeadbeef';
Greg Spencer984a24c2018-03-09 18:58:41 -080020 test('Throws on missing executable', () async {
21 // Uses a *real* process manager, since we want to know what happens if
22 // it can't find an executable.
23 final ProcessRunner processRunner = new ProcessRunner(subprocessOutput: false);
24 expect(
25 expectAsync1((List<String> commandLine) async {
26 return processRunner.runProcess(commandLine);
27 })(<String>['this_executable_better_not_exist_2857632534321']),
28 throwsA(const isInstanceOf<ProcessRunnerException>()));
29 try {
30 await processRunner.runProcess(<String>['this_executable_better_not_exist_2857632534321']);
31 } on ProcessRunnerException catch (e) {
32 expect(
33 e.message,
34 contains('Invalid argument(s): Cannot find executable for this_executable_better_not_exist_2857632534321.'),
35 );
36 }
37 });
Greg Spencer8a2df392018-02-06 15:32:19 -080038 for (String platformName in <String>['macos', 'linux', 'windows']) {
39 final FakePlatform platform = new FakePlatform(
40 operatingSystem: platformName,
41 environment: <String, String>{},
42 );
Greg Spencerdf791272018-02-07 12:21:14 -080043 group('ProcessRunner for $platform', () {
Greg Spencerdf791272018-02-07 12:21:14 -080044 test('Returns stdout', () async {
45 final FakeProcessManager fakeProcessManager = new FakeProcessManager();
46 fakeProcessManager.fakeResults = <String, List<ProcessResult>>{
47 'echo test': <ProcessResult>[new ProcessResult(0, 0, 'output', 'error')],
48 };
49 final ProcessRunner processRunner = new ProcessRunner(
50 subprocessOutput: false, platform: platform, processManager: fakeProcessManager);
51 final String output = await processRunner.runProcess(<String>['echo', 'test']);
52 expect(output, equals('output'));
53 });
54 test('Throws on process failure', () async {
55 final FakeProcessManager fakeProcessManager = new FakeProcessManager();
56 fakeProcessManager.fakeResults = <String, List<ProcessResult>>{
57 'echo test': <ProcessResult>[new ProcessResult(0, -1, 'output', 'error')],
58 };
59 final ProcessRunner processRunner = new ProcessRunner(
60 subprocessOutput: false, platform: platform, processManager: fakeProcessManager);
61 expect(
62 expectAsync1((List<String> commandLine) async {
63 return processRunner.runProcess(commandLine);
64 })(<String>['echo', 'test']),
65 throwsA(const isInstanceOf<ProcessRunnerException>()));
66 });
67 });
Greg Spencer8a2df392018-02-06 15:32:19 -080068 group('ArchiveCreator for $platformName', () {
69 ArchiveCreator creator;
70 Directory tmpDir;
71 Directory flutterDir;
72 FakeProcessManager processManager;
73 final List<List<String>> args = <List<String>>[];
74 final List<Map<Symbol, dynamic>> namedArgs = <Map<Symbol, dynamic>>[];
75 String flutter;
Greg Spencerf00c9022017-12-15 15:01:30 -080076
Greg Spencerdf791272018-02-07 12:21:14 -080077 Future<Uint8List> fakeHttpReader(Uri url, {Map<String, String> headers}) {
78 return new Future<Uint8List>.value(new Uint8List(0));
79 }
80
Greg Spencer8a2df392018-02-06 15:32:19 -080081 setUp(() async {
82 processManager = new FakeProcessManager();
83 args.clear();
84 namedArgs.clear();
85 tmpDir = await Directory.systemTemp.createTemp('flutter_');
86 flutterDir = new Directory(path.join(tmpDir.path, 'flutter'));
87 flutterDir.createSync(recursive: true);
88 creator = new ArchiveCreator(
89 tmpDir,
90 tmpDir,
91 testRef,
92 Branch.dev,
93 processManager: processManager,
94 subprocessOutput: false,
95 platform: platform,
Greg Spencerdf791272018-02-07 12:21:14 -080096 httpReader: fakeHttpReader,
Greg Spencer8a2df392018-02-06 15:32:19 -080097 );
98 flutter = path.join(creator.flutterRoot.absolute.path, 'bin', 'flutter');
99 });
100
101 tearDown(() async {
102 // On Windows, the directory is locked and not able to be deleted yet. So
103 // we just leave some (very small, because we're not actually building
104 // archives here) trash around to be deleted at the next reboot.
105 if (!platform.isWindows) {
106 await tmpDir.delete(recursive: true);
107 }
108 });
109
110 test('sets PUB_CACHE properly', () async {
111 final String createBase = path.join(tmpDir.absolute.path, 'create_');
112 final Map<String, List<ProcessResult>> calls = <String, List<ProcessResult>>{
113 'git clone -b dev https://chromium.googlesource.com/external/github.com/flutter/flutter':
114 null,
115 'git reset --hard $testRef': null,
Greg Spencerc345c1b2018-03-14 12:56:44 -0700116 'git remote set-url origin https://github.com/flutter/flutter.git': null,
Greg Spencer8a2df392018-02-06 15:32:19 -0800117 'git describe --tags --abbrev=0': <ProcessResult>[new ProcessResult(0, 0, 'v1.2.3', '')],
118 };
119 if (platform.isWindows) {
120 calls['7za x ${path.join(tmpDir.path, 'mingit.zip')}'] = null;
121 }
122 calls.addAll(<String, List<ProcessResult>>{
123 '$flutter doctor': null,
124 '$flutter update-packages': null,
125 '$flutter precache': null,
126 '$flutter ide-config': null,
127 '$flutter create --template=app ${createBase}app': null,
128 '$flutter create --template=package ${createBase}package': null,
129 '$flutter create --template=plugin ${createBase}plugin': null,
130 'git clean -f -X **/.packages': null,
131 });
132 final String archiveName = path.join(tmpDir.absolute.path,
Greg Spencer29d59e32018-02-27 13:15:32 -0800133 'flutter_${platformName}_v1.2.3-dev${platform.isLinux ? '.tar.xz' : '.zip'}');
Greg Spencer8a2df392018-02-06 15:32:19 -0800134 if (platform.isWindows) {
135 calls['7za a -tzip -mx=9 $archiveName flutter'] = null;
Greg Spencer29d59e32018-02-27 13:15:32 -0800136 } else if (platform.isMacOS) {
137 calls['zip -r -9 $archiveName flutter'] = null;
138 } else if (platform.isLinux) {
Greg Spencer8a2df392018-02-06 15:32:19 -0800139 calls['tar cJf $archiveName flutter'] = null;
140 }
141 processManager.fakeResults = calls;
142 await creator.initializeRepo();
143 await creator.createArchive();
144 expect(
145 verify(processManager.start(
Greg Spencerd9e37152018-03-20 08:14:08 -0700146 typed(captureAny),
147 workingDirectory: typed(captureAny, named: 'workingDirectory'),
148 environment: typed(captureAny, named: 'environment'),
149 )).captured[2]['PUB_CACHE'],
Greg Spencer8a2df392018-02-06 15:32:19 -0800150 endsWith(path.join('flutter', '.pub-cache')),
151 );
152 });
153
154 test('calls the right commands for archive output', () async {
155 final String createBase = path.join(tmpDir.absolute.path, 'create_');
156 final Map<String, List<ProcessResult>> calls = <String, List<ProcessResult>>{
157 'git clone -b dev https://chromium.googlesource.com/external/github.com/flutter/flutter':
158 null,
159 'git reset --hard $testRef': null,
Greg Spencerc345c1b2018-03-14 12:56:44 -0700160 'git remote set-url origin https://github.com/flutter/flutter.git': null,
Greg Spencer8a2df392018-02-06 15:32:19 -0800161 'git describe --tags --abbrev=0': <ProcessResult>[new ProcessResult(0, 0, 'v1.2.3', '')],
162 };
163 if (platform.isWindows) {
164 calls['7za x ${path.join(tmpDir.path, 'mingit.zip')}'] = null;
165 }
166 calls.addAll(<String, List<ProcessResult>>{
167 '$flutter doctor': null,
168 '$flutter update-packages': null,
169 '$flutter precache': null,
170 '$flutter ide-config': null,
171 '$flutter create --template=app ${createBase}app': null,
Greg Spencerdf791272018-02-07 12:21:14 -0800172 '$flutter create --template=package ${createBase}package': null,
Greg Spencer8a2df392018-02-06 15:32:19 -0800173 '$flutter create --template=plugin ${createBase}plugin': null,
174 'git clean -f -X **/.packages': null,
175 });
176 final String archiveName = path.join(tmpDir.absolute.path,
Greg Spencer29d59e32018-02-27 13:15:32 -0800177 'flutter_${platformName}_v1.2.3-dev${platform.isLinux ? '.tar.xz' : '.zip'}');
Greg Spencer8a2df392018-02-06 15:32:19 -0800178 if (platform.isWindows) {
179 calls['7za a -tzip -mx=9 $archiveName flutter'] = null;
Greg Spencer29d59e32018-02-27 13:15:32 -0800180 } else if (platform.isMacOS) {
181 calls['zip -r -9 $archiveName flutter'] = null;
182 } else if (platform.isLinux) {
Greg Spencer8a2df392018-02-06 15:32:19 -0800183 calls['tar cJf $archiveName flutter'] = null;
184 }
185 processManager.fakeResults = calls;
186 creator = new ArchiveCreator(
187 tmpDir,
188 tmpDir,
189 testRef,
190 Branch.dev,
191 processManager: processManager,
192 subprocessOutput: false,
193 platform: platform,
Greg Spencerdf791272018-02-07 12:21:14 -0800194 httpReader: fakeHttpReader,
Greg Spencer8a2df392018-02-06 15:32:19 -0800195 );
196 await creator.initializeRepo();
197 await creator.createArchive();
198 processManager.verifyCalls(calls.keys.toList());
199 });
200
201 test('throws when a command errors out', () async {
202 final Map<String, List<ProcessResult>> calls = <String, List<ProcessResult>>{
203 'git clone -b dev https://chromium.googlesource.com/external/github.com/flutter/flutter':
204 <ProcessResult>[new ProcessResult(0, 0, 'output1', '')],
205 'git reset --hard $testRef': <ProcessResult>[new ProcessResult(0, -1, 'output2', '')],
206 };
207 processManager.fakeResults = calls;
208 expect(expectAsync0(creator.initializeRepo),
209 throwsA(const isInstanceOf<ProcessRunnerException>()));
210 });
211 });
212
213 group('ArchivePublisher for $platformName', () {
214 FakeProcessManager processManager;
215 Directory tempDir;
216
217 setUp(() async {
218 processManager = new FakeProcessManager();
219 tempDir = await Directory.systemTemp.createTemp('flutter_');
220 tempDir.createSync();
221 });
222
223 tearDown(() async {
224 // On Windows, the directory is locked and not able to be deleted yet. So
225 // we just leave some (very small, because we're not actually building
226 // archives here) trash around to be deleted at the next reboot.
227 if (!platform.isWindows) {
228 await tempDir.delete(recursive: true);
229 }
230 });
231
232 test('calls the right processes', () async {
233 final String releasesName = 'releases_$platformName.json';
Greg Spencer29d59e32018-02-27 13:15:32 -0800234 final String archiveName = platform.isLinux ? 'archive.tar.xz' : 'archive.zip';
235 final String archiveMime = platform.isLinux ? 'application/x-gtar' : 'application/zip';
Greg Spencer97e77932018-02-09 15:42:51 -0800236 final String archivePath = path.join(tempDir.absolute.path, archiveName);
237 final String gsArchivePath = 'gs://flutter_infra/releases/dev/$platformName/$archiveName';
Greg Spencer8a2df392018-02-06 15:32:19 -0800238 final String jsonPath = path.join(tempDir.absolute.path, releasesName);
239 final String gsJsonPath = 'gs://flutter_infra/releases/$releasesName';
240 final String releasesJson = '''{
241 "base_url": "https://storage.googleapis.com/flutter_infra/releases",
242 "current_release": {
243 "beta": "6da8ec6bd0c4801b80d666869e4069698561c043",
244 "dev": "f88c60b38c3a5ef92115d24e3da4175b4890daba"
245 },
246 "releases": {
247 "6da8ec6bd0c4801b80d666869e4069698561c043": {
Greg Spencer29d59e32018-02-27 13:15:32 -0800248 "${platformName}_archive": "dev/linux/flutter_${platformName}_0.21.0-beta.zip",
Greg Spencer8a2df392018-02-06 15:32:19 -0800249 "release_date": "2017-12-19T10:30:00,847287019-08:00",
250 "version": "0.21.0-beta"
251 },
252 "f88c60b38c3a5ef92115d24e3da4175b4890daba": {
Greg Spencer29d59e32018-02-27 13:15:32 -0800253 "${platformName}_archive": "dev/linux/flutter_${platformName}_0.22.0-dev.zip",
Greg Spencer8a2df392018-02-06 15:32:19 -0800254 "release_date": "2018-01-19T13:30:09,728487019-08:00",
255 "version": "0.22.0-dev"
256 }
Greg Spencerf00c9022017-12-15 15:01:30 -0800257 }
Greg Spencerf00c9022017-12-15 15:01:30 -0800258}
Greg Spencer8a2df392018-02-06 15:32:19 -0800259''';
Greg Spencerd9e37152018-03-20 08:14:08 -0700260 new File(jsonPath).writeAsStringSync(releasesJson);
Greg Spencer8a2df392018-02-06 15:32:19 -0800261 final Map<String, List<ProcessResult>> calls = <String, List<ProcessResult>>{
262 'gsutil rm $gsArchivePath': null,
Greg Spencer0b6c1932018-02-22 09:03:10 -0800263 'gsutil -h Content-Type:$archiveMime cp $archivePath $gsArchivePath': null,
Greg Spencerd9e37152018-03-20 08:14:08 -0700264 'gsutil cp $gsJsonPath $jsonPath': null,
Greg Spencer8a2df392018-02-06 15:32:19 -0800265 'gsutil rm $gsJsonPath': null,
Greg Spencer0b6c1932018-02-22 09:03:10 -0800266 'gsutil -h Content-Type:application/json cp $jsonPath $gsJsonPath': null,
Greg Spencer8a2df392018-02-06 15:32:19 -0800267 };
268 processManager.fakeResults = calls;
Greg Spencer97e77932018-02-09 15:42:51 -0800269 final File outputFile = new File(path.join(tempDir.absolute.path, archiveName));
Greg Spencer8a2df392018-02-06 15:32:19 -0800270 assert(tempDir.existsSync());
271 final ArchivePublisher publisher = new ArchivePublisher(
272 tempDir,
273 testRef,
274 Branch.dev,
275 '1.2.3',
276 outputFile,
277 processManager: processManager,
278 subprocessOutput: false,
279 platform: platform,
280 );
281 assert(tempDir.existsSync());
282 await publisher.publishArchive();
283 processManager.verifyCalls(calls.keys.toList());
284 final File releaseFile = new File(jsonPath);
285 expect(releaseFile.existsSync(), isTrue);
286 final String contents = releaseFile.readAsStringSync();
287 // Make sure new data is added.
288 expect(contents, contains('"dev": "$testRef"'));
289 expect(contents, contains('"$testRef": {'));
Greg Spencer97e77932018-02-09 15:42:51 -0800290 expect(contents, contains('"${platformName}_archive": "dev/$platformName/$archiveName"'));
Greg Spencer8a2df392018-02-06 15:32:19 -0800291 // Make sure existing entries are preserved.
292 expect(contents, contains('"6da8ec6bd0c4801b80d666869e4069698561c043": {'));
293 expect(contents, contains('"f88c60b38c3a5ef92115d24e3da4175b4890daba": {'));
294 expect(contents, contains('"beta": "6da8ec6bd0c4801b80d666869e4069698561c043"'));
295 // Make sure it's valid JSON, and in the right format.
296 final Map<String, dynamic> jsonData = json.decode(contents);
Alexandre Ardhuin7667db62018-03-14 06:24:49 +0100297 const JsonEncoder encoder = const JsonEncoder.withIndent(' ');
Greg Spencer8a2df392018-02-06 15:32:19 -0800298 expect(contents, equals(encoder.convert(jsonData)));
299 });
300 });
301 }
Greg Spencerf00c9022017-12-15 15:01:30 -0800302}