upgrade_test.dart 10.7 KB
Newer Older
1 2 3 4
// 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.

5
import 'package:flutter_tools/runner.dart' as runner;
6
import 'package:flutter_tools/src/base/common.dart';
7
import 'package:flutter_tools/src/base/file_system.dart';
8
import 'package:flutter_tools/src/base/io.dart';
9
import 'package:flutter_tools/src/base/platform.dart';
10
import 'package:flutter_tools/src/base/os.dart';
11
import 'package:flutter_tools/src/cache.dart';
12
import 'package:flutter_tools/src/commands/upgrade.dart';
13
import 'package:flutter_tools/src/persistent_tool_state.dart';
14 15 16
import 'package:flutter_tools/src/runner/flutter_command.dart';
import 'package:flutter_tools/src/version.dart';
import 'package:mockito/mockito.dart';
17
import 'package:platform/platform.dart';
18
import 'package:process/process.dart';
19

20 21
import '../../src/common.dart';
import '../../src/context.dart';
22
import '../../src/fake_process_manager.dart';
23
import '../../src/mocks.dart';
24

25
void main() {
26 27 28 29
  group('UpgradeCommandRunner', () {
    FakeUpgradeCommandRunner fakeCommandRunner;
    UpgradeCommandRunner realCommandRunner;
    MockProcessManager processManager;
30
    FakePlatform fakePlatform;
31 32 33 34 35 36 37 38
    final MockFlutterVersion flutterVersion = MockFlutterVersion();
    const GitTagVersion gitTagVersion = GitTagVersion(1, 2, 3, 4, 5, 'asd');
    when(flutterVersion.channel).thenReturn('dev');

    setUp(() {
      fakeCommandRunner = FakeUpgradeCommandRunner();
      realCommandRunner = UpgradeCommandRunner();
      processManager = MockProcessManager();
39 40 41 42 43 44 45 46 47 48 49 50
      when(processManager.start(
        <String>[
          fs.path.join('bin', 'flutter'),
          'upgrade',
          '--continue',
          '--no-version-check',
        ],
        environment: anyNamed('environment'),
        workingDirectory: anyNamed('workingDirectory'),
      )).thenAnswer((Invocation invocation) async {
        return Future<Process>.value(createMockProcess());
      });
51
      fakeCommandRunner.willHaveUncomittedChanges = false;
52
      fakePlatform = FakePlatform()..environment = Map<String, String>.unmodifiable(<String, String>{
53 54
        'ENV1': 'irrelevant',
        'ENV2': 'irrelevant',
55
      });
56 57
    });

58
    testUsingContext('throws on unknown tag, official branch,  noforce', () async {
59
      final Future<FlutterCommandResult> result = fakeCommandRunner.runCommand(
60
        false,
61 62 63 64 65
        false,
        const GitTagVersion.unknown(),
        flutterVersion,
      );
      expect(result, throwsA(isInstanceOf<ToolExit>()));
66 67
    }, overrides: <Type, Generator>{
      Platform: () => fakePlatform,
68 69
    });

70
    testUsingContext('does not throw on unknown tag, official branch, force', () async {
71 72
      final Future<FlutterCommandResult> result = fakeCommandRunner.runCommand(
        true,
73
        false,
74 75 76 77
        const GitTagVersion.unknown(),
        flutterVersion,
      );
      expect(await result, null);
78 79
    }, overrides: <Type, Generator>{
      ProcessManager: () => processManager,
80
      Platform: () => fakePlatform,
81 82
    });

83
    testUsingContext('throws tool exit with uncommitted changes', () async {
84 85
      fakeCommandRunner.willHaveUncomittedChanges = true;
      final Future<FlutterCommandResult> result = fakeCommandRunner.runCommand(
86
        false,
87 88 89 90 91
        false,
        gitTagVersion,
        flutterVersion,
      );
      expect(result, throwsA(isA<ToolExit>()));
92 93
    }, overrides: <Type, Generator>{
      Platform: () => fakePlatform,
94 95
    });

96
    testUsingContext('does not throw tool exit with uncommitted changes and force', () async {
97
      fakeCommandRunner.willHaveUncomittedChanges = true;
98

99 100
      final Future<FlutterCommandResult> result = fakeCommandRunner.runCommand(
        true,
101
        false,
102 103 104 105
        gitTagVersion,
        flutterVersion,
      );
      expect(await result, null);
106 107
    }, overrides: <Type, Generator>{
      ProcessManager: () => processManager,
108
      Platform: () => fakePlatform,
109 110
    });

111
    testUsingContext('Doesn\'t throw on known tag, dev branch, no force', () async {
112
      final Future<FlutterCommandResult> result = fakeCommandRunner.runCommand(
113
        false,
114 115 116 117 118
        false,
        gitTagVersion,
        flutterVersion,
      );
      expect(await result, null);
119 120
    }, overrides: <Type, Generator>{
      ProcessManager: () => processManager,
121
      Platform: () => fakePlatform,
122 123 124 125 126 127
    });

    testUsingContext('verifyUpstreamConfigured', () async {
      when(processManager.run(
        <String>['git', 'rev-parse', '@{u}'],
        environment:anyNamed('environment'),
128
        workingDirectory: anyNamed('workingDirectory')),
129 130 131 132 133 134 135
      ).thenAnswer((Invocation invocation) async {
        return FakeProcessResult()
          ..exitCode = 0;
      });
      await realCommandRunner.verifyUpstreamConfigured();
    }, overrides: <Type, Generator>{
      ProcessManager: () => processManager,
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
      Platform: () => fakePlatform,
    });

    testUsingContext('flutterUpgradeContinue passes env variables to child process', () async {
      await realCommandRunner.flutterUpgradeContinue();

      final VerificationResult result = verify(processManager.start(
        <String>[
          fs.path.join('bin', 'flutter'),
          'upgrade',
          '--continue',
          '--no-version-check',
        ],
        environment: captureAnyNamed('environment'),
        workingDirectory: anyNamed('workingDirectory'),
      ));

153 154
      expect(result.captured.first,
          <String, String>{ 'FLUTTER_ALREADY_LOCKED': 'true', ...fakePlatform.environment });
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
    }, overrides: <Type, Generator>{
      ProcessManager: () => processManager,
      Platform: () => fakePlatform,
    });

    testUsingContext('precacheArtifacts passes env variables to child process', () async {
      final List<String> precacheCommand = <String>[
        fs.path.join('bin', 'flutter'),
        '--no-color',
        '--no-version-check',
        'precache',
      ];

      when(processManager.start(
        precacheCommand,
        environment: anyNamed('environment'),
        workingDirectory: anyNamed('workingDirectory'),
      )).thenAnswer((Invocation invocation) async {
        return Future<Process>.value(createMockProcess());
      });

      await realCommandRunner.precacheArtifacts();

      final VerificationResult result = verify(processManager.start(
        precacheCommand,
        environment: captureAnyNamed('environment'),
        workingDirectory: anyNamed('workingDirectory'),
      ));

184 185
      expect(result.captured.first,
          <String, String>{ 'FLUTTER_ALREADY_LOCKED': 'true', ...fakePlatform.environment });
186 187 188
    }, overrides: <Type, Generator>{
      ProcessManager: () => processManager,
      Platform: () => fakePlatform,
189
    });
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232

    group('full command', () {
      final FakeProcessManager fakeProcessManager = FakeProcessManager.list(<FakeCommand>[
        const FakeCommand(command: <String>[
          'git', 'describe', '--match', 'v*.*.*', '--first-parent', '--long', '--tags',
        ]),
      ]);

      Directory tempDir;
      File flutterToolState;

      FlutterVersion mockFlutterVersion;

      setUp(() {
        Cache.disableLocking();
        tempDir = fs.systemTempDirectory.createTempSync('flutter_upgrade_test.');
        flutterToolState = tempDir.childFile('.flutter_tool_state');
        mockFlutterVersion = MockFlutterVersion(isStable: true);
      });

      tearDown(() {
        Cache.enableLocking();
        tryToDelete(tempDir);
      });

      testUsingContext('upgrade continue prints welcome message', () async {
        final UpgradeCommand upgradeCommand = UpgradeCommand(fakeCommandRunner);
        await runner.run(
          <String>[
            'upgrade',
            '--continue',
          ],
          <FlutterCommand>[
            upgradeCommand,
          ],
        );
        expect(testLogger.statusText, contains('Welcome to Flutter!'));
      }, overrides: <Type, Generator>{
        FlutterVersion: () => mockFlutterVersion,
        ProcessManager: () => fakeProcessManager,
        PersistentToolState: () => PersistentToolState(flutterToolState),
      });
    });
233 234 235
  });

  group('matchesGitLine', () {
236 237 238 239
    setUpAll(() {
      Cache.disableLocking();
    });

240
    bool _match(String line) => UpgradeCommandRunner.matchesGitLine(line);
241 242

    test('regex match', () {
243
      expect(_match(' .../flutter_gallery/lib/demo/buttons_demo.dart    | 10 +--'), true);
244 245 246 247
      expect(_match(' dev/benchmarks/complex_layout/lib/main.dart        |  24 +-'), true);

      expect(_match(' rename {packages/flutter/doc => dev/docs}/styles.html (92%)'), true);
      expect(_match(' delete mode 100644 doc/index.html'), true);
248
      expect(_match(' create mode 100644 examples/flutter_gallery/lib/gallery/demo.dart'), true);
249 250 251 252 253 254 255 256

      expect(_match('Fast-forward'), true);
    });

    test('regex doesn\'t match', () {
      expect(_match('Updating 79cfe1e..5046107'), false);
      expect(_match('229 files changed, 6179 insertions(+), 3065 deletions(-)'), false);
    });
257 258

    group('findProjectRoot', () {
259
      Directory tempDir;
260 261

      setUp(() async {
262
        tempDir = fs.systemTempDirectory.createTempSync('flutter_tools_upgrade_test.');
263 264 265
      });

      tearDown(() {
266
        tryToDelete(tempDir);
267 268 269
      });

      testUsingContext('in project', () async {
270
        final String projectPath = await createProject(tempDir);
271 272
        expect(findProjectRoot(projectPath), projectPath);
        expect(findProjectRoot(fs.path.join(projectPath, 'lib')), projectPath);
273

274
        final String hello = fs.path.join(Cache.flutterRoot, 'examples', 'hello_world');
275
        expect(findProjectRoot(hello), hello);
276
        expect(findProjectRoot(fs.path.join(hello, 'lib')), hello);
277 278 279
      });

      testUsingContext('outside project', () async {
280
        final String projectPath = await createProject(tempDir);
281
        expect(findProjectRoot(fs.directory(projectPath).parent.path), null);
282
        expect(findProjectRoot(Cache.flutterRoot), null);
283 284
      });
    });
285 286
  });
}
287 288

class FakeUpgradeCommandRunner extends UpgradeCommandRunner {
289 290
  bool willHaveUncomittedChanges = false;

291 292 293
  @override
  Future<void> verifyUpstreamConfigured() async {}

294 295 296
  @override
  Future<bool> hasUncomittedChanges() async => willHaveUncomittedChanges;

297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
  @override
  Future<void> resetChanges(GitTagVersion gitTagVersion) async {}

  @override
  Future<void> upgradeChannel(FlutterVersion flutterVersion) async {}

  @override
  Future<void> attemptFastForward() async {}

  @override
  Future<void> precacheArtifacts() async {}

  @override
  Future<void> updatePackages(FlutterVersion flutterVersion) async {}

  @override
  Future<void> runDoctor() async {}
}

316
class MockProcess extends Mock implements Process {}
317 318 319 320 321 322 323 324 325 326 327 328 329 330
class MockProcessManager extends Mock implements ProcessManager {}
class FakeProcessResult implements ProcessResult {
  @override
  int exitCode;

  @override
  int pid = 0;

  @override
  String stderr = '';

  @override
  String stdout = '';
}