flutter/packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart

365 lines
12 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright 2014 The Flutter 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 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/upgrade.dart';
import 'package:flutter_tools/src/convert.dart';
import 'package:flutter_tools/src/persistent_tool_state.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart';
import 'package:flutter_tools/src/version.dart';
import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
import 'package:process/process.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/fake_process_manager.dart';
import '../../src/mocks.dart';
void main() {
group('UpgradeCommandRunner', () {
FakeUpgradeCommandRunner fakeCommandRunner;
UpgradeCommandRunner realCommandRunner;
MockProcessManager processManager;
FakePlatform fakePlatform;
final MockFlutterVersion flutterVersion = MockFlutterVersion();
const GitTagVersion gitTagVersion = GitTagVersion(
x: 1,
y: 2,
z: 3,
hotfix: 4,
commits: 5,
hash: 'asd',
);
when(flutterVersion.channel).thenReturn('dev');
setUp(() {
fakeCommandRunner = FakeUpgradeCommandRunner();
realCommandRunner = UpgradeCommandRunner();
processManager = MockProcessManager();
when(processManager.start(
<String>[
globals.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());
});
fakeCommandRunner.willHaveUncomittedChanges = false;
fakePlatform = FakePlatform()..environment = Map<String, String>.unmodifiable(<String, String>{
'ENV1': 'irrelevant',
'ENV2': 'irrelevant',
});
});
testUsingContext('throws on unknown tag, official branch, noforce', () async {
final Future<FlutterCommandResult> result = fakeCommandRunner.runCommand(
force: false,
continueFlow: false,
testFlow: false,
gitTagVersion: const GitTagVersion.unknown(),
flutterVersion: flutterVersion,
);
expect(result, throwsToolExit());
}, overrides: <Type, Generator>{
Platform: () => fakePlatform,
});
testUsingContext('does not throw on unknown tag, official branch, force', () async {
final Future<FlutterCommandResult> result = fakeCommandRunner.runCommand(
force: true,
continueFlow: false,
testFlow: false,
gitTagVersion: const GitTagVersion.unknown(),
flutterVersion: flutterVersion,
);
expect(await result, FlutterCommandResult.success());
}, overrides: <Type, Generator>{
ProcessManager: () => processManager,
Platform: () => fakePlatform,
});
testUsingContext('throws tool exit with uncommitted changes', () async {
fakeCommandRunner.willHaveUncomittedChanges = true;
final Future<FlutterCommandResult> result = fakeCommandRunner.runCommand(
force: false,
continueFlow: false,
testFlow: false,
gitTagVersion: gitTagVersion,
flutterVersion: flutterVersion,
);
expect(result, throwsToolExit());
}, overrides: <Type, Generator>{
Platform: () => fakePlatform,
});
testUsingContext('does not throw tool exit with uncommitted changes and force', () async {
fakeCommandRunner.willHaveUncomittedChanges = true;
final Future<FlutterCommandResult> result = fakeCommandRunner.runCommand(
force: true,
continueFlow: false,
testFlow: false,
gitTagVersion: gitTagVersion,
flutterVersion: flutterVersion,
);
expect(await result, FlutterCommandResult.success());
}, overrides: <Type, Generator>{
ProcessManager: () => processManager,
Platform: () => fakePlatform,
});
testUsingContext("Doesn't throw on known tag, dev branch, no force", () async {
final Future<FlutterCommandResult> result = fakeCommandRunner.runCommand(
force: false,
continueFlow: false,
testFlow: false,
gitTagVersion: gitTagVersion,
flutterVersion: flutterVersion,
);
expect(await result, FlutterCommandResult.success());
}, overrides: <Type, Generator>{
ProcessManager: () => processManager,
Platform: () => fakePlatform,
});
testUsingContext("Doesn't continue on known tag, dev branch, no force, already up-to-date", () async {
const String revision = 'abc123';
when(flutterVersion.frameworkRevision).thenReturn(revision);
fakeCommandRunner.alreadyUpToDate = true;
fakeCommandRunner.remoteRevision = revision;
final Future<FlutterCommandResult> result = fakeCommandRunner.runCommand(
force: false,
continueFlow: false,
testFlow: false,
gitTagVersion: gitTagVersion,
flutterVersion: flutterVersion,
);
expect(await result, FlutterCommandResult.success());
verifyNever(globals.processManager.start(
<String>[
globals.fs.path.join('bin', 'flutter'),
'upgrade',
'--continue',
'--no-version-check',
],
environment: anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
));
expect(testLogger.statusText, contains('Flutter is already up to date'));
}, overrides: <Type, Generator>{
ProcessManager: () => processManager,
Platform: () => fakePlatform,
});
testUsingContext('fetchRemoteRevision', () async {
const String revision = 'abc123';
when(processManager.run(
<String>['git', 'fetch', '--tags'],
environment:anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory')),
).thenAnswer((Invocation invocation) async {
return FakeProcessResult()
..exitCode = 0;
});
when(processManager.run(
<String>['git', 'rev-parse', '--verify', '@{u}'],
environment:anyNamed('environment'),
workingDirectory: anyNamed('workingDirectory')),
).thenAnswer((Invocation invocation) async {
return FakeProcessResult()
..exitCode = 0
..stdout = revision;
});
expect(await realCommandRunner.fetchRemoteRevision(), revision);
}, overrides: <Type, Generator>{
ProcessManager: () => processManager,
Platform: () => fakePlatform,
});
testUsingContext('git exception during attemptReset throwsToolExit', () async {
const String revision = 'abc123';
const String errorMessage = 'fatal: Could not parse object ´$revision´';
when(processManager.run(
<String>['git', 'reset', '--hard', revision]
)).thenThrow(const ProcessException(
'git',
<String>['reset', '--hard', revision],
errorMessage,
));
expect(
() async => await realCommandRunner.attemptReset(revision),
throwsToolExit(message: errorMessage),
);
}, overrides: <Type, Generator>{
ProcessManager: () => processManager,
Platform: () => fakePlatform,
});
testUsingContext('flutterUpgradeContinue passes env variables to child process', () async {
await realCommandRunner.flutterUpgradeContinue();
final VerificationResult result = verify(globals.processManager.start(
<String>[
globals.fs.path.join('bin', 'flutter'),
'upgrade',
'--continue',
'--no-version-check',
],
environment: captureAnyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
));
expect(result.captured.first,
<String, String>{ 'FLUTTER_ALREADY_LOCKED': 'true', ...fakePlatform.environment });
}, overrides: <Type, Generator>{
ProcessManager: () => processManager,
Platform: () => fakePlatform,
});
testUsingContext('precacheArtifacts passes env variables to child process', () async {
final List<String> precacheCommand = <String>[
globals.fs.path.join('bin', 'flutter'),
'--no-color',
'--no-version-check',
'precache',
];
when(globals.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(globals.processManager.start(
precacheCommand,
environment: captureAnyNamed('environment'),
workingDirectory: anyNamed('workingDirectory'),
));
expect(result.captured.first,
<String, String>{ 'FLUTTER_ALREADY_LOCKED': 'true', ...fakePlatform.environment });
}, overrides: <Type, Generator>{
ProcessManager: () => processManager,
Platform: () => fakePlatform,
});
group('full command', () {
FakeProcessManager fakeProcessManager;
Directory tempDir;
File flutterToolState;
FlutterVersion mockFlutterVersion;
setUp(() {
Cache.disableLocking();
fakeProcessManager = FakeProcessManager.list(<FakeCommand>[
const FakeCommand(
command: <String>[
'git', 'tag', '--contains', 'HEAD',
],
stdout: '',
),
const FakeCommand(
command: <String>[
'git', 'describe', '--match', '*.*.*-*.*.pre', '--first-parent', '--long', '--tags',
],
stdout: 'v1.12.16-19-gb45b676af',
),
]);
tempDir = globals.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);
applyMocksToCommand(upgradeCommand);
await createTestCommandRunner(upgradeCommand).run(
<String>[
'upgrade',
'--continue',
],
);
expect(
json.decode(flutterToolState.readAsStringSync()),
containsPair('redisplay-welcome-message', true),
);
}, overrides: <Type, Generator>{
FlutterVersion: () => mockFlutterVersion,
ProcessManager: () => fakeProcessManager,
PersistentToolState: () => PersistentToolState.test(
directory: tempDir,
logger: testLogger,
),
});
});
});
}
class FakeUpgradeCommandRunner extends UpgradeCommandRunner {
bool willHaveUncomittedChanges = false;
bool alreadyUpToDate = false;
String remoteRevision = '';
@override
Future<String> fetchRemoteRevision() async => remoteRevision;
@override
Future<bool> hasUncomittedChanges() async => willHaveUncomittedChanges;
@override
Future<void> upgradeChannel(FlutterVersion flutterVersion) async {}
@override
Future<void> attemptReset(String newRevision) async {}
@override
Future<void> precacheArtifacts() async {}
@override
Future<void> updatePackages(FlutterVersion flutterVersion) async {}
@override
Future<void> runDoctor() async {}
}
class MockProcess extends Mock implements Process {}
class MockProcessManager extends Mock implements ProcessManager {}
class FakeProcessResult implements ProcessResult {
@override
int exitCode;
@override
int pid = 0;
@override
String stderr = '';
@override
String stdout = '';
}