| // 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 'package:file/file.dart'; |
| import 'package:file/memory.dart'; |
| import 'package:flutter_tools/src/cache.dart'; |
| import 'package:flutter_tools/src/base/context.dart'; |
| import 'package:flutter_tools/src/base/io.dart'; |
| import 'package:flutter_tools/src/base/platform.dart'; |
| import 'package:flutter_tools/src/dart/pub.dart'; |
| |
| import 'package:mockito/mockito.dart'; |
| import 'package:process/process.dart'; |
| import 'package:quiver/testing/async.dart'; |
| |
| import '../src/common.dart'; |
| import '../src/context.dart'; |
| |
| void main() { |
| setUpAll(() { |
| Cache.flutterRoot = getFlutterRoot(); |
| }); |
| |
| testUsingContext('pub get 69', () async { |
| String error; |
| |
| final MockProcessManager processMock = context.get<ProcessManager>(); |
| |
| FakeAsync().run((FakeAsync time) { |
| expect(processMock.lastPubEnvironment, isNull); |
| expect(testLogger.statusText, ''); |
| pubGet(context: PubContext.flutterTests, checkLastModified: false).then((void value) { |
| error = 'test completed unexpectedly'; |
| }, onError: (dynamic thrownError) { |
| error = 'test failed unexpectedly: $thrownError'; |
| }); |
| time.elapse(const Duration(milliseconds: 500)); |
| expect(testLogger.statusText, |
| 'Running "flutter packages get" in /...\n' |
| 'pub get failed (69) -- attempting retry 1 in 1 second...\n', |
| ); |
| expect(processMock.lastPubEnvironment, contains('flutter_cli:flutter_tests')); |
| expect(processMock.lastPubCache, isNull); |
| time.elapse(const Duration(milliseconds: 500)); |
| expect(testLogger.statusText, |
| 'Running "flutter packages get" in /...\n' |
| 'pub get failed (69) -- attempting retry 1 in 1 second...\n' |
| 'pub get failed (69) -- attempting retry 2 in 2 seconds...\n', |
| ); |
| time.elapse(const Duration(seconds: 1)); |
| expect(testLogger.statusText, |
| 'Running "flutter packages get" in /...\n' |
| 'pub get failed (69) -- attempting retry 1 in 1 second...\n' |
| 'pub get failed (69) -- attempting retry 2 in 2 seconds...\n', |
| ); |
| time.elapse(const Duration(seconds: 100)); // from t=0 to t=100 |
| expect(testLogger.statusText, |
| 'Running "flutter packages get" in /...\n' |
| 'pub get failed (69) -- attempting retry 1 in 1 second...\n' |
| 'pub get failed (69) -- attempting retry 2 in 2 seconds...\n' |
| 'pub get failed (69) -- attempting retry 3 in 4 seconds...\n' // at t=1 |
| 'pub get failed (69) -- attempting retry 4 in 8 seconds...\n' // at t=5 |
| 'pub get failed (69) -- attempting retry 5 in 16 seconds...\n' // at t=13 |
| 'pub get failed (69) -- attempting retry 6 in 32 seconds...\n' // at t=29 |
| 'pub get failed (69) -- attempting retry 7 in 64 seconds...\n', // at t=61 |
| ); |
| time.elapse(const Duration(seconds: 200)); // from t=0 to t=200 |
| expect(testLogger.statusText, |
| 'Running "flutter packages get" in /...\n' |
| 'pub get failed (69) -- attempting retry 1 in 1 second...\n' |
| 'pub get failed (69) -- attempting retry 2 in 2 seconds...\n' |
| 'pub get failed (69) -- attempting retry 3 in 4 seconds...\n' |
| 'pub get failed (69) -- attempting retry 4 in 8 seconds...\n' |
| 'pub get failed (69) -- attempting retry 5 in 16 seconds...\n' |
| 'pub get failed (69) -- attempting retry 6 in 32 seconds...\n' |
| 'pub get failed (69) -- attempting retry 7 in 64 seconds...\n' |
| 'pub get failed (69) -- attempting retry 8 in 64 seconds...\n' // at t=39 |
| 'pub get failed (69) -- attempting retry 9 in 64 seconds...\n' // at t=103 |
| 'pub get failed (69) -- attempting retry 10 in 64 seconds...\n', // at t=167 |
| ); |
| }); |
| expect(testLogger.errorText, isEmpty); |
| expect(error, isNull); |
| }, overrides: <Type, Generator>{ |
| ProcessManager: () => MockProcessManager(69), |
| FileSystem: () => MockFileSystem(), |
| Platform: () => FakePlatform( |
| environment: <String, String>{}, |
| ), |
| }); |
| |
| testUsingContext('pub cache in root is used', () async { |
| String error; |
| |
| final MockProcessManager processMock = context.get<ProcessManager>() as MockProcessManager; |
| final MockFileSystem fsMock = context.get<FileSystem>() as MockFileSystem; |
| |
| FakeAsync().run((FakeAsync time) { |
| MockDirectory.findCache = true; |
| expect(processMock.lastPubEnvironment, isNull); |
| expect(processMock.lastPubCache, isNull); |
| pubGet(context: PubContext.flutterTests, checkLastModified: false).then((void value) { |
| error = 'test completed unexpectedly'; |
| }, onError: (dynamic thrownError) { |
| error = 'test failed unexpectedly: $thrownError'; |
| }); |
| time.elapse(const Duration(milliseconds: 500)); |
| expect(processMock.lastPubCache, equals(fsMock.path.join(Cache.flutterRoot, '.pub-cache'))); |
| expect(error, isNull); |
| }); |
| }, overrides: <Type, Generator>{ |
| ProcessManager: () => MockProcessManager(69), |
| FileSystem: () => MockFileSystem(), |
| Platform: () => FakePlatform( |
| environment: <String, String>{}, |
| ), |
| }); |
| |
| testUsingContext('pub cache in environment is used', () async { |
| String error; |
| |
| final MockProcessManager processMock = context.get<ProcessManager>(); |
| |
| FakeAsync().run((FakeAsync time) { |
| MockDirectory.findCache = true; |
| expect(processMock.lastPubEnvironment, isNull); |
| expect(processMock.lastPubCache, isNull); |
| pubGet(context: PubContext.flutterTests, checkLastModified: false).then((void value) { |
| error = 'test completed unexpectedly'; |
| }, onError: (dynamic thrownError) { |
| error = 'test failed unexpectedly: $thrownError'; |
| }); |
| time.elapse(const Duration(milliseconds: 500)); |
| expect(processMock.lastPubCache, equals('custom/pub-cache/path')); |
| expect(error, isNull); |
| }); |
| }, overrides: <Type, Generator>{ |
| ProcessManager: () => MockProcessManager(69), |
| FileSystem: () => MockFileSystem(), |
| Platform: () => FakePlatform( |
| environment: <String, String>{'PUB_CACHE': 'custom/pub-cache/path'}, |
| ), |
| }); |
| } |
| |
| typedef StartCallback = void Function(List<dynamic> command); |
| |
| class MockProcessManager implements ProcessManager { |
| MockProcessManager(this.fakeExitCode); |
| |
| final int fakeExitCode; |
| |
| String lastPubEnvironment; |
| String lastPubCache; |
| |
| @override |
| Future<Process> start( |
| List<dynamic> command, { |
| String workingDirectory, |
| Map<String, String> environment, |
| bool includeParentEnvironment = true, |
| bool runInShell = false, |
| ProcessStartMode mode = ProcessStartMode.normal, |
| }) { |
| lastPubEnvironment = environment['PUB_ENVIRONMENT']; |
| lastPubCache = environment['PUB_CACHE']; |
| return Future<Process>.value(MockProcess(fakeExitCode)); |
| } |
| |
| @override |
| dynamic noSuchMethod(Invocation invocation) => null; |
| } |
| |
| class MockProcess implements Process { |
| MockProcess(this.fakeExitCode); |
| |
| final int fakeExitCode; |
| |
| @override |
| Stream<List<int>> get stdout => MockStream<List<int>>(); |
| |
| @override |
| Stream<List<int>> get stderr => MockStream<List<int>>(); |
| |
| @override |
| Future<int> get exitCode => Future<int>.value(fakeExitCode); |
| |
| @override |
| dynamic noSuchMethod(Invocation invocation) => null; |
| } |
| |
| class MockStream<T> implements Stream<T> { |
| @override |
| Stream<S> transform<S>(StreamTransformer<T, S> streamTransformer) => MockStream<S>(); |
| |
| @override |
| Stream<T> where(bool test(T event)) => MockStream<T>(); |
| |
| @override |
| StreamSubscription<T> listen(void onData(T event), { Function onError, void onDone(), bool cancelOnError }) { |
| return MockStreamSubscription<T>(); |
| } |
| |
| @override |
| dynamic noSuchMethod(Invocation invocation) => null; |
| } |
| |
| class MockStreamSubscription<T> implements StreamSubscription<T> { |
| @override |
| Future<E> asFuture<E>([ E futureValue ]) => Future<E>.value(); |
| |
| @override |
| Future<void> cancel() async { } |
| |
| @override |
| dynamic noSuchMethod(Invocation invocation) => null; |
| } |
| |
| |
| class MockFileSystem extends ForwardingFileSystem { |
| MockFileSystem() : super(MemoryFileSystem()); |
| |
| @override |
| File file(dynamic path) { |
| return MockFile(); |
| } |
| |
| @override |
| Directory directory(dynamic path) { |
| return MockDirectory(path); |
| } |
| } |
| |
| class MockFile implements File { |
| @override |
| Future<RandomAccessFile> open({ FileMode mode = FileMode.read }) async { |
| return MockRandomAccessFile(); |
| } |
| |
| @override |
| bool existsSync() => true; |
| |
| @override |
| DateTime lastModifiedSync() => DateTime(0); |
| |
| @override |
| dynamic noSuchMethod(Invocation invocation) => null; |
| } |
| |
| class MockDirectory implements Directory { |
| MockDirectory(this.path); |
| |
| @override |
| final String path; |
| |
| static bool findCache = false; |
| |
| @override |
| bool existsSync() => findCache && path.endsWith('.pub-cache'); |
| |
| @override |
| dynamic noSuchMethod(Invocation invocation) => null; |
| } |
| |
| class MockRandomAccessFile extends Mock implements RandomAccessFile {} |