pub_get_test.dart 8.8 KB
Newer Older
1 2 3 4 5 6 7 8
// 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';
9
import 'package:flutter_tools/src/cache.dart';
10
import 'package:flutter_tools/src/base/context.dart';
11
import 'package:flutter_tools/src/base/io.dart';
12
import 'package:flutter_tools/src/base/platform.dart';
13
import 'package:flutter_tools/src/dart/pub.dart';
14

15 16 17 18
import 'package:mockito/mockito.dart';
import 'package:process/process.dart';
import 'package:quiver/testing/async.dart';

19
import '../src/common.dart';
20 21 22
import '../src/context.dart';

void main() {
23 24 25 26
  setUpAll(() {
    Cache.flutterRoot = getFlutterRoot();
  });

27 28
  testUsingContext('pub get 69', () async {
    String error;
29

30
    final MockProcessManager processMock = context.get<ProcessManager>();
31

32
    FakeAsync().run((FakeAsync time) {
Josh Soref's avatar
Josh Soref committed
33
      expect(processMock.lastPubEnvironment, isNull);
34
      expect(testLogger.statusText, '');
35
      pubGet(context: PubContext.flutterTests, checkLastModified: false).then((void value) {
36
        error = 'test completed unexpectedly';
37 38
      }, onError: (dynamic thrownError) {
        error = 'test failed unexpectedly: $thrownError';
39 40 41 42
      });
      time.elapse(const Duration(milliseconds: 500));
      expect(testLogger.statusText,
        'Running "flutter packages get" in /...\n'
43
        'pub get failed (69) -- attempting retry 1 in 1 second...\n',
44
      );
Josh Soref's avatar
Josh Soref committed
45
      expect(processMock.lastPubEnvironment, contains('flutter_cli:flutter_tests'));
46
      expect(processMock.lastPubCache, isNull);
47 48 49 50
      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'
51
        'pub get failed (69) -- attempting retry 2 in 2 seconds...\n',
52 53 54 55 56
      );
      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'
57
        'pub get failed (69) -- attempting retry 2 in 2 seconds...\n',
58 59 60 61 62 63 64 65 66 67
      );
      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
68
        'pub get failed (69) -- attempting retry 7 in 64 seconds...\n', // at t=61
69 70 71 72 73 74 75 76 77 78 79 80 81
      );
      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
82
        'pub get failed (69) -- attempting retry 10 in 64 seconds...\n', // at t=167
83 84 85 86 87
      );
    });
    expect(testLogger.errorText, isEmpty);
    expect(error, isNull);
  }, overrides: <Type, Generator>{
88 89 90
    ProcessManager: () => MockProcessManager(69),
    FileSystem: () => MockFileSystem(),
    Platform: () => FakePlatform(
91 92 93 94 95 96 97
      environment: <String, String>{},
    ),
  });

  testUsingContext('pub cache in root is used', () async {
    String error;

98 99
    final MockProcessManager processMock = context.get<ProcessManager>() as MockProcessManager;
    final MockFileSystem fsMock = context.get<FileSystem>() as MockFileSystem;
100

101
    FakeAsync().run((FakeAsync time) {
102
      MockDirectory.findCache = true;
Josh Soref's avatar
Josh Soref committed
103
      expect(processMock.lastPubEnvironment, isNull);
104
      expect(processMock.lastPubCache, isNull);
105
      pubGet(context: PubContext.flutterTests, checkLastModified: false).then((void value) {
106 107 108 109 110
        error = 'test completed unexpectedly';
      }, onError: (dynamic thrownError) {
        error = 'test failed unexpectedly: $thrownError';
      });
      time.elapse(const Duration(milliseconds: 500));
111
      expect(processMock.lastPubCache, equals(fsMock.path.join(Cache.flutterRoot, '.pub-cache')));
112 113 114
      expect(error, isNull);
    });
  }, overrides: <Type, Generator>{
115 116 117
    ProcessManager: () => MockProcessManager(69),
    FileSystem: () => MockFileSystem(),
    Platform: () => FakePlatform(
118 119 120 121 122 123 124
      environment: <String, String>{},
    ),
  });

  testUsingContext('pub cache in environment is used', () async {
    String error;

125
    final MockProcessManager processMock = context.get<ProcessManager>();
126

127
    FakeAsync().run((FakeAsync time) {
128
      MockDirectory.findCache = true;
Josh Soref's avatar
Josh Soref committed
129
      expect(processMock.lastPubEnvironment, isNull);
130
      expect(processMock.lastPubCache, isNull);
131
      pubGet(context: PubContext.flutterTests, checkLastModified: false).then((void value) {
132 133 134 135 136
        error = 'test completed unexpectedly';
      }, onError: (dynamic thrownError) {
        error = 'test failed unexpectedly: $thrownError';
      });
      time.elapse(const Duration(milliseconds: 500));
137
      expect(processMock.lastPubCache, equals('custom/pub-cache/path'));
138 139 140
      expect(error, isNull);
    });
  }, overrides: <Type, Generator>{
141 142 143
    ProcessManager: () => MockProcessManager(69),
    FileSystem: () => MockFileSystem(),
    Platform: () => FakePlatform(
144
      environment: <String, String>{'PUB_CACHE': 'custom/pub-cache/path'},
145
    ),
146 147 148
  });
}

149
typedef StartCallback = void Function(List<dynamic> command);
150 151 152 153 154 155

class MockProcessManager implements ProcessManager {
  MockProcessManager(this.fakeExitCode);

  final int fakeExitCode;

Josh Soref's avatar
Josh Soref committed
156
  String lastPubEnvironment;
157
  String lastPubCache;
158

159 160 161 162 163
  @override
  Future<Process> start(
    List<dynamic> command, {
    String workingDirectory,
    Map<String, String> environment,
164 165
    bool includeParentEnvironment = true,
    bool runInShell = false,
166
    ProcessStartMode mode = ProcessStartMode.normal,
167
  }) {
Josh Soref's avatar
Josh Soref committed
168
    lastPubEnvironment = environment['PUB_ENVIRONMENT'];
169
    lastPubCache = environment['PUB_CACHE'];
170
    return Future<Process>.value(MockProcess(fakeExitCode));
171 172 173 174 175 176 177 178 179 180 181 182
  }

  @override
  dynamic noSuchMethod(Invocation invocation) => null;
}

class MockProcess implements Process {
  MockProcess(this.fakeExitCode);

  final int fakeExitCode;

  @override
183
  Stream<List<int>> get stdout => MockStream<List<int>>();
184 185

  @override
186
  Stream<List<int>> get stderr => MockStream<List<int>>();
187 188

  @override
189
  Future<int> get exitCode => Future<int>.value(fakeExitCode);
190 191 192 193 194 195 196

  @override
  dynamic noSuchMethod(Invocation invocation) => null;
}

class MockStream<T> implements Stream<T> {
  @override
197
  Stream<S> transform<S>(StreamTransformer<T, S> streamTransformer) => MockStream<S>();
198 199

  @override
200
  Stream<T> where(bool test(T event)) => MockStream<T>();
201 202

  @override
203
  StreamSubscription<T> listen(void onData(T event), { Function onError, void onDone(), bool cancelOnError }) {
204
    return MockStreamSubscription<T>();
205 206 207 208 209 210 211 212
  }

  @override
  dynamic noSuchMethod(Invocation invocation) => null;
}

class MockStreamSubscription<T> implements StreamSubscription<T> {
  @override
213
  Future<E> asFuture<E>([ E futureValue ]) => Future<E>.value();
214 215

  @override
216
  Future<void> cancel() async { }
217 218 219 220 221 222

  @override
  dynamic noSuchMethod(Invocation invocation) => null;
}


223
class MockFileSystem extends ForwardingFileSystem {
224
  MockFileSystem() : super(MemoryFileSystem());
225

226 227
  @override
  File file(dynamic path) {
228
    return MockFile();
229
  }
230 231 232

  @override
  Directory directory(dynamic path) {
233
    return MockDirectory(path);
234
  }
235 236 237 238
}

class MockFile implements File {
  @override
239
  Future<RandomAccessFile> open({ FileMode mode = FileMode.read }) async {
240
    return MockRandomAccessFile();
241 242 243 244 245 246
  }

  @override
  bool existsSync() => true;

  @override
247
  DateTime lastModifiedSync() => DateTime(0);
248 249 250 251 252

  @override
  dynamic noSuchMethod(Invocation invocation) => null;
}

253 254 255 256 257 258
class MockDirectory implements Directory {
  MockDirectory(this.path);

  @override
  final String path;

259 260
  static bool findCache = false;

261 262 263 264 265 266 267
  @override
  bool existsSync() => findCache && path.endsWith('.pub-cache');

  @override
  dynamic noSuchMethod(Invocation invocation) => null;
}

268
class MockRandomAccessFile extends Mock implements RandomAccessFile {}