mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00

update flutter precache --force to delete all stamp files. In the event that a user is hitting a cache issue, this should be easier than re-downloading all artifacts or manually blowing away the cache. This is probably how it should have worked in the first place
774 lines
31 KiB
Dart
774 lines
31 KiB
Dart
// 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:file/file.dart';
|
|
import 'package:file/memory.dart';
|
|
import 'package:file_testing/file_testing.dart';
|
|
import 'package:flutter_tools/src/android/gradle_utils.dart';
|
|
import 'package:flutter_tools/src/base/file_system.dart';
|
|
import 'package:flutter_tools/src/base/io.dart' show InternetAddress, SocketException;
|
|
import 'package:flutter_tools/src/base/io.dart';
|
|
import 'package:flutter_tools/src/base/logger.dart';
|
|
import 'package:flutter_tools/src/base/net.dart';
|
|
import 'package:flutter_tools/src/base/os.dart';
|
|
import 'package:flutter_tools/src/base/platform.dart';
|
|
import 'package:flutter_tools/src/cache.dart';
|
|
import 'package:flutter_tools/src/globals.dart' as globals;
|
|
import 'package:meta/meta.dart';
|
|
import 'package:mockito/mockito.dart';
|
|
import 'package:process/process.dart';
|
|
|
|
import '../src/common.dart';
|
|
import '../src/context.dart';
|
|
import '../src/testbed.dart';
|
|
|
|
void main() {
|
|
group('$Cache.checkLockAcquired', () {
|
|
MockFileSystem mockFileSystem;
|
|
MemoryFileSystem memoryFileSystem;
|
|
MockFile mockFile;
|
|
MockRandomAccessFile mockRandomAccessFile;
|
|
|
|
setUp(() {
|
|
mockFileSystem = MockFileSystem();
|
|
memoryFileSystem = MemoryFileSystem();
|
|
mockFile = MockFile();
|
|
mockRandomAccessFile = MockRandomAccessFile();
|
|
when(mockFileSystem.path).thenReturn(memoryFileSystem.path);
|
|
|
|
Cache.enableLocking();
|
|
});
|
|
|
|
tearDown(() {
|
|
// Restore locking to prevent potential side-effects in
|
|
// tests outside this group (this option is globally shared).
|
|
Cache.enableLocking();
|
|
Cache.releaseLock();
|
|
});
|
|
|
|
test('should throw when locking is not acquired', () {
|
|
expect(() => Cache.checkLockAcquired(), throwsStateError);
|
|
});
|
|
|
|
test('should not throw when locking is disabled', () {
|
|
Cache.disableLocking();
|
|
Cache.checkLockAcquired();
|
|
});
|
|
|
|
testUsingContext('should not throw when lock is acquired', () async {
|
|
when(mockFileSystem.file(argThat(endsWith('lockfile')))).thenReturn(mockFile);
|
|
when(mockFile.openSync(mode: anyNamed('mode'))).thenReturn(mockRandomAccessFile);
|
|
await Cache.lock();
|
|
Cache.checkLockAcquired();
|
|
Cache.releaseLock();
|
|
}, overrides: <Type, Generator>{
|
|
FileSystem: () => mockFileSystem,
|
|
ProcessManager: () => FakeProcessManager.any(),
|
|
});
|
|
|
|
testUsingContext('throws tool exit when lockfile open fails', () async {
|
|
when(mockFileSystem.file(argThat(endsWith('lockfile')))).thenReturn(mockFile);
|
|
when(mockFile.openSync(mode: anyNamed('mode'))).thenThrow(const FileSystemException());
|
|
expect(() async => await Cache.lock(), throwsToolExit());
|
|
}, overrides: <Type, Generator>{
|
|
FileSystem: () => mockFileSystem,
|
|
ProcessManager: () => FakeProcessManager.any(),
|
|
});
|
|
|
|
testUsingContext('should not throw when FLUTTER_ALREADY_LOCKED is set', () async {
|
|
Cache.checkLockAcquired();
|
|
}, overrides: <Type, Generator>{
|
|
Platform: () => FakePlatform()..environment = <String, String>{'FLUTTER_ALREADY_LOCKED': 'true'},
|
|
});
|
|
});
|
|
|
|
group('Cache', () {
|
|
MockCache mockCache;
|
|
MemoryFileSystem memoryFileSystem;
|
|
|
|
setUp(() {
|
|
mockCache = MockCache();
|
|
memoryFileSystem = MemoryFileSystem();
|
|
});
|
|
|
|
testUsingContext('Continues on failed delete', () async {
|
|
final Directory artifactDir = globals.fs.systemTempDirectory.createTempSync('flutter_cache_test_artifact.');
|
|
final Directory downloadDir = globals.fs.systemTempDirectory.createTempSync('flutter_cache_test_download.');
|
|
when(mockCache.getArtifactDirectory(any)).thenReturn(artifactDir);
|
|
when(mockCache.getDownloadDir()).thenReturn(downloadDir);
|
|
final File mockFile = MockFile();
|
|
when(mockFile.deleteSync()).thenAnswer((_) {
|
|
throw const FileSystemException('delete failed');
|
|
});
|
|
final FakeDownloadedArtifact artifact = FakeDownloadedArtifact(
|
|
mockFile,
|
|
mockCache,
|
|
);
|
|
await artifact.update();
|
|
expect(testLogger.errorText, contains('delete failed'));
|
|
}, overrides: <Type, Generator>{
|
|
Cache: () => mockCache,
|
|
FileSystem: () => memoryFileSystem,
|
|
ProcessManager: () => FakeProcessManager.any(),
|
|
});
|
|
|
|
testUsingContext('Continues on failed stamp file update', () async {
|
|
final Directory artifactDir = globals.fs.systemTempDirectory.createTempSync('flutter_cache_test_artifact.');
|
|
final Directory downloadDir = globals.fs.systemTempDirectory.createTempSync('flutter_cache_test_download.');
|
|
when(mockCache.getArtifactDirectory(any)).thenReturn(artifactDir);
|
|
when(mockCache.getDownloadDir()).thenReturn(downloadDir);
|
|
when(mockCache.setStampFor(any, any)).thenAnswer((_) {
|
|
throw const FileSystemException('stamp write failed');
|
|
});
|
|
final FakeSimpleArtifact artifact = FakeSimpleArtifact(mockCache);
|
|
await artifact.update();
|
|
expect(testLogger.errorText, contains('stamp write failed'));
|
|
}, overrides: <Type, Generator>{
|
|
Cache: () => mockCache,
|
|
FileSystem: () => memoryFileSystem,
|
|
ProcessManager: () => FakeProcessManager.any(),
|
|
});
|
|
|
|
testUsingContext('Gradle wrapper should not be up to date, if some cached artifact is not available', () {
|
|
final GradleWrapper gradleWrapper = GradleWrapper(mockCache);
|
|
final Directory directory = globals.fs.directory('/Applications/flutter/bin/cache');
|
|
directory.createSync(recursive: true);
|
|
globals.fs.file(globals.fs.path.join(directory.path, 'artifacts', 'gradle_wrapper', 'gradle', 'wrapper', 'gradle-wrapper.jar')).createSync(recursive: true);
|
|
when(mockCache.getCacheDir(globals.fs.path.join('artifacts', 'gradle_wrapper'))).thenReturn(globals.fs.directory(globals.fs.path.join(directory.path, 'artifacts', 'gradle_wrapper')));
|
|
expect(gradleWrapper.isUpToDateInner(), false);
|
|
}, overrides: <Type, Generator>{
|
|
Cache: () => mockCache,
|
|
FileSystem: () => memoryFileSystem,
|
|
ProcessManager: () => FakeProcessManager.any(),
|
|
});
|
|
|
|
testUsingContext('Gradle wrapper should be up to date, only if all cached artifact are available', () {
|
|
final GradleWrapper gradleWrapper = GradleWrapper(mockCache);
|
|
final Directory directory = globals.fs.directory('/Applications/flutter/bin/cache');
|
|
directory.createSync(recursive: true);
|
|
globals.fs.file(globals.fs.path.join(directory.path, 'artifacts', 'gradle_wrapper', 'gradle', 'wrapper', 'gradle-wrapper.jar')).createSync(recursive: true);
|
|
globals.fs.file(globals.fs.path.join(directory.path, 'artifacts', 'gradle_wrapper', 'gradlew')).createSync(recursive: true);
|
|
globals.fs.file(globals.fs.path.join(directory.path, 'artifacts', 'gradle_wrapper', 'gradlew.bat')).createSync(recursive: true);
|
|
|
|
when(mockCache.getCacheDir(globals.fs.path.join('artifacts', 'gradle_wrapper'))).thenReturn(globals.fs.directory(globals.fs.path.join(directory.path, 'artifacts', 'gradle_wrapper')));
|
|
expect(gradleWrapper.isUpToDateInner(), true);
|
|
}, overrides: <Type, Generator>{
|
|
Cache: () => mockCache,
|
|
FileSystem: () => memoryFileSystem,
|
|
ProcessManager: () => FakeProcessManager.any(),
|
|
});
|
|
|
|
test('should not be up to date, if some cached artifact is not', () {
|
|
final CachedArtifact artifact1 = MockCachedArtifact();
|
|
final CachedArtifact artifact2 = MockCachedArtifact();
|
|
when(artifact1.isUpToDate()).thenReturn(true);
|
|
when(artifact2.isUpToDate()).thenReturn(false);
|
|
final Cache cache = Cache(artifacts: <CachedArtifact>[artifact1, artifact2]);
|
|
expect(cache.isUpToDate(), isFalse);
|
|
});
|
|
test('should be up to date, if all cached artifacts are', () {
|
|
final CachedArtifact artifact1 = MockCachedArtifact();
|
|
final CachedArtifact artifact2 = MockCachedArtifact();
|
|
when(artifact1.isUpToDate()).thenReturn(true);
|
|
when(artifact2.isUpToDate()).thenReturn(true);
|
|
final Cache cache = Cache(artifacts: <CachedArtifact>[artifact1, artifact2]);
|
|
expect(cache.isUpToDate(), isTrue);
|
|
});
|
|
test('should update cached artifacts which are not up to date', () async {
|
|
final CachedArtifact artifact1 = MockCachedArtifact();
|
|
final CachedArtifact artifact2 = MockCachedArtifact();
|
|
when(artifact1.isUpToDate()).thenReturn(true);
|
|
when(artifact2.isUpToDate()).thenReturn(false);
|
|
final Cache cache = Cache(artifacts: <CachedArtifact>[artifact1, artifact2]);
|
|
await cache.updateAll(<DevelopmentArtifact>{
|
|
null,
|
|
});
|
|
verifyNever(artifact1.update());
|
|
verify(artifact2.update());
|
|
});
|
|
testUsingContext("getter dyLdLibEntry concatenates the output of each artifact's dyLdLibEntry getter", () async {
|
|
final IosUsbArtifacts artifact1 = MockIosUsbArtifacts();
|
|
final IosUsbArtifacts artifact2 = MockIosUsbArtifacts();
|
|
final IosUsbArtifacts artifact3 = MockIosUsbArtifacts();
|
|
when(artifact1.environment)
|
|
.thenReturn(<String, String>{
|
|
'DYLD_LIBRARY_PATH': '/path/to/alpha:/path/to/beta',
|
|
});
|
|
when(artifact2.environment)
|
|
.thenReturn(<String, String>{
|
|
'DYLD_LIBRARY_PATH': '/path/to/gamma:/path/to/delta:/path/to/epsilon',
|
|
});
|
|
when(artifact3.environment)
|
|
.thenReturn(<String, String>{
|
|
'DYLD_LIBRARY_PATH': '',
|
|
});
|
|
final Cache cache = Cache(artifacts: <CachedArtifact>[artifact1, artifact2, artifact3]);
|
|
|
|
expect(cache.dyLdLibEntry.key, 'DYLD_LIBRARY_PATH');
|
|
expect(
|
|
cache.dyLdLibEntry.value,
|
|
'/path/to/alpha:/path/to/beta:/path/to/gamma:/path/to/delta:/path/to/epsilon',
|
|
);
|
|
}, overrides: <Type, Generator>{
|
|
Cache: () => mockCache,
|
|
});
|
|
testUsingContext('failed storage.googleapis.com download shows China warning', () async {
|
|
final CachedArtifact artifact1 = MockCachedArtifact();
|
|
final CachedArtifact artifact2 = MockCachedArtifact();
|
|
when(artifact1.isUpToDate()).thenReturn(false);
|
|
when(artifact2.isUpToDate()).thenReturn(false);
|
|
final MockInternetAddress address = MockInternetAddress();
|
|
when(address.host).thenReturn('storage.googleapis.com');
|
|
when(artifact1.update()).thenThrow(SocketException(
|
|
'Connection reset by peer',
|
|
address: address,
|
|
));
|
|
final Cache cache = Cache(artifacts: <CachedArtifact>[artifact1, artifact2]);
|
|
try {
|
|
await cache.updateAll(<DevelopmentArtifact>{
|
|
null,
|
|
});
|
|
fail('Mock thrown exception expected');
|
|
} on Exception {
|
|
verify(artifact1.update());
|
|
// Don't continue when retrieval fails.
|
|
verifyNever(artifact2.update());
|
|
expect(
|
|
testLogger.errorText,
|
|
contains('https://flutter.dev/community/china'),
|
|
);
|
|
}
|
|
});
|
|
|
|
testUsingContext('Invalid URI for FLUTTER_STORAGE_BASE_URL throws ToolExit', () async {
|
|
final Cache cache = Cache();
|
|
|
|
expect(() => cache.storageBaseUrl, throwsToolExit());
|
|
}, overrides: <Type, Generator>{
|
|
Platform: () => FakePlatform(environment: <String, String>{
|
|
'FLUTTER_STORAGE_BASE_URL': ' http://foo',
|
|
}),
|
|
});
|
|
});
|
|
|
|
testUsingContext('flattenNameSubdirs', () {
|
|
expect(flattenNameSubdirs(Uri.parse('http://flutter.dev/foo/bar')), 'flutter.dev/foo/bar');
|
|
expect(flattenNameSubdirs(Uri.parse('http://docs.flutter.io/foo/bar')), 'docs.flutter.io/foo/bar');
|
|
expect(flattenNameSubdirs(Uri.parse('https://www.flutter.dev')), 'www.flutter.dev');
|
|
}, overrides: <Type, Generator>{
|
|
FileSystem: () => MemoryFileSystem(),
|
|
ProcessManager: () => FakeProcessManager.any(),
|
|
});
|
|
|
|
test('Unstable artifacts', () {
|
|
expect(DevelopmentArtifact.web.unstable, false);
|
|
expect(DevelopmentArtifact.linux.unstable, false);
|
|
expect(DevelopmentArtifact.macOS.unstable, false);
|
|
expect(DevelopmentArtifact.windows.unstable, false);
|
|
expect(DevelopmentArtifact.fuchsia.unstable, true);
|
|
expect(DevelopmentArtifact.flutterRunner.unstable, true);
|
|
});
|
|
|
|
group('EngineCachedArtifact', () {
|
|
FakeHttpClient fakeHttpClient;
|
|
FakePlatform fakePlatform;
|
|
MemoryFileSystem memoryFileSystem;
|
|
MockCache mockCache;
|
|
MockOperatingSystemUtils mockOperatingSystemUtils;
|
|
MockHttpClient mockHttpClient;
|
|
|
|
setUp(() {
|
|
fakeHttpClient = FakeHttpClient();
|
|
mockHttpClient = MockHttpClient();
|
|
fakePlatform = FakePlatform()..environment = const <String, String>{};
|
|
memoryFileSystem = MemoryFileSystem();
|
|
mockCache = MockCache();
|
|
mockOperatingSystemUtils = MockOperatingSystemUtils();
|
|
});
|
|
|
|
testUsingContext('makes binary dirs readable and executable by all', () async {
|
|
when(mockOperatingSystemUtils.verifyZip(any)).thenReturn(true);
|
|
final Directory artifactDir = globals.fs.systemTempDirectory.createTempSync('flutter_cache_test_artifact.');
|
|
final Directory downloadDir = globals.fs.systemTempDirectory.createTempSync('flutter_cache_test_download.');
|
|
when(mockCache.getArtifactDirectory(any)).thenReturn(artifactDir);
|
|
when(mockCache.getDownloadDir()).thenReturn(downloadDir);
|
|
final FakeCachedArtifact artifact = FakeCachedArtifact(
|
|
cache: mockCache,
|
|
binaryDirs: <List<String>>[
|
|
<String>['bin_dir', 'unused_url_path'],
|
|
],
|
|
requiredArtifacts: DevelopmentArtifact.universal,
|
|
);
|
|
await artifact.updateInner();
|
|
final Directory dir = memoryFileSystem.systemTempDirectory
|
|
.listSync(recursive: true)
|
|
.whereType<Directory>()
|
|
.singleWhere((Directory directory) => directory.basename == 'bin_dir', orElse: () => null);
|
|
expect(dir, isNotNull);
|
|
expect(dir.path, artifactDir.childDirectory('bin_dir').path);
|
|
verify(mockOperatingSystemUtils.chmod(argThat(hasPath(dir.path)), 'a+r,a+x'));
|
|
}, overrides: <Type, Generator>{
|
|
Cache: () => mockCache,
|
|
FileSystem: () => memoryFileSystem,
|
|
ProcessManager: () => FakeProcessManager.any(),
|
|
HttpClientFactory: () => () => fakeHttpClient,
|
|
OperatingSystemUtils: () => mockOperatingSystemUtils,
|
|
Platform: () => fakePlatform,
|
|
});
|
|
|
|
testUsingContext('prints a friendly name when downloading', () async {
|
|
when(mockOperatingSystemUtils.verifyZip(any)).thenReturn(false);
|
|
final MockHttpClientRequest httpClientRequest = MockHttpClientRequest();
|
|
final MockHttpClientResponse httpClientResponse = MockHttpClientResponse();
|
|
when(httpClientResponse.statusCode).thenReturn(200);
|
|
|
|
when(httpClientRequest.close()).thenAnswer((_) async => httpClientResponse);
|
|
when(mockHttpClient.getUrl(any)).thenAnswer((_) async => httpClientRequest);
|
|
|
|
final Directory artifactDir = globals.fs.systemTempDirectory.createTempSync('flutter_cache_test_artifact.');
|
|
final Directory downloadDir = globals.fs.systemTempDirectory.createTempSync('flutter_cache_test_download.');
|
|
when(mockCache.getArtifactDirectory(any)).thenReturn(artifactDir);
|
|
when(mockCache.getDownloadDir()).thenReturn(downloadDir);
|
|
final FakeCachedArtifact artifact = FakeCachedArtifact(
|
|
cache: mockCache,
|
|
binaryDirs: <List<String>>[
|
|
<String>['bin_dir', 'darwin-x64/artifacts.zip'],
|
|
<String>['font-subset', 'darwin-x64/font-subset.zip'],
|
|
],
|
|
requiredArtifacts: DevelopmentArtifact.universal,
|
|
);
|
|
await artifact.updateInner();
|
|
expect(testLogger.statusText, isNotNull);
|
|
expect(testLogger.statusText, isNotEmpty);
|
|
expect(
|
|
testLogger.statusText.split('\n'),
|
|
<String>[
|
|
'Downloading darwin-x64 tools...',
|
|
'Downloading darwin-x64/font-subset tools...',
|
|
'',
|
|
],
|
|
);
|
|
}, overrides: <Type, Generator>{
|
|
Cache: () => mockCache,
|
|
FileSystem: () => memoryFileSystem,
|
|
ProcessManager: () => FakeProcessManager.any(),
|
|
HttpClientFactory: () => () => mockHttpClient,
|
|
OperatingSystemUtils: () => mockOperatingSystemUtils,
|
|
Platform: () => fakePlatform,
|
|
});
|
|
});
|
|
|
|
group('AndroidMavenArtifacts', () {
|
|
MemoryFileSystem memoryFileSystem;
|
|
MockProcessManager processManager;
|
|
MockCache mockCache;
|
|
|
|
setUp(() {
|
|
memoryFileSystem = MemoryFileSystem();
|
|
processManager = MockProcessManager();
|
|
mockCache = MockCache();
|
|
});
|
|
|
|
test('development artifact', () async {
|
|
final AndroidMavenArtifacts mavenArtifacts = AndroidMavenArtifacts(mockCache);
|
|
expect(mavenArtifacts.developmentArtifact, DevelopmentArtifact.androidMaven);
|
|
});
|
|
|
|
testUsingContext('update', () async {
|
|
final Directory cacheRoot = globals.fs.directory('/bin/cache')
|
|
..createSync(recursive: true);
|
|
when(mockCache.getRoot()).thenReturn(cacheRoot);
|
|
final AndroidMavenArtifacts mavenArtifacts = AndroidMavenArtifacts(mockCache);
|
|
expect(mavenArtifacts.isUpToDate(), isFalse);
|
|
|
|
final Directory gradleWrapperDir = globals.fs.systemTempDirectory.createTempSync('flutter_cache_test_gradle_wrapper.');
|
|
when(mockCache.getArtifactDirectory('gradle_wrapper')).thenReturn(gradleWrapperDir);
|
|
|
|
globals.fs.directory(gradleWrapperDir.childDirectory('gradle').childDirectory('wrapper'))
|
|
.createSync(recursive: true);
|
|
globals.fs.file(globals.fs.path.join(gradleWrapperDir.path, 'gradlew')).writeAsStringSync('irrelevant');
|
|
globals.fs.file(globals.fs.path.join(gradleWrapperDir.path, 'gradlew.bat')).writeAsStringSync('irrelevant');
|
|
|
|
when(globals.processManager.run(any, environment: captureAnyNamed('environment')))
|
|
.thenAnswer((Invocation invocation) {
|
|
final List<String> args = invocation.positionalArguments[0] as List<String>;
|
|
expect(args.length, 6);
|
|
expect(args[1], '-b');
|
|
expect(args[2].endsWith('resolve_dependencies.gradle'), isTrue);
|
|
expect(args[5], 'resolveDependencies');
|
|
expect(invocation.namedArguments[#environment], gradleEnvironment);
|
|
return Future<ProcessResult>.value(ProcessResult(0, 0, '', ''));
|
|
});
|
|
|
|
await mavenArtifacts.update();
|
|
|
|
expect(mavenArtifacts.isUpToDate(), isFalse);
|
|
}, overrides: <Type, Generator>{
|
|
Cache: () => mockCache,
|
|
FileSystem: () => memoryFileSystem,
|
|
ProcessManager: () => processManager,
|
|
});
|
|
});
|
|
|
|
group('macOS artifacts', () {
|
|
MockCache mockCache;
|
|
|
|
setUp(() {
|
|
mockCache = MockCache();
|
|
});
|
|
|
|
testUsingContext('verifies executables for libimobiledevice in isUpToDateInner', () async {
|
|
final IosUsbArtifacts iosUsbArtifacts = IosUsbArtifacts('libimobiledevice', mockCache);
|
|
when(mockCache.getArtifactDirectory(any)).thenReturn(globals.fs.currentDirectory);
|
|
iosUsbArtifacts.location.createSync();
|
|
final File ideviceScreenshotFile = iosUsbArtifacts.location.childFile('idevicescreenshot')
|
|
..createSync();
|
|
iosUsbArtifacts.location.childFile('idevicesyslog')
|
|
.createSync();
|
|
|
|
expect(iosUsbArtifacts.isUpToDateInner(), true);
|
|
|
|
ideviceScreenshotFile.deleteSync();
|
|
|
|
expect(iosUsbArtifacts.isUpToDateInner(), false);
|
|
}, overrides: <Type, Generator>{
|
|
Cache: () => mockCache,
|
|
FileSystem: () => MemoryFileSystem(),
|
|
ProcessManager: () => FakeProcessManager.any(),
|
|
});
|
|
|
|
testUsingContext('verifies iproxy for usbmuxd in isUpToDateInner', () async {
|
|
final IosUsbArtifacts iosUsbArtifacts = IosUsbArtifacts('usbmuxd', mockCache);
|
|
when(mockCache.getArtifactDirectory(any)).thenReturn(globals.fs.currentDirectory);
|
|
iosUsbArtifacts.location.createSync();
|
|
final File iproxy = iosUsbArtifacts.location.childFile('iproxy')
|
|
..createSync();
|
|
|
|
expect(iosUsbArtifacts.isUpToDateInner(), true);
|
|
|
|
iproxy.deleteSync();
|
|
|
|
expect(iosUsbArtifacts.isUpToDateInner(), false);
|
|
}, overrides: <Type, Generator>{
|
|
Cache: () => mockCache,
|
|
FileSystem: () => MemoryFileSystem(),
|
|
ProcessManager: () => FakeProcessManager.any(),
|
|
});
|
|
|
|
testUsingContext('Does not verify executables for openssl in isUpToDateInner', () async {
|
|
final IosUsbArtifacts iosUsbArtifacts = IosUsbArtifacts('openssl', mockCache);
|
|
when(mockCache.getArtifactDirectory(any)).thenReturn(globals.fs.currentDirectory);
|
|
iosUsbArtifacts.location.createSync();
|
|
|
|
expect(iosUsbArtifacts.isUpToDateInner(), true);
|
|
}, overrides: <Type, Generator>{
|
|
Cache: () => mockCache,
|
|
FileSystem: () => MemoryFileSystem(),
|
|
ProcessManager: () => FakeProcessManager.any(),
|
|
});
|
|
|
|
testUsingContext('use unsigned when specified', () async {
|
|
when(mockCache.useUnsignedMacBinaries).thenReturn(true);
|
|
|
|
final IosUsbArtifacts iosUsbArtifacts = IosUsbArtifacts('name', mockCache);
|
|
expect(iosUsbArtifacts.archiveUri.toString(), contains('/unsigned/'));
|
|
}, overrides: <Type, Generator>{
|
|
Cache: () => mockCache,
|
|
});
|
|
|
|
testUsingContext('not use unsigned when not specified', () async {
|
|
when(mockCache.useUnsignedMacBinaries).thenReturn(false);
|
|
|
|
final IosUsbArtifacts iosUsbArtifacts = IosUsbArtifacts('name', mockCache);
|
|
expect(iosUsbArtifacts.archiveUri.toString(), isNot(contains('/unsigned/')));
|
|
}, overrides: <Type, Generator>{
|
|
Cache: () => mockCache,
|
|
});
|
|
});
|
|
|
|
group('Flutter runner debug symbols', () {
|
|
MockCache mockCache;
|
|
MockVersionedPackageResolver mockPackageResolver;
|
|
|
|
setUp(() {
|
|
mockCache = MockCache();
|
|
mockPackageResolver = MockVersionedPackageResolver();
|
|
});
|
|
|
|
testUsingContext('Downloads Flutter runner debug symbols', () async {
|
|
final FlutterRunnerDebugSymbols flutterRunnerDebugSymbols =
|
|
FlutterRunnerDebugSymbols(mockCache, packageResolver: mockPackageResolver, dryRun: true);
|
|
|
|
await flutterRunnerDebugSymbols.updateInner();
|
|
|
|
verifyInOrder(<void>[
|
|
mockPackageResolver.resolveUrl('fuchsia-debug-symbols-x64', any),
|
|
mockPackageResolver.resolveUrl('fuchsia-debug-symbols-arm64', any),
|
|
]);
|
|
});
|
|
}, skip: !globals.platform.isLinux);
|
|
|
|
|
|
testUsingContext('FontSubset in univeral artifacts', () {
|
|
final MockCache mockCache = MockCache();
|
|
final FontSubsetArtifacts artifacts = FontSubsetArtifacts(mockCache);
|
|
expect(artifacts.developmentArtifact, DevelopmentArtifact.universal);
|
|
});
|
|
|
|
testUsingContext('FontSubset artifacts on linux', () {
|
|
final MockCache mockCache = MockCache();
|
|
final FontSubsetArtifacts artifacts = FontSubsetArtifacts(mockCache);
|
|
when(mockCache.includeAllPlatforms).thenReturn(false);
|
|
expect(artifacts.getBinaryDirs(), <List<String>>[<String>['linux-x64', 'linux-x64/font-subset.zip']]);
|
|
}, overrides: <Type, Generator> {
|
|
Platform: () => FakePlatform(operatingSystem: 'linux'),
|
|
});
|
|
|
|
testUsingContext('FontSubset artifacts on windows', () {
|
|
final MockCache mockCache = MockCache();
|
|
final FontSubsetArtifacts artifacts = FontSubsetArtifacts(mockCache);
|
|
when(mockCache.includeAllPlatforms).thenReturn(false);
|
|
expect(artifacts.getBinaryDirs(), <List<String>>[<String>['windows-x64', 'windows-x64/font-subset.zip']]);
|
|
}, overrides: <Type, Generator> {
|
|
Platform: () => FakePlatform(operatingSystem: 'windows'),
|
|
});
|
|
|
|
testUsingContext('FontSubset artifacts on macos', () {
|
|
final MockCache mockCache = MockCache();
|
|
final FontSubsetArtifacts artifacts = FontSubsetArtifacts(mockCache);
|
|
when(mockCache.includeAllPlatforms).thenReturn(false);
|
|
expect(artifacts.getBinaryDirs(), <List<String>>[<String>['darwin-x64', 'darwin-x64/font-subset.zip']]);
|
|
}, overrides: <Type, Generator> {
|
|
Platform: () => FakePlatform(operatingSystem: 'macos'),
|
|
});
|
|
|
|
testUsingContext('FontSubset artifacts on fuchsia', () {
|
|
final MockCache mockCache = MockCache();
|
|
final FontSubsetArtifacts artifacts = FontSubsetArtifacts(mockCache);
|
|
when(mockCache.includeAllPlatforms).thenReturn(false);
|
|
expect(() => artifacts.getBinaryDirs(), throwsToolExit(message: 'Unsupported operating system: ${globals.platform.operatingSystem}'));
|
|
}, overrides: <Type, Generator> {
|
|
Platform: () => FakePlatform(operatingSystem: 'fuchsia'),
|
|
});
|
|
|
|
testUsingContext('FontSubset artifacts for all platforms', () {
|
|
final MockCache mockCache = MockCache();
|
|
final FontSubsetArtifacts artifacts = FontSubsetArtifacts(mockCache);
|
|
when(mockCache.includeAllPlatforms).thenReturn(true);
|
|
expect(artifacts.getBinaryDirs(), <List<String>>[
|
|
<String>['darwin-x64', 'darwin-x64/font-subset.zip'],
|
|
<String>['linux-x64', 'linux-x64/font-subset.zip'],
|
|
<String>['windows-x64', 'windows-x64/font-subset.zip'],
|
|
]);
|
|
}, overrides: <Type, Generator> {
|
|
Platform: () => FakePlatform(operatingSystem: 'fuchsia'),
|
|
});
|
|
|
|
testUsingContext('macOS desktop artifacts ignore filtering when requested', () {
|
|
final MockCache mockCache = MockCache();
|
|
final MacOSEngineArtifacts artifacts = MacOSEngineArtifacts(mockCache);
|
|
when(mockCache.includeAllPlatforms).thenReturn(false);
|
|
when(mockCache.platformOverrideArtifacts).thenReturn(<String>{'macos'});
|
|
|
|
expect(artifacts.getBinaryDirs(), isNotEmpty);
|
|
}, overrides: <Type, Generator> {
|
|
Platform: () => FakePlatform(operatingSystem: 'linux'),
|
|
});
|
|
|
|
testWithoutContext('Windows desktop artifacts ignore filtering when requested', () {
|
|
final MockCache mockCache = MockCache();
|
|
final WindowsEngineArtifacts artifacts = WindowsEngineArtifacts(
|
|
mockCache,
|
|
platform: FakePlatform(operatingSystem: 'linux'),
|
|
);
|
|
when(mockCache.includeAllPlatforms).thenReturn(false);
|
|
when(mockCache.platformOverrideArtifacts).thenReturn(<String>{'windows'});
|
|
|
|
expect(artifacts.getBinaryDirs(), isNotEmpty);
|
|
});
|
|
|
|
testWithoutContext('Windows desktop artifacts include profile and release artifacts', () {
|
|
final MockCache mockCache = MockCache();
|
|
final WindowsEngineArtifacts artifacts = WindowsEngineArtifacts(
|
|
mockCache,
|
|
platform: FakePlatform(operatingSystem: 'windows'),
|
|
);
|
|
|
|
expect(artifacts.getBinaryDirs(), containsAll(<Matcher>[
|
|
contains(contains('profile')),
|
|
contains(contains('release')),
|
|
]));
|
|
});
|
|
|
|
testWithoutContext('Linux desktop artifacts ignore filtering when requested', () {
|
|
final MockCache mockCache = MockCache();
|
|
final LinuxEngineArtifacts artifacts = LinuxEngineArtifacts(
|
|
mockCache,
|
|
platform: FakePlatform(operatingSystem: 'macos'),
|
|
);
|
|
when(mockCache.includeAllPlatforms).thenReturn(false);
|
|
when(mockCache.platformOverrideArtifacts).thenReturn(<String>{'linux'});
|
|
|
|
expect(artifacts.getBinaryDirs(), isNotEmpty);
|
|
});
|
|
|
|
testWithoutContext('Linux desktop artifacts include profile and release artifacts', () {
|
|
final MockCache mockCache = MockCache();
|
|
final LinuxEngineArtifacts artifacts = LinuxEngineArtifacts(
|
|
mockCache,
|
|
platform: FakePlatform(operatingSystem: 'linux'),
|
|
);
|
|
|
|
expect(artifacts.getBinaryDirs(), containsAll(<Matcher>[
|
|
contains(contains('profile')),
|
|
contains(contains('release')),
|
|
]));
|
|
});
|
|
|
|
testWithoutContext('Cache can delete stampfiles of artifacts', () {
|
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
|
final ArtifactSet artifactSet = MockIosUsbArtifacts();
|
|
final BufferLogger logger = BufferLogger.test();
|
|
|
|
when(artifactSet.stampName).thenReturn('STAMP');
|
|
final Cache cache = Cache(
|
|
artifacts: <ArtifactSet>[
|
|
artifactSet,
|
|
],
|
|
logger: logger,
|
|
fileSystem: fileSystem,
|
|
platform: FakePlatform(),
|
|
osUtils: MockOperatingSystemUtils(),
|
|
rootOverride: fileSystem.currentDirectory,
|
|
);
|
|
final File toolStampFile = fileSystem.file('bin/cache/flutter_tools.stamp');
|
|
final File stampFile = cache.getStampFileFor(artifactSet.stampName);
|
|
stampFile.createSync(recursive: true);
|
|
toolStampFile.createSync(recursive: true);
|
|
|
|
cache.clearStampFiles();
|
|
|
|
expect(logger.errorText, isEmpty);
|
|
expect(stampFile, isNot(exists));
|
|
expect(toolStampFile, isNot(exists));
|
|
});
|
|
|
|
testWithoutContext('Cache does not attempt to delete already missing stamp files', () {
|
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
|
final ArtifactSet artifactSet = MockIosUsbArtifacts();
|
|
final BufferLogger logger = BufferLogger.test();
|
|
|
|
when(artifactSet.stampName).thenReturn('STAMP');
|
|
final Cache cache = Cache(
|
|
artifacts: <ArtifactSet>[
|
|
artifactSet,
|
|
],
|
|
logger: logger,
|
|
fileSystem: fileSystem,
|
|
platform: FakePlatform(),
|
|
osUtils: MockOperatingSystemUtils(),
|
|
rootOverride: fileSystem.currentDirectory,
|
|
);
|
|
final File toolStampFile = fileSystem.file('bin/cache/flutter_tools.stamp');
|
|
final File stampFile = cache.getStampFileFor(artifactSet.stampName);
|
|
toolStampFile.createSync(recursive: true);
|
|
|
|
cache.clearStampFiles();
|
|
|
|
expect(logger.errorText, isEmpty);
|
|
expect(stampFile, isNot(exists));
|
|
expect(toolStampFile, isNot(exists));
|
|
});
|
|
|
|
testWithoutContext('Cache catches file system exception from missing tool stamp file', () {
|
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
|
final ArtifactSet artifactSet = MockIosUsbArtifacts();
|
|
final BufferLogger logger = BufferLogger.test();
|
|
|
|
when(artifactSet.stampName).thenReturn('STAMP');
|
|
final Cache cache = Cache(
|
|
artifacts: <ArtifactSet>[
|
|
artifactSet,
|
|
],
|
|
logger: logger,
|
|
fileSystem: fileSystem,
|
|
platform: FakePlatform(),
|
|
osUtils: MockOperatingSystemUtils(),
|
|
rootOverride: fileSystem.currentDirectory,
|
|
);
|
|
|
|
cache.clearStampFiles();
|
|
|
|
expect(logger.errorText, contains('Failed to delete some stamp files'));
|
|
});
|
|
}
|
|
|
|
class FakeCachedArtifact extends EngineCachedArtifact {
|
|
FakeCachedArtifact({
|
|
String stampName = 'STAMP',
|
|
@required Cache cache,
|
|
DevelopmentArtifact requiredArtifacts,
|
|
this.binaryDirs = const <List<String>>[],
|
|
this.licenseDirs = const <String>[],
|
|
this.packageDirs = const <String>[],
|
|
}) : super(stampName, cache, requiredArtifacts);
|
|
|
|
final List<List<String>> binaryDirs;
|
|
final List<String> licenseDirs;
|
|
final List<String> packageDirs;
|
|
|
|
@override
|
|
List<List<String>> getBinaryDirs() => binaryDirs;
|
|
|
|
@override
|
|
List<String> getLicenseDirs() => licenseDirs;
|
|
|
|
@override
|
|
List<String> getPackageDirs() => packageDirs;
|
|
}
|
|
|
|
class FakeSimpleArtifact extends CachedArtifact {
|
|
FakeSimpleArtifact(Cache cache) : super(
|
|
'fake',
|
|
cache,
|
|
DevelopmentArtifact.universal,
|
|
);
|
|
|
|
@override
|
|
Future<void> updateInner() async {
|
|
// nop.
|
|
}
|
|
}
|
|
|
|
class FakeDownloadedArtifact extends CachedArtifact {
|
|
FakeDownloadedArtifact(this.downloadedFile, Cache cache) : super(
|
|
'fake',
|
|
cache,
|
|
DevelopmentArtifact.universal,
|
|
);
|
|
|
|
final File downloadedFile;
|
|
|
|
@override
|
|
Future<void> updateInner() async {
|
|
downloadedFiles.add(downloadedFile);
|
|
}
|
|
}
|
|
|
|
class MockProcessManager extends Mock implements ProcessManager {}
|
|
class MockFileSystem extends Mock implements FileSystem {}
|
|
class MockFile extends Mock implements File {}
|
|
class MockDirectory extends Mock implements Directory {}
|
|
|
|
class MockRandomAccessFile extends Mock implements RandomAccessFile {}
|
|
class MockCachedArtifact extends Mock implements CachedArtifact {}
|
|
class MockIosUsbArtifacts extends Mock implements IosUsbArtifacts {}
|
|
class MockInternetAddress extends Mock implements InternetAddress {}
|
|
class MockCache extends Mock implements Cache {}
|
|
class MockOperatingSystemUtils extends Mock implements OperatingSystemUtils {}
|
|
class MockVersionedPackageResolver extends Mock implements VersionedPackageResolver {}
|
|
|
|
class MockHttpClientRequest extends Mock implements HttpClientRequest {}
|
|
class MockHttpClientResponse extends Mock implements HttpClientResponse {}
|