mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
207 lines
6.8 KiB
Dart
207 lines
6.8 KiB
Dart
// Copyright 2016 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:async';
|
|
import 'dart:convert';
|
|
import 'dart:io';
|
|
|
|
import 'package:archive/archive.dart';
|
|
import 'package:flutter_tools/src/base/context.dart';
|
|
import 'package:flutter_tools/src/base/logger.dart';
|
|
import 'package:flutter_tools/src/base/os.dart';
|
|
import 'package:flutter_tools/src/base/process.dart';
|
|
import 'package:flutter_tools/src/base/process_manager.dart';
|
|
import 'package:path/path.dart' as path;
|
|
import 'package:test/test.dart';
|
|
|
|
typedef bool Predicate<T>(T item);
|
|
|
|
/// Decodes a UTF8-encoded byte array into a list of Strings, where each list
|
|
/// entry represents a line of text.
|
|
List<String> _decode(List<int> data) =>
|
|
const LineSplitter().convert(UTF8.decode(data));
|
|
|
|
/// Consumes and returns an entire stream of bytes.
|
|
Future<List<int>> _consume(Stream<List<int>> stream) =>
|
|
stream.expand((List<int> data) => data).toList();
|
|
|
|
void main() {
|
|
group('RecordingProcessManager', () {
|
|
Directory tmp;
|
|
ProcessManager manager;
|
|
|
|
setUp(() {
|
|
tmp = Directory.systemTemp.createTempSync('flutter_tools_');
|
|
manager = new RecordingProcessManager(tmp.path);
|
|
});
|
|
|
|
tearDown(() {
|
|
tmp.deleteSync(recursive: true);
|
|
});
|
|
|
|
test('start', () async {
|
|
Process process = await manager.start('echo', <String>['foo']);
|
|
int pid = process.pid;
|
|
int exitCode = await process.exitCode;
|
|
List<int> stdout = await _consume(process.stdout);
|
|
List<int> stderr = await _consume(process.stderr);
|
|
expect(exitCode, 0);
|
|
expect(_decode(stdout), <String>['foo']);
|
|
expect(stderr, isEmpty);
|
|
|
|
// Force the recording to be written to disk.
|
|
await runShutdownHooks();
|
|
|
|
_Recording recording = _Recording.readFrom(tmp);
|
|
expect(recording.manifest, hasLength(1));
|
|
Map<String, dynamic> entry = recording.manifest.first;
|
|
expect(entry['pid'], pid);
|
|
expect(entry['exitCode'], exitCode);
|
|
expect(recording.stdoutForEntryAt(0), stdout);
|
|
expect(recording.stderrForEntryAt(0), stderr);
|
|
});
|
|
|
|
test('run', () async {
|
|
ProcessResult result = await manager.run('echo', <String>['bar']);
|
|
int pid = result.pid;
|
|
int exitCode = result.exitCode;
|
|
String stdout = result.stdout;
|
|
String stderr = result.stderr;
|
|
expect(exitCode, 0);
|
|
expect(stdout, 'bar\n');
|
|
expect(stderr, isEmpty);
|
|
|
|
// Force the recording to be written to disk.
|
|
await runShutdownHooks();
|
|
|
|
_Recording recording = _Recording.readFrom(tmp);
|
|
expect(recording.manifest, hasLength(1));
|
|
Map<String, dynamic> entry = recording.manifest.first;
|
|
expect(entry['pid'], pid);
|
|
expect(entry['exitCode'], exitCode);
|
|
expect(recording.stdoutForEntryAt(0), stdout);
|
|
expect(recording.stderrForEntryAt(0), stderr);
|
|
});
|
|
|
|
test('runSync', () async {
|
|
ProcessResult result = manager.runSync('echo', <String>['baz']);
|
|
int pid = result.pid;
|
|
int exitCode = result.exitCode;
|
|
String stdout = result.stdout;
|
|
String stderr = result.stderr;
|
|
expect(exitCode, 0);
|
|
expect(stdout, 'baz\n');
|
|
expect(stderr, isEmpty);
|
|
|
|
// Force the recording to be written to disk.
|
|
await runShutdownHooks();
|
|
|
|
_Recording recording = _Recording.readFrom(tmp);
|
|
expect(recording.manifest, hasLength(1));
|
|
Map<String, dynamic> entry = recording.manifest.first;
|
|
expect(entry['pid'], pid);
|
|
expect(entry['exitCode'], exitCode);
|
|
expect(recording.stdoutForEntryAt(0), stdout);
|
|
expect(recording.stderrForEntryAt(0), stderr);
|
|
});
|
|
});
|
|
|
|
group('ReplayProcessManager', () {
|
|
ProcessManager manager;
|
|
|
|
setUp(() async {
|
|
await runInMinimalContext(() async {
|
|
Directory dir = new Directory('test/data/process_manager/replay');
|
|
manager = await ReplayProcessManager.create(dir.path);
|
|
});
|
|
});
|
|
|
|
tearDown(() async {
|
|
// Allow the replay manager to clean up
|
|
await runShutdownHooks();
|
|
});
|
|
|
|
test('start', () async {
|
|
Process process = await manager.start('sing', <String>['ppap']);
|
|
int exitCode = await process.exitCode;
|
|
List<int> stdout = await _consume(process.stdout);
|
|
List<int> stderr = await _consume(process.stderr);
|
|
expect(process.pid, 100);
|
|
expect(exitCode, 0);
|
|
expect(_decode(stdout), <String>['I have a pen', 'I have a pineapple']);
|
|
expect(_decode(stderr), <String>['Uh, pineapple pen']);
|
|
});
|
|
|
|
test('run', () async {
|
|
ProcessResult result = await manager.run('dance', <String>['gangnam-style']);
|
|
expect(result.pid, 101);
|
|
expect(result.exitCode, 2);
|
|
expect(result.stdout, '');
|
|
expect(result.stderr, 'No one can dance like Psy\n');
|
|
});
|
|
|
|
test('runSync', () {
|
|
ProcessResult result = manager.runSync('dance', <String>['gangnam-style']);
|
|
expect(result.pid, 101);
|
|
expect(result.exitCode, 2);
|
|
expect(result.stdout, '');
|
|
expect(result.stderr, 'No one can dance like Psy\n');
|
|
});
|
|
});
|
|
}
|
|
|
|
Future<Null> runInMinimalContext(Future<dynamic> method()) async {
|
|
AppContext context = new AppContext();
|
|
context.putIfAbsent(ProcessManager, () => new ProcessManager());
|
|
context.putIfAbsent(Logger, () => new BufferLogger());
|
|
context.putIfAbsent(OperatingSystemUtils, () => new OperatingSystemUtils());
|
|
await context.runInZone(method);
|
|
}
|
|
|
|
/// A testing utility class that encapsulates a recording.
|
|
class _Recording {
|
|
final File file;
|
|
final Archive _archive;
|
|
|
|
_Recording(this.file, this._archive);
|
|
|
|
static _Recording readFrom(Directory dir) {
|
|
File file = new File(path.join(
|
|
dir.path, RecordingProcessManager.kDefaultRecordTo));
|
|
Archive archive = new ZipDecoder().decodeBytes(file.readAsBytesSync());
|
|
return new _Recording(file, archive);
|
|
}
|
|
|
|
List<Map<String, dynamic>> get manifest {
|
|
return JSON.decoder.convert(_getFileContent('MANIFEST.txt', UTF8));
|
|
}
|
|
|
|
dynamic stdoutForEntryAt(int index) =>
|
|
_getStdioContent(manifest[index], 'stdout');
|
|
|
|
dynamic stderrForEntryAt(int index) =>
|
|
_getStdioContent(manifest[index], 'stderr');
|
|
|
|
dynamic _getFileContent(String name, Encoding encoding) {
|
|
List<int> bytes = _fileNamed(name).content;
|
|
return encoding == null ? bytes : encoding.decode(bytes);
|
|
}
|
|
|
|
dynamic _getStdioContent(Map<String, dynamic> entry, String type) {
|
|
String basename = entry['basename'];
|
|
String encodingName = entry['${type}Encoding'];
|
|
Encoding encoding;
|
|
if (encodingName != null)
|
|
encoding = encodingName == 'system'
|
|
? const SystemEncoding()
|
|
: Encoding.getByName(encodingName);
|
|
return _getFileContent('$basename.$type', encoding);
|
|
}
|
|
|
|
ArchiveFile _fileNamed(String name) => _archive.firstWhere(_hasName(name));
|
|
|
|
Predicate<ArchiveFile> _hasName(String name) =>
|
|
(ArchiveFile file) => file.name == name;
|
|
}
|