flutter/dev/bots/test/prepare_package_test.dart
Greg Spencer 8a2df39662
Create packages only for release builds, and publish when created. (#14476)
This changes the publishing of archives so that it happens on the chrome_infra bots when they build a packaged branch instead of as part of the dev_roll process.

It uses the tagged version in the branch, and leaves the git repo that it clones checked out on the branch and hash used to build the package.

It updates metadata located at gs://flutter_infra/releases/releases_.json (where is one of macos, linux, or windows) once published, since it would be complex to do the proper locking to keep them all in one shared .json file safely.

A separate [change to the chrome_infra bots](https://chromium-review.googlesource.com/c/chromium/tools/build/+/902823) was made to instruct them to build packaged for the dev, beta, and release branches (but not master anymore).
2018-02-06 15:32:19 -08:00

249 lines
10 KiB
Dart

// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert';
import 'dart:io' hide Platform;
import 'package:mockito/mockito.dart';
import 'package:test/test.dart';
import 'package:path/path.dart' as path;
import 'package:platform/platform.dart' show FakePlatform;
import '../prepare_package.dart';
import 'fake_process_manager.dart';
void main() {
final String testRef = 'deadbeefdeadbeefdeadbeefdeadbeefdeadbeef';
for (String platformName in <String>['macos', 'linux', 'windows']) {
final FakePlatform platform = new FakePlatform(
operatingSystem: platformName,
environment: <String, String>{},
);
group('ArchiveCreator for $platformName', () {
ArchiveCreator creator;
Directory tmpDir;
Directory flutterDir;
FakeProcessManager processManager;
final List<List<String>> args = <List<String>>[];
final List<Map<Symbol, dynamic>> namedArgs = <Map<Symbol, dynamic>>[];
String flutter;
setUp(() async {
processManager = new FakeProcessManager();
args.clear();
namedArgs.clear();
tmpDir = await Directory.systemTemp.createTemp('flutter_');
flutterDir = new Directory(path.join(tmpDir.path, 'flutter'));
flutterDir.createSync(recursive: true);
creator = new ArchiveCreator(
tmpDir,
tmpDir,
testRef,
Branch.dev,
processManager: processManager,
subprocessOutput: false,
platform: platform,
);
flutter = path.join(creator.flutterRoot.absolute.path, 'bin', 'flutter');
});
tearDown(() async {
// On Windows, the directory is locked and not able to be deleted yet. So
// we just leave some (very small, because we're not actually building
// archives here) trash around to be deleted at the next reboot.
if (!platform.isWindows) {
await tmpDir.delete(recursive: true);
}
});
test('sets PUB_CACHE properly', () async {
final String createBase = path.join(tmpDir.absolute.path, 'create_');
final Map<String, List<ProcessResult>> calls = <String, List<ProcessResult>>{
'git clone -b dev https://chromium.googlesource.com/external/github.com/flutter/flutter':
null,
'git reset --hard $testRef': null,
'git remote remove origin': null,
'git remote add origin https://github.com/flutter/flutter.git': null,
'git describe --tags --abbrev=0': <ProcessResult>[new ProcessResult(0, 0, 'v1.2.3', '')],
};
if (platform.isWindows) {
calls['7za x ${path.join(tmpDir.path, 'mingit.zip')}'] = null;
}
calls.addAll(<String, List<ProcessResult>>{
'$flutter doctor': null,
'$flutter update-packages': null,
'$flutter precache': null,
'$flutter ide-config': null,
'$flutter create --template=app ${createBase}app': null,
'$flutter create --template=package ${createBase}package': null,
'$flutter create --template=plugin ${createBase}plugin': null,
'git clean -f -X **/.packages': null,
});
final String archiveName = path.join(tmpDir.absolute.path,
'flutter_${platformName}_v1.2.3-dev${platform.isWindows ? '.zip' : '.tar.xz'}');
if (platform.isWindows) {
calls['7za a -tzip -mx=9 $archiveName flutter'] = null;
} else {
calls['tar cJf $archiveName flutter'] = null;
}
processManager.fakeResults = calls;
await creator.initializeRepo();
await creator.createArchive();
expect(
verify(processManager.start(
captureAny,
workingDirectory: captureAny,
environment: captureAny,
)).captured[1]['PUB_CACHE'],
endsWith(path.join('flutter', '.pub-cache')),
);
});
test('calls the right commands for archive output', () async {
final String createBase = path.join(tmpDir.absolute.path, 'create_');
final Map<String, List<ProcessResult>> calls = <String, List<ProcessResult>>{
'git clone -b dev https://chromium.googlesource.com/external/github.com/flutter/flutter':
null,
'git reset --hard $testRef': null,
'git remote remove origin': null,
'git remote add origin https://github.com/flutter/flutter.git': null,
'git describe --tags --abbrev=0': <ProcessResult>[new ProcessResult(0, 0, 'v1.2.3', '')],
};
if (platform.isWindows) {
calls['7za x ${path.join(tmpDir.path, 'mingit.zip')}'] = null;
}
calls.addAll(<String, List<ProcessResult>>{
'$flutter doctor': null,
'$flutter update-packages': null,
'$flutter precache': null,
'$flutter ide-config': null,
'$flutter create --template=app ${createBase}app': null,
// TODO(gspencer): Re-enable this when package works again:
// https://github.com/flutter/flutter/issues/14448
// '$flutter create --template=package ${createBase}package': null,
'$flutter create --template=plugin ${createBase}plugin': null,
'git clean -f -X **/.packages': null,
});
final String archiveName = path.join(tmpDir.absolute.path,
'flutter_${platformName}_v1.2.3-dev${platform.isWindows ? '.zip' : '.tar.xz'}');
if (platform.isWindows) {
calls['7za a -tzip -mx=9 $archiveName flutter'] = null;
} else {
calls['tar cJf $archiveName flutter'] = null;
}
processManager.fakeResults = calls;
creator = new ArchiveCreator(
tmpDir,
tmpDir,
testRef,
Branch.dev,
processManager: processManager,
subprocessOutput: false,
platform: platform,
);
await creator.initializeRepo();
await creator.createArchive();
processManager.verifyCalls(calls.keys.toList());
});
test('throws when a command errors out', () async {
final Map<String, List<ProcessResult>> calls = <String, List<ProcessResult>>{
'git clone -b dev https://chromium.googlesource.com/external/github.com/flutter/flutter':
<ProcessResult>[new ProcessResult(0, 0, 'output1', '')],
'git reset --hard $testRef': <ProcessResult>[new ProcessResult(0, -1, 'output2', '')],
};
processManager.fakeResults = calls;
expect(expectAsync0(creator.initializeRepo),
throwsA(const isInstanceOf<ProcessRunnerException>()));
});
});
group('ArchivePublisher for $platformName', () {
FakeProcessManager processManager;
Directory tempDir;
setUp(() async {
processManager = new FakeProcessManager();
tempDir = await Directory.systemTemp.createTemp('flutter_');
tempDir.createSync();
});
tearDown(() async {
// On Windows, the directory is locked and not able to be deleted yet. So
// we just leave some (very small, because we're not actually building
// archives here) trash around to be deleted at the next reboot.
if (!platform.isWindows) {
await tempDir.delete(recursive: true);
}
});
test('calls the right processes', () async {
final String releasesName = 'releases_$platformName.json';
final String archivePath = path.join(tempDir.absolute.path, 'output_archive');
final String gsArchivePath = 'gs://flutter_infra/releases/dev/$platformName/output_archive';
final String jsonPath = path.join(tempDir.absolute.path, releasesName);
final String gsJsonPath = 'gs://flutter_infra/releases/$releasesName';
final String releasesJson = '''{
"base_url": "https://storage.googleapis.com/flutter_infra/releases",
"current_release": {
"beta": "6da8ec6bd0c4801b80d666869e4069698561c043",
"dev": "f88c60b38c3a5ef92115d24e3da4175b4890daba"
},
"releases": {
"6da8ec6bd0c4801b80d666869e4069698561c043": {
"${platformName}_archive": "dev/linux/flutter_${platformName}_0.21.0-beta.tar.xz",
"release_date": "2017-12-19T10:30:00,847287019-08:00",
"version": "0.21.0-beta"
},
"f88c60b38c3a5ef92115d24e3da4175b4890daba": {
"${platformName}_archive": "dev/linux/flutter_${platformName}_0.22.0-dev.tar.xz",
"release_date": "2018-01-19T13:30:09,728487019-08:00",
"version": "0.22.0-dev"
}
}
}
''';
final Map<String, List<ProcessResult>> calls = <String, List<ProcessResult>>{
'gsutil rm $gsArchivePath': null,
'gsutil cp $archivePath $gsArchivePath': null,
'gsutil cat $gsJsonPath': <ProcessResult>[new ProcessResult(0, 0, releasesJson, '')],
'gsutil rm $gsJsonPath': null,
'gsutil cp $jsonPath $gsJsonPath': null,
};
processManager.fakeResults = calls;
final File outputFile = new File(path.join(tempDir.absolute.path, 'output_archive'));
assert(tempDir.existsSync());
final ArchivePublisher publisher = new ArchivePublisher(
tempDir,
testRef,
Branch.dev,
'1.2.3',
outputFile,
processManager: processManager,
subprocessOutput: false,
platform: platform,
);
assert(tempDir.existsSync());
await publisher.publishArchive();
processManager.verifyCalls(calls.keys.toList());
final File releaseFile = new File(jsonPath);
expect(releaseFile.existsSync(), isTrue);
final String contents = releaseFile.readAsStringSync();
// Make sure new data is added.
expect(contents, contains('"dev": "$testRef"'));
expect(contents, contains('"$testRef": {'));
expect(contents, contains('"${platformName}_archive": "dev/$platformName/output_archive"'));
// Make sure existing entries are preserved.
expect(contents, contains('"6da8ec6bd0c4801b80d666869e4069698561c043": {'));
expect(contents, contains('"f88c60b38c3a5ef92115d24e3da4175b4890daba": {'));
expect(contents, contains('"beta": "6da8ec6bd0c4801b80d666869e4069698561c043"'));
// Make sure it's valid JSON, and in the right format.
final Map<String, dynamic> jsonData = json.decode(contents);
final JsonEncoder encoder = const JsonEncoder.withIndent(' ');
expect(contents, equals(encoder.convert(jsonData)));
});
});
}
}