flutter/packages/flutter_tools/test/channel_test.dart
Greg Spencer 7cebaac985
Makes switching channels remove version freshness stamp. (#21182)
When switching between channels, we were leaving around the version freshness stamp file (bin/cache/flutter_version_check.stamp), which meant that the flutter tool would read from that file to see what the cached date of the most recent commit to the current channel (branch) was. The problem was that since the file was created while on the previous channel, the cached date was for the wrong channel, so if you switch from master to beta, flutter would think that the channel was out of date, and a new version was available, at least for three days after the first time it checked (after three days since the last time the freshness was checked, the cached date would get updated).

This PR modifies the channel command to remove that stamp file whenever the user switches channels, so that the cached date will be from the right channel when it is recreated.

Fixes #21134
2018-08-29 21:53:39 -07:00

201 lines
8.0 KiB
Dart

// Copyright 2015 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' hide File;
import 'package:args/command_runner.dart';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/channel.dart';
import 'package:flutter_tools/src/version.dart';
import 'package:mockito/mockito.dart';
import 'package:process/process.dart';
import 'src/common.dart';
import 'src/context.dart';
Process createMockProcess({int exitCode = 0, String stdout = '', String stderr = ''}) {
final Stream<List<int>> stdoutStream = new Stream<List<int>>.fromIterable(<List<int>>[
utf8.encode(stdout),
]);
final Stream<List<int>> stderrStream = new Stream<List<int>>.fromIterable(<List<int>>[
utf8.encode(stderr),
]);
final Process process = new MockProcess();
when(process.stdout).thenAnswer((_) => stdoutStream);
when(process.stderr).thenAnswer((_) => stderrStream);
when(process.exitCode).thenAnswer((_) => new Future<int>.value(exitCode));
return process;
}
void main() {
group('channel', () {
final MockProcessManager mockProcessManager = new MockProcessManager();
setUpAll(() {
Cache.disableLocking();
});
testUsingContext('list', () async {
final ChannelCommand command = new ChannelCommand();
final CommandRunner<Null> runner = createTestCommandRunner(command);
await runner.run(<String>['channel']);
expect(testLogger.errorText, hasLength(0));
// The bots may return an empty list of channels (network hiccup?)
// and when run locally the list of branches might be different
// so we check for the header text rather than any specific channel name.
expect(testLogger.statusText, contains('Flutter channels:'));
});
testUsingContext('removes duplicates', () async {
final Process process = createMockProcess(
stdout: 'origin/dev\n'
'origin/beta\n'
'upstream/dev\n'
'upstream/beta\n');
when(mockProcessManager.start(
<String>['git', 'branch', '-r'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).thenAnswer((_) => new Future<Process>.value(process));
final ChannelCommand command = new ChannelCommand();
final CommandRunner<Null> runner = createTestCommandRunner(command);
await runner.run(<String>['channel']);
verify(mockProcessManager.start(
<String>['git', 'branch', '-r'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).called(1);
expect(testLogger.errorText, hasLength(0));
// format the status text for a simpler assertion.
final Iterable<String> rows = testLogger.statusText
.split('\n')
.map((String line) => line.trim())
.where((String line) => line?.isNotEmpty == true)
.skip(1); // remove `Flutter channels:` line
expect(rows, <String>['dev', 'beta']);
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
});
testUsingContext('can switch channels', () async {
when(mockProcessManager.start(
<String>['git', 'fetch'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).thenAnswer((_) => new Future<Process>.value(createMockProcess()));
when(mockProcessManager.start(
<String>['git', 'show-ref', '--verify', '--quiet', 'refs/heads/beta'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).thenAnswer((_) => new Future<Process>.value(createMockProcess()));
when(mockProcessManager.start(
<String>['git', 'checkout', 'beta', '--'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).thenAnswer((_) => new Future<Process>.value(createMockProcess()));
final ChannelCommand command = new ChannelCommand();
final CommandRunner<Null> runner = createTestCommandRunner(command);
await runner.run(<String>['channel', 'beta']);
verify(mockProcessManager.start(
<String>['git', 'fetch'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).called(1);
verify(mockProcessManager.start(
<String>['git', 'show-ref', '--verify', '--quiet', 'refs/heads/beta'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).called(1);
verify(mockProcessManager.start(
<String>['git', 'checkout', 'beta', '--'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).called(1);
expect(testLogger.statusText, contains("Switching to flutter channel 'beta'..."));
expect(testLogger.errorText, hasLength(0));
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
FileSystem: () => new MemoryFileSystem(),
});
// This verifies that bug https://github.com/flutter/flutter/issues/21134
// doesn't return.
testUsingContext('removes version stamp file when switching channels', () async {
when(mockProcessManager.start(
<String>['git', 'fetch'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).thenAnswer((_) => new Future<Process>.value(createMockProcess()));
when(mockProcessManager.start(
<String>['git', 'show-ref', '--verify', '--quiet', 'refs/heads/beta'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).thenAnswer((_) => new Future<Process>.value(createMockProcess()));
when(mockProcessManager.start(
<String>['git', 'checkout', 'beta', '--'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).thenAnswer((_) => new Future<Process>.value(createMockProcess()));
final File versionCheckFile = Cache.instance.getStampFileFor(
VersionCheckStamp.kFlutterVersionCheckStampFile,
);
/// Create a bogus "leftover" version check file to make sure it gets
/// removed when the channel changes. The content doesn't matter.
versionCheckFile.createSync(recursive: true);
versionCheckFile.writeAsStringSync('''
{
"lastTimeVersionWasChecked": "2151-08-29 10:17:30.763802",
"lastKnownRemoteVersion": "2151-09-26 15:56:19.000Z"
}
''');
final ChannelCommand command = new ChannelCommand();
final CommandRunner<Null> runner = createTestCommandRunner(command);
await runner.run(<String>['channel', 'beta']);
verify(mockProcessManager.start(
<String>['git', 'fetch'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).called(1);
verify(mockProcessManager.start(
<String>['git', 'show-ref', '--verify', '--quiet', 'refs/heads/beta'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).called(1);
verify(mockProcessManager.start(
<String>['git', 'checkout', 'beta', '--'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).called(1);
expect(testLogger.statusText, isNot(contains('A new version of Flutter')));
expect(testLogger.errorText, hasLength(0));
expect(versionCheckFile.existsSync(), isFalse);
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
FileSystem: () => new MemoryFileSystem(),
});
});
}
class MockProcessManager extends Mock implements ProcessManager {}
class MockProcess extends Mock implements Process {}