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

Context: https://github.com/flutter/flutter/issues/131862 This PR injects a "realm" component to the storage base URL when the contents of the file `bin/internal/engine.realm` is non-empty. As documented in the PR, when the realm is `flutter_archives_v2`, and `bin/internal/engine.version` contains the commit hash for a commit in a `flutter/engine` PR, then the artifacts pulled by the tool will be the artifacts built by the presubmit checks for the PR. This works for everything but the following two cases: 1. Fuchsia artifacts are not uploaded to CIPD by the Fuchsia presubmit builds. 2. Web artifacts are not uploaded to gstatic by the web engine presubmit builds. For (1), the flutter/flutter presubmit `fuchsia_precache` is driven by a shell script outside of the repo. It will fail when the `engine.version` and `engine.realm` don't point to a post-submit engine commit. For (2), the flutter/flutter web presubmit tests that refer to artifacts in gstatic hang when the artifacts aren't found, so this PR skips them.
1339 lines
51 KiB
Dart
1339 lines
51 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:collection/collection.dart' show IterableExtension;
|
|
import 'package:file/file.dart';
|
|
import 'package:file/memory.dart';
|
|
import 'package:file_testing/file_testing.dart';
|
|
import 'package:flutter_tools/src/android/android_sdk.dart';
|
|
import 'package:flutter_tools/src/base/file_system.dart';
|
|
import 'package:flutter_tools/src/base/io.dart';
|
|
import 'package:flutter_tools/src/base/logger.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/dart/pub.dart';
|
|
import 'package:flutter_tools/src/flutter_cache.dart';
|
|
import 'package:flutter_tools/src/globals.dart' as globals;
|
|
import 'package:flutter_tools/src/project.dart';
|
|
import 'package:test/fake.dart';
|
|
|
|
import '../src/common.dart';
|
|
import '../src/context.dart';
|
|
import '../src/fakes.dart';
|
|
|
|
const FakeCommand unameCommandForX64 = FakeCommand(
|
|
command: <String>[
|
|
'uname',
|
|
'-m',
|
|
],
|
|
stdout: 'x86_64',
|
|
);
|
|
|
|
const FakeCommand unameCommandForArm64 = FakeCommand(
|
|
command: <String>[
|
|
'uname',
|
|
'-m',
|
|
],
|
|
stdout: 'aarch64',
|
|
);
|
|
|
|
void main() {
|
|
late FakeProcessManager fakeProcessManager;
|
|
|
|
setUp(() {
|
|
fakeProcessManager = FakeProcessManager.empty();
|
|
});
|
|
|
|
Cache createCache(Platform platform) {
|
|
return Cache.test(
|
|
platform: platform,
|
|
processManager: fakeProcessManager
|
|
);
|
|
}
|
|
|
|
group('Cache.checkLockAcquired', () {
|
|
setUp(() {
|
|
Cache.enableLocking();
|
|
});
|
|
|
|
tearDown(() {
|
|
// Restore locking to prevent potential side-effects in
|
|
// tests outside this group (this option is globally shared).
|
|
Cache.enableLocking();
|
|
});
|
|
|
|
testWithoutContext('should throw when locking is not acquired', () {
|
|
final Cache cache = Cache.test(processManager: FakeProcessManager.any());
|
|
|
|
expect(cache.checkLockAcquired, throwsStateError);
|
|
});
|
|
|
|
testWithoutContext('should not throw when locking is disabled', () {
|
|
final Cache cache = Cache.test(processManager: FakeProcessManager.any());
|
|
Cache.disableLocking();
|
|
|
|
expect(cache.checkLockAcquired, returnsNormally);
|
|
});
|
|
|
|
testWithoutContext('should not throw when lock is acquired', () async {
|
|
final String? oldRoot = Cache.flutterRoot;
|
|
Cache.flutterRoot = '';
|
|
try {
|
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
|
final Cache cache = Cache.test(
|
|
fileSystem: fileSystem, processManager: FakeProcessManager.any());
|
|
fileSystem.file(fileSystem.path.join('bin', 'cache', 'lockfile'))
|
|
.createSync(recursive: true);
|
|
|
|
await cache.lock();
|
|
|
|
expect(cache.checkLockAcquired, returnsNormally);
|
|
expect(cache.releaseLock, returnsNormally);
|
|
} finally {
|
|
Cache.flutterRoot = oldRoot;
|
|
}
|
|
// TODO(zanderso): implement support for lock so this can be tested with the memory file system.
|
|
}, skip: true); // https://github.com/flutter/flutter/issues/87923
|
|
|
|
testWithoutContext('throws tool exit when lockfile open fails', () async {
|
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
|
final Cache cache = Cache.test(fileSystem: fileSystem, processManager: FakeProcessManager.any());
|
|
fileSystem.file(fileSystem.path.join('bin', 'cache', 'lockfile'))
|
|
.createSync(recursive: true);
|
|
|
|
expect(() async => cache.lock(), throwsToolExit());
|
|
// TODO(zanderso): implement support for lock so this can be tested with the memory file system.
|
|
}, skip: true); // https://github.com/flutter/flutter/issues/87923
|
|
|
|
testWithoutContext('should not throw when FLUTTER_ALREADY_LOCKED is set', () {
|
|
final Cache cache = Cache.test(
|
|
platform: FakePlatform(environment: <String, String>{
|
|
'FLUTTER_ALREADY_LOCKED': 'true',
|
|
}),
|
|
processManager: FakeProcessManager.any(),
|
|
);
|
|
|
|
expect(cache.checkLockAcquired, returnsNormally);
|
|
});
|
|
});
|
|
|
|
group('Cache', () {
|
|
testWithoutContext('Continues on failed stamp file update', () async {
|
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
|
final BufferLogger logger = BufferLogger.test();
|
|
final Directory artifactDir = fileSystem.systemTempDirectory.createTempSync('flutter_cache_test_artifact.');
|
|
final Directory downloadDir = fileSystem.systemTempDirectory.createTempSync('flutter_cache_test_download.');
|
|
final Cache cache = FakeSecondaryCache()
|
|
..version = 'asdasd'
|
|
..artifactDirectory = artifactDir
|
|
..downloadDir = downloadDir
|
|
..onSetStamp = (String name, String version) {
|
|
throw const FileSystemException('stamp write failed');
|
|
};
|
|
|
|
final FakeSimpleArtifact artifact = FakeSimpleArtifact(cache);
|
|
await artifact.update(FakeArtifactUpdater(), logger, fileSystem, FakeOperatingSystemUtils());
|
|
|
|
expect(logger.warningText, contains('stamp write failed'));
|
|
});
|
|
|
|
testWithoutContext('Continues on missing version file', () async {
|
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
|
final BufferLogger logger = BufferLogger.test();
|
|
final Directory artifactDir = fileSystem.systemTempDirectory.createTempSync('flutter_cache_test_artifact.');
|
|
final Directory downloadDir = fileSystem.systemTempDirectory.createTempSync('flutter_cache_test_download.');
|
|
final Cache cache = FakeSecondaryCache()
|
|
..version = null // version is missing.
|
|
..artifactDirectory = artifactDir
|
|
..downloadDir = downloadDir;
|
|
|
|
final FakeSimpleArtifact artifact = FakeSimpleArtifact(cache);
|
|
await artifact.update(FakeArtifactUpdater(), logger, fileSystem, FakeOperatingSystemUtils());
|
|
|
|
expect(logger.warningText, contains('No known version for the artifact name "fake"'));
|
|
});
|
|
|
|
testWithoutContext('Gradle wrapper should not be up to date, if some cached artifact is not available', () {
|
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
|
final Cache cache = Cache.test(fileSystem: fileSystem, processManager: FakeProcessManager.any());
|
|
final GradleWrapper gradleWrapper = GradleWrapper(cache);
|
|
final Directory directory = cache.getCacheDir(fileSystem.path.join('artifacts', 'gradle_wrapper'));
|
|
fileSystem.file(fileSystem.path.join(directory.path, 'gradle', 'wrapper', 'gradle-wrapper.jar')).createSync(recursive: true);
|
|
|
|
expect(gradleWrapper.isUpToDateInner(fileSystem), false);
|
|
});
|
|
|
|
testWithoutContext('Gradle wrapper will delete .properties/NOTICES if they exist', () async {
|
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
|
final Directory artifactDir = fileSystem.systemTempDirectory.createTempSync('flutter_cache_test_artifact.');
|
|
final FakeSecondaryCache cache = FakeSecondaryCache()
|
|
..artifactDirectory = artifactDir
|
|
..version = '123456';
|
|
|
|
final OperatingSystemUtils operatingSystemUtils = OperatingSystemUtils(
|
|
processManager: FakeProcessManager.any(),
|
|
platform: FakePlatform(),
|
|
logger: BufferLogger.test(),
|
|
fileSystem: fileSystem,
|
|
);
|
|
final GradleWrapper gradleWrapper = GradleWrapper(cache);
|
|
final File propertiesFile = fileSystem.file(fileSystem.path.join(artifactDir.path, 'gradle', 'wrapper', 'gradle-wrapper.properties'))
|
|
..createSync(recursive: true);
|
|
final File noticeFile = fileSystem.file(fileSystem.path.join(artifactDir.path, 'NOTICE'))
|
|
..createSync(recursive: true);
|
|
|
|
await gradleWrapper.updateInner(FakeArtifactUpdater(), fileSystem, operatingSystemUtils);
|
|
|
|
expect(propertiesFile, isNot(exists));
|
|
expect(noticeFile, isNot(exists));
|
|
});
|
|
|
|
testWithoutContext('Gradle wrapper should be up to date, only if all cached artifact are available', () {
|
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
|
final Cache cache = Cache.test(fileSystem: fileSystem, processManager: FakeProcessManager.any());
|
|
final GradleWrapper gradleWrapper = GradleWrapper(cache);
|
|
final Directory directory = cache.getCacheDir(fileSystem.path.join('artifacts', 'gradle_wrapper'));
|
|
fileSystem.file(fileSystem.path.join(directory.path, 'gradle', 'wrapper', 'gradle-wrapper.jar')).createSync(recursive: true);
|
|
fileSystem.file(fileSystem.path.join(directory.path, 'gradlew')).createSync(recursive: true);
|
|
fileSystem.file(fileSystem.path.join(directory.path, 'gradlew.bat')).createSync(recursive: true);
|
|
|
|
expect(gradleWrapper.isUpToDateInner(fileSystem), true);
|
|
});
|
|
|
|
testWithoutContext('should not be up to date, if some cached artifact is not', () async {
|
|
final CachedArtifact artifact1 = FakeSecondaryCachedArtifact()
|
|
..upToDate = true;
|
|
final CachedArtifact artifact2 = FakeSecondaryCachedArtifact()
|
|
..upToDate = false;
|
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
|
|
|
final Cache cache = Cache.test(
|
|
fileSystem: fileSystem,
|
|
artifacts: <CachedArtifact>[artifact1, artifact2],
|
|
processManager: FakeProcessManager.any(),
|
|
);
|
|
|
|
expect(await cache.isUpToDate(), isFalse);
|
|
});
|
|
|
|
testWithoutContext('should be up to date, if all cached artifacts are', () async {
|
|
final FakeSecondaryCachedArtifact artifact1 = FakeSecondaryCachedArtifact()
|
|
..upToDate = true;
|
|
final FakeSecondaryCachedArtifact artifact2 = FakeSecondaryCachedArtifact()
|
|
..upToDate = true;
|
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
|
final Cache cache = Cache.test(
|
|
fileSystem: fileSystem,
|
|
artifacts: <CachedArtifact>[artifact1, artifact2],
|
|
processManager: FakeProcessManager.any(),
|
|
);
|
|
|
|
expect(await cache.isUpToDate(), isTrue);
|
|
});
|
|
|
|
testWithoutContext('should update cached artifacts which are not up to date', () async {
|
|
final FakeSecondaryCachedArtifact artifact1 = FakeSecondaryCachedArtifact()
|
|
..upToDate = true;
|
|
final FakeSecondaryCachedArtifact artifact2 = FakeSecondaryCachedArtifact()
|
|
..upToDate = false;
|
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
|
|
|
final Cache cache = Cache.test(
|
|
fileSystem: fileSystem,
|
|
artifacts: <CachedArtifact>[artifact1, artifact2],
|
|
processManager: FakeProcessManager.any(),
|
|
);
|
|
|
|
await cache.updateAll(<DevelopmentArtifact>{
|
|
DevelopmentArtifact.universal,
|
|
});
|
|
expect(artifact1.didUpdate, false);
|
|
expect(artifact2.didUpdate, true);
|
|
});
|
|
|
|
testWithoutContext("getter dyLdLibEntry concatenates the output of each artifact's dyLdLibEntry getter", () async {
|
|
final FakeIosUsbArtifacts artifact1 = FakeIosUsbArtifacts();
|
|
final FakeIosUsbArtifacts artifact2 = FakeIosUsbArtifacts();
|
|
final FakeIosUsbArtifacts artifact3 = FakeIosUsbArtifacts();
|
|
artifact1.environment = <String, String>{
|
|
'DYLD_LIBRARY_PATH': '/path/to/alpha:/path/to/beta',
|
|
};
|
|
artifact2.environment = <String, String>{
|
|
'DYLD_LIBRARY_PATH': '/path/to/gamma:/path/to/delta:/path/to/epsilon',
|
|
};
|
|
artifact3.environment = <String, String>{
|
|
'DYLD_LIBRARY_PATH': '',
|
|
};
|
|
final Cache cache = Cache.test(
|
|
artifacts: <CachedArtifact>[artifact1, artifact2, artifact3],
|
|
processManager: FakeProcessManager.any(),
|
|
);
|
|
|
|
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',
|
|
);
|
|
});
|
|
|
|
testWithoutContext('failed storage.googleapis.com download shows China warning', () async {
|
|
final InternetAddress address = (await InternetAddress.lookup('storage.googleapis.com')).first;
|
|
final FakeSecondaryCachedArtifact artifact1 = FakeSecondaryCachedArtifact()
|
|
..upToDate = false;
|
|
final FakeSecondaryCachedArtifact artifact2 = FakeSecondaryCachedArtifact()
|
|
..upToDate = false
|
|
..updateException = SocketException(
|
|
'Connection reset by peer',
|
|
address: address,
|
|
);
|
|
|
|
final BufferLogger logger = BufferLogger.test();
|
|
final Cache cache = Cache.test(
|
|
artifacts: <CachedArtifact>[artifact1, artifact2],
|
|
processManager: FakeProcessManager.any(),
|
|
logger: logger,
|
|
);
|
|
await expectLater(
|
|
() => cache.updateAll(<DevelopmentArtifact>{DevelopmentArtifact.universal}),
|
|
throwsException,
|
|
);
|
|
expect(artifact1.didUpdate, true);
|
|
// Don't continue when retrieval fails.
|
|
expect(artifact2.didUpdate, false);
|
|
expect(
|
|
logger.errorText,
|
|
contains('https://flutter.dev/community/china'),
|
|
);
|
|
});
|
|
|
|
testWithoutContext('Invalid URI for FLUTTER_STORAGE_BASE_URL throws ToolExit', () async {
|
|
final Cache cache = Cache.test(
|
|
platform: FakePlatform(environment: <String, String>{
|
|
'FLUTTER_STORAGE_BASE_URL': ' http://foo',
|
|
}),
|
|
processManager: FakeProcessManager.any(),
|
|
);
|
|
|
|
expect(() => cache.storageBaseUrl, throwsToolExit());
|
|
});
|
|
|
|
testWithoutContext('overridden storage base url prints warning', () async {
|
|
final BufferLogger logger = BufferLogger.test();
|
|
const String baseUrl = 'https://storage.com';
|
|
final Cache cache = Cache.test(
|
|
platform: FakePlatform(environment: <String, String>{
|
|
'FLUTTER_STORAGE_BASE_URL': baseUrl,
|
|
}),
|
|
processManager: FakeProcessManager.any(),
|
|
logger: logger,
|
|
);
|
|
|
|
expect(cache.storageBaseUrl, baseUrl);
|
|
expect(logger.warningText, contains('Flutter assets will be downloaded from $baseUrl'));
|
|
expect(logger.statusText, isEmpty);
|
|
});
|
|
|
|
testWithoutContext('a non-empty realm is included in the storage url', () async {
|
|
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
|
final Directory internalDir = fileSystem.currentDirectory
|
|
.childDirectory('cache')
|
|
.childDirectory('bin')
|
|
.childDirectory('internal');
|
|
final File engineVersionFile = internalDir.childFile('engine.version');
|
|
engineVersionFile.createSync(recursive: true);
|
|
engineVersionFile.writeAsStringSync('abcdef');
|
|
|
|
final File engineRealmFile = internalDir.childFile('engine.realm');
|
|
engineRealmFile.createSync(recursive: true);
|
|
engineRealmFile.writeAsStringSync('flutter_archives_v2');
|
|
|
|
final Cache cache = Cache.test(
|
|
processManager: FakeProcessManager.any(),
|
|
fileSystem: fileSystem,
|
|
);
|
|
|
|
expect(cache.storageBaseUrl, contains('flutter_archives_v2'));
|
|
});
|
|
|
|
test('bin/internal/engine.realm is empty', () async {
|
|
final FileSystem fileSystem = globals.fs;
|
|
final String realmFilePath = fileSystem.path.join(
|
|
getFlutterRoot(), 'bin', 'internal', 'engine.realm');
|
|
final String realm = fileSystem.file(realmFilePath).readAsStringSync().trim();
|
|
expect(realm, isEmpty,
|
|
reason: 'The checked-in engine.realm file must be empty.');
|
|
});
|
|
});
|
|
|
|
testWithoutContext('flattenNameSubdirs', () {
|
|
expect(flattenNameSubdirs(Uri.parse('http://flutter.dev/foo/bar'), MemoryFileSystem.test()), 'flutter.dev/foo/bar');
|
|
expect(flattenNameSubdirs(Uri.parse('http://api.flutter.dev/foo/bar'), MemoryFileSystem.test()), 'api.flutter.dev/foo/bar');
|
|
expect(flattenNameSubdirs(Uri.parse('https://www.flutter.dev'), MemoryFileSystem.test()), 'www.flutter.dev');
|
|
});
|
|
|
|
testWithoutContext('EngineCachedArtifact makes binary dirs readable and executable by all', () async {
|
|
final FakeOperatingSystemUtils operatingSystemUtils = FakeOperatingSystemUtils();
|
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
|
final Directory artifactDir = fileSystem.systemTempDirectory.createTempSync('flutter_cache_test_artifact.');
|
|
final Directory downloadDir = fileSystem.systemTempDirectory.createTempSync('flutter_cache_test_download.');
|
|
final FakeSecondaryCache cache = FakeSecondaryCache()
|
|
..artifactDirectory = artifactDir
|
|
..downloadDir = downloadDir;
|
|
artifactDir.childDirectory('bin_dir').createSync();
|
|
artifactDir.childFile('unused_url_path').createSync();
|
|
|
|
final FakeCachedArtifact artifact = FakeCachedArtifact(
|
|
cache: cache,
|
|
binaryDirs: <List<String>>[
|
|
<String>['bin_dir', 'unused_url_path'],
|
|
],
|
|
requiredArtifacts: DevelopmentArtifact.universal,
|
|
);
|
|
await artifact.updateInner(FakeArtifactUpdater(), fileSystem, operatingSystemUtils);
|
|
final Directory dir = fileSystem.systemTempDirectory
|
|
.listSync(recursive: true)
|
|
.whereType<Directory>()
|
|
.singleWhereOrNull((Directory directory) => directory.basename == 'bin_dir')!;
|
|
|
|
expect(dir, isNotNull);
|
|
expect(dir.path, artifactDir.childDirectory('bin_dir').path);
|
|
expect(operatingSystemUtils.chmods, <List<String>>[<String>['/.tmp_rand0/flutter_cache_test_artifact.rand0/bin_dir', 'a+r,a+x']]);
|
|
});
|
|
|
|
testWithoutContext('EngineCachedArtifact removes unzipped FlutterMacOS.framework before replacing', () async {
|
|
final OperatingSystemUtils operatingSystemUtils = FakeOperatingSystemUtils();
|
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
|
final Directory artifactDir = fileSystem.systemTempDirectory.createTempSync('flutter_cache_test_artifact.');
|
|
final Directory downloadDir = fileSystem.systemTempDirectory.createTempSync('flutter_cache_test_download.');
|
|
final FakeSecondaryCache cache = FakeSecondaryCache()
|
|
..artifactDirectory = artifactDir
|
|
..downloadDir = downloadDir;
|
|
|
|
final Directory binDir = artifactDir.childDirectory('bin_dir')..createSync();
|
|
binDir.childFile('FlutterMacOS.framework.zip').createSync();
|
|
final Directory unzippedFramework = binDir.childDirectory('FlutterMacOS.framework');
|
|
final File staleFile = unzippedFramework.childFile('stale_file')..createSync(recursive: true);
|
|
artifactDir.childFile('unused_url_path').createSync();
|
|
|
|
final FakeCachedArtifact artifact = FakeCachedArtifact(
|
|
cache: cache,
|
|
binaryDirs: <List<String>>[
|
|
<String>['bin_dir', 'unused_url_path'],
|
|
],
|
|
requiredArtifacts: DevelopmentArtifact.universal,
|
|
);
|
|
await artifact.updateInner(FakeArtifactUpdater(), fileSystem, operatingSystemUtils);
|
|
expect(unzippedFramework, exists);
|
|
expect(staleFile, isNot(exists));
|
|
});
|
|
|
|
testWithoutContext('Try to remove without a parent', () async {
|
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
|
final Directory parent = fileSystem.directory('dir');
|
|
parent.createSync();
|
|
final Directory child = parent.childDirectory('child');
|
|
child.createSync();
|
|
final Directory tempStorage = parent.childDirectory('temp');
|
|
tempStorage.createSync();
|
|
final FakeArtifactUpdaterDownload fakeArtifact = FakeArtifactUpdaterDownload(
|
|
operatingSystemUtils: FakeOperatingSystemUtils(),
|
|
logger: BufferLogger.test(),
|
|
fileSystem: fileSystem,
|
|
tempStorage: tempStorage,
|
|
httpClient: HttpClient(),
|
|
platform: FakePlatform(),
|
|
allowedBaseUrls: <String>[]
|
|
);
|
|
final File file = child.childFile('file');
|
|
file.createSync();
|
|
fakeArtifact.addFiles(<File>[file]);
|
|
child.deleteSync(recursive: true);
|
|
fakeArtifact.removeDownloadedFiles();
|
|
});
|
|
|
|
testWithoutContext('IosUsbArtifacts verifies executables for libimobiledevice in isUpToDateInner', () async {
|
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
|
final Cache cache = Cache.test(fileSystem: fileSystem, processManager: FakeProcessManager.any());
|
|
final IosUsbArtifacts iosUsbArtifacts = IosUsbArtifacts('libimobiledevice', cache, platform: FakePlatform(operatingSystem: 'macos'));
|
|
iosUsbArtifacts.location.createSync();
|
|
final File ideviceScreenshotFile = iosUsbArtifacts.location.childFile('idevicescreenshot')
|
|
..createSync();
|
|
iosUsbArtifacts.location.childFile('idevicesyslog')
|
|
.createSync();
|
|
|
|
expect(iosUsbArtifacts.isUpToDateInner(fileSystem), true);
|
|
|
|
ideviceScreenshotFile.deleteSync();
|
|
|
|
expect(iosUsbArtifacts.isUpToDateInner(fileSystem), false);
|
|
});
|
|
|
|
testWithoutContext('IosUsbArtifacts verifies iproxy for usbmuxd in isUpToDateInner', () async {
|
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
|
final Cache cache = Cache.test(fileSystem: fileSystem, processManager: FakeProcessManager.any());
|
|
final IosUsbArtifacts iosUsbArtifacts = IosUsbArtifacts('usbmuxd', cache, platform: FakePlatform(operatingSystem: 'macos'));
|
|
iosUsbArtifacts.location.createSync();
|
|
final File iproxy = iosUsbArtifacts.location.childFile('iproxy')
|
|
..createSync();
|
|
|
|
expect(iosUsbArtifacts.isUpToDateInner(fileSystem), true);
|
|
|
|
iproxy.deleteSync();
|
|
|
|
expect(iosUsbArtifacts.isUpToDateInner(fileSystem), false);
|
|
});
|
|
|
|
testWithoutContext('IosUsbArtifacts does not verify executables for openssl in isUpToDateInner', () async {
|
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
|
final Cache cache = Cache.test(fileSystem: fileSystem, processManager: FakeProcessManager.any());
|
|
final IosUsbArtifacts iosUsbArtifacts = IosUsbArtifacts('openssl', cache, platform: FakePlatform(operatingSystem: 'macos'));
|
|
iosUsbArtifacts.location.createSync();
|
|
|
|
expect(iosUsbArtifacts.isUpToDateInner(fileSystem), true);
|
|
});
|
|
|
|
testWithoutContext('IosUsbArtifacts uses unsigned when specified', () async {
|
|
final Cache cache = Cache.test(processManager: FakeProcessManager.any());
|
|
cache.useUnsignedMacBinaries = true;
|
|
|
|
final IosUsbArtifacts iosUsbArtifacts = IosUsbArtifacts('name', cache, platform: FakePlatform(operatingSystem: 'macos'));
|
|
expect(iosUsbArtifacts.archiveUri.toString(), contains('/unsigned/'));
|
|
});
|
|
|
|
testWithoutContext('IosUsbArtifacts does not use unsigned when not specified', () async {
|
|
final Cache cache = Cache.test(processManager: FakeProcessManager.any());
|
|
final IosUsbArtifacts iosUsbArtifacts = IosUsbArtifacts('name', cache, platform: FakePlatform(operatingSystem: 'macos'));
|
|
|
|
expect(iosUsbArtifacts.archiveUri.toString(), isNot(contains('/unsigned/')));
|
|
});
|
|
|
|
testWithoutContext('FlutterRunnerDebugSymbols downloads Flutter runner debug symbols', () async {
|
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
|
final Cache cache = FakeSecondaryCache()
|
|
..artifactDirectory = fileSystem.currentDirectory
|
|
..version = '123456';
|
|
|
|
final FakeVersionedPackageResolver packageResolver = FakeVersionedPackageResolver();
|
|
final FlutterRunnerDebugSymbols flutterRunnerDebugSymbols = FlutterRunnerDebugSymbols(
|
|
cache,
|
|
packageResolver: packageResolver,
|
|
platform: FakePlatform(),
|
|
);
|
|
|
|
await flutterRunnerDebugSymbols.updateInner(FakeArtifactUpdater(), fileSystem, FakeOperatingSystemUtils());
|
|
|
|
expect(packageResolver.resolved, <List<String>>[
|
|
<String>['fuchsia-debug-symbols-x64', '123456'],
|
|
<String>['fuchsia-debug-symbols-arm64', '123456'],
|
|
]);
|
|
});
|
|
|
|
testWithoutContext('FontSubset in universal artifacts', () {
|
|
final Cache cache = Cache.test(processManager: FakeProcessManager.any());
|
|
final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache, platform: FakePlatform());
|
|
|
|
expect(artifacts.developmentArtifact, DevelopmentArtifact.universal);
|
|
});
|
|
|
|
testWithoutContext('FontSubset artifacts on x64 linux', () {
|
|
fakeProcessManager.addCommand(unameCommandForX64);
|
|
|
|
final Cache cache = createCache(FakePlatform());
|
|
final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache, platform: FakePlatform());
|
|
cache.includeAllPlatforms = false;
|
|
|
|
expect(artifacts.getBinaryDirs(), <List<String>>[<String>['linux-x64', 'linux-x64/font-subset.zip']]);
|
|
});
|
|
|
|
testWithoutContext('FontSubset artifacts on arm64 linux', () {
|
|
fakeProcessManager.addCommand(unameCommandForArm64);
|
|
|
|
final Cache cache = createCache(FakePlatform());
|
|
final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache, platform: FakePlatform());
|
|
cache.includeAllPlatforms = false;
|
|
|
|
expect(artifacts.getBinaryDirs(), <List<String>>[<String>['linux-arm64', 'linux-arm64/font-subset.zip']]);
|
|
});
|
|
|
|
testWithoutContext('FontSubset artifacts on windows', () {
|
|
final Cache cache = createCache(FakePlatform(operatingSystem: 'windows'));
|
|
final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache, platform: FakePlatform(operatingSystem: 'windows'));
|
|
cache.includeAllPlatforms = false;
|
|
|
|
expect(artifacts.getBinaryDirs(), <List<String>>[<String>['windows-x64', 'windows-x64/font-subset.zip']]);
|
|
});
|
|
|
|
testWithoutContext('FontSubset artifacts on macos', () {
|
|
fakeProcessManager.addCommands(<FakeCommand>[
|
|
const FakeCommand(
|
|
command: <String>[
|
|
'which',
|
|
'sysctl',
|
|
],
|
|
stdout: '/sbin/sysctl',
|
|
),
|
|
const FakeCommand(
|
|
command: <String>[
|
|
'sysctl',
|
|
'hw.optional.arm64',
|
|
],
|
|
stdout: 'hw.optional.arm64: 0',
|
|
),
|
|
]);
|
|
|
|
final Cache cache = createCache(FakePlatform(operatingSystem: 'macos'));
|
|
final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache, platform: FakePlatform(operatingSystem: 'macos'));
|
|
cache.includeAllPlatforms = false;
|
|
|
|
expect(artifacts.getBinaryDirs(), <List<String>>[<String>['darwin-x64', 'darwin-x64/font-subset.zip']]);
|
|
});
|
|
|
|
testWithoutContext('FontSubset artifacts on fuchsia', () {
|
|
fakeProcessManager.addCommand(unameCommandForX64);
|
|
|
|
final Cache cache = createCache(FakePlatform(operatingSystem: 'fuchsia'));
|
|
final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache, platform: FakePlatform(operatingSystem: 'fuchsia'));
|
|
cache.includeAllPlatforms = false;
|
|
|
|
expect(artifacts.getBinaryDirs, throwsToolExit(message: 'Unsupported operating system: fuchsia'));
|
|
});
|
|
|
|
testWithoutContext('FontSubset artifacts for all platforms on x64 hosts', () {
|
|
fakeProcessManager.addCommand(unameCommandForX64);
|
|
|
|
final Cache cache = createCache(FakePlatform(operatingSystem: 'fuchsia'));
|
|
final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache, platform: FakePlatform(operatingSystem: 'fuchsia'));
|
|
cache.includeAllPlatforms = 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'],
|
|
]);
|
|
});
|
|
|
|
testWithoutContext('FontSubset artifacts for all platforms on arm64 hosts', () {
|
|
fakeProcessManager.addCommand(unameCommandForArm64);
|
|
|
|
final Cache cache = createCache(FakePlatform(operatingSystem: 'fuchsia'));
|
|
final FontSubsetArtifacts artifacts = FontSubsetArtifacts(cache, platform: FakePlatform(operatingSystem: 'fuchsia'));
|
|
cache.includeAllPlatforms = true;
|
|
|
|
expect(artifacts.getBinaryDirs(), <List<String>>[
|
|
<String>['darwin-x64', 'darwin-arm64/font-subset.zip'],
|
|
<String>['linux-arm64', 'linux-arm64/font-subset.zip'],
|
|
<String>['windows-x64', 'windows-x64/font-subset.zip'], // arm64 windows hosts are not supported now
|
|
]);
|
|
});
|
|
|
|
testWithoutContext('macOS desktop artifacts include all gen_snapshot binaries', () {
|
|
final Cache cache = Cache.test(processManager: FakeProcessManager.any());
|
|
final MacOSEngineArtifacts artifacts = MacOSEngineArtifacts(cache, platform: FakePlatform());
|
|
cache.includeAllPlatforms = false;
|
|
cache.platformOverrideArtifacts = <String>{'macos'};
|
|
|
|
expect(artifacts.getBinaryDirs(), containsAll(<List<String>>[
|
|
<String>['darwin-x64', 'darwin-x64/gen_snapshot.zip'],
|
|
<String>['darwin-x64-profile', 'darwin-x64-profile/gen_snapshot.zip'],
|
|
<String>['darwin-x64-release', 'darwin-x64-release/gen_snapshot.zip'],
|
|
]));
|
|
});
|
|
|
|
testWithoutContext('macOS desktop artifacts ignore filtering when requested', () {
|
|
final Cache cache = Cache.test(processManager: FakeProcessManager.any());
|
|
final MacOSEngineArtifacts artifacts = MacOSEngineArtifacts(cache, platform: FakePlatform());
|
|
cache.includeAllPlatforms = false;
|
|
cache.platformOverrideArtifacts = <String>{'macos'};
|
|
|
|
expect(artifacts.getBinaryDirs(), isNotEmpty);
|
|
});
|
|
|
|
testWithoutContext('Windows desktop artifacts ignore filtering when requested', () {
|
|
final Cache cache = Cache.test(processManager: FakeProcessManager.any());
|
|
final WindowsEngineArtifacts artifacts = WindowsEngineArtifacts(
|
|
cache,
|
|
platform: FakePlatform(),
|
|
);
|
|
cache.includeAllPlatforms = false;
|
|
cache.platformOverrideArtifacts = <String>{'windows'};
|
|
|
|
expect(artifacts.getBinaryDirs(), isNotEmpty);
|
|
});
|
|
|
|
testWithoutContext('Windows desktop artifacts include profile and release artifacts', () {
|
|
final Cache cache = Cache.test(processManager: FakeProcessManager.any());
|
|
final WindowsEngineArtifacts artifacts = WindowsEngineArtifacts(
|
|
cache,
|
|
platform: FakePlatform(operatingSystem: 'windows'),
|
|
);
|
|
|
|
expect(artifacts.getBinaryDirs(), containsAll(<Matcher>[
|
|
contains(contains('profile')),
|
|
contains(contains('release')),
|
|
]));
|
|
});
|
|
|
|
testWithoutContext('Linux desktop artifacts ignore filtering when requested', () {
|
|
fakeProcessManager.addCommand(unameCommandForX64);
|
|
|
|
final Cache cache = createCache(FakePlatform());
|
|
final LinuxEngineArtifacts artifacts = LinuxEngineArtifacts(
|
|
cache,
|
|
platform: FakePlatform(operatingSystem: 'macos'),
|
|
);
|
|
cache.includeAllPlatforms = false;
|
|
cache.platformOverrideArtifacts = <String>{'linux'};
|
|
|
|
expect(artifacts.getBinaryDirs(), isNotEmpty);
|
|
});
|
|
|
|
testWithoutContext('Linux desktop artifacts for x64 include profile and release artifacts', () {
|
|
fakeProcessManager.addCommand(unameCommandForX64);
|
|
|
|
final Cache cache = createCache(FakePlatform());
|
|
final LinuxEngineArtifacts artifacts = LinuxEngineArtifacts(
|
|
cache,
|
|
platform: FakePlatform(),
|
|
);
|
|
|
|
expect(artifacts.getBinaryDirs(), <List<String>>[
|
|
<String>['linux-x64', 'linux-x64-debug/linux-x64-flutter-gtk.zip'],
|
|
<String>['linux-x64-profile', 'linux-x64-profile/linux-x64-flutter-gtk.zip'],
|
|
<String>['linux-x64-release', 'linux-x64-release/linux-x64-flutter-gtk.zip'],
|
|
]);
|
|
});
|
|
|
|
testWithoutContext('Linux desktop artifacts for arm64 include profile and release artifacts', () {
|
|
fakeProcessManager.addCommand(unameCommandForArm64);
|
|
|
|
final Cache cache = createCache(FakePlatform());
|
|
final LinuxEngineArtifacts artifacts = LinuxEngineArtifacts(
|
|
cache,
|
|
platform: FakePlatform(),
|
|
);
|
|
|
|
expect(artifacts.getBinaryDirs(), <List<String>>[
|
|
<String>['linux-arm64', 'linux-arm64-debug/linux-arm64-flutter-gtk.zip'],
|
|
<String>['linux-arm64-profile', 'linux-arm64-profile/linux-arm64-flutter-gtk.zip'],
|
|
<String>['linux-arm64-release', 'linux-arm64-release/linux-arm64-flutter-gtk.zip'],
|
|
]);
|
|
});
|
|
|
|
testWithoutContext('Cache can delete stampfiles of artifacts', () {
|
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
|
final FakeIosUsbArtifacts artifactSet = FakeIosUsbArtifacts();
|
|
final BufferLogger logger = BufferLogger.test();
|
|
|
|
artifactSet.stampName = 'STAMP';
|
|
final Cache cache = Cache(
|
|
artifacts: <ArtifactSet>[
|
|
artifactSet,
|
|
],
|
|
logger: logger,
|
|
fileSystem: fileSystem,
|
|
platform: FakePlatform(),
|
|
osUtils: FakeOperatingSystemUtils(),
|
|
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 FakeIosUsbArtifacts artifactSet = FakeIosUsbArtifacts();
|
|
final BufferLogger logger = BufferLogger.test();
|
|
|
|
artifactSet.stampName = 'STAMP';
|
|
final Cache cache = Cache(
|
|
artifacts: <ArtifactSet>[
|
|
artifactSet,
|
|
],
|
|
logger: logger,
|
|
fileSystem: fileSystem,
|
|
platform: FakePlatform(),
|
|
osUtils: FakeOperatingSystemUtils(),
|
|
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 FakeIosUsbArtifacts artifactSet = FakeIosUsbArtifacts();
|
|
final BufferLogger logger = BufferLogger.test();
|
|
|
|
artifactSet.stampName = 'STAMP';
|
|
final Cache cache = Cache(
|
|
artifacts: <ArtifactSet>[
|
|
artifactSet,
|
|
],
|
|
logger: logger,
|
|
fileSystem: fileSystem,
|
|
platform: FakePlatform(),
|
|
osUtils: FakeOperatingSystemUtils(),
|
|
rootOverride: fileSystem.currentDirectory,
|
|
);
|
|
|
|
cache.clearStampFiles();
|
|
|
|
expect(logger.warningText, contains('Failed to delete some stamp files'));
|
|
});
|
|
|
|
testWithoutContext('FlutterWebSdk fetches web artifacts and deletes previous directory contents', () async {
|
|
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
|
final Directory internalDir = fileSystem.currentDirectory
|
|
.childDirectory('cache')
|
|
.childDirectory('bin')
|
|
.childDirectory('internal');
|
|
final File canvasKitVersionFile = internalDir.childFile('canvaskit.version');
|
|
canvasKitVersionFile.createSync(recursive: true);
|
|
canvasKitVersionFile.writeAsStringSync('abcdefg');
|
|
|
|
final File engineVersionFile = internalDir.childFile('engine.version');
|
|
engineVersionFile.createSync(recursive: true);
|
|
engineVersionFile.writeAsStringSync('hijklmnop');
|
|
|
|
final Cache cache = Cache.test(processManager: FakeProcessManager.any(), fileSystem: fileSystem);
|
|
final Directory webCacheDirectory = cache.getWebSdkDirectory();
|
|
final FakeArtifactUpdater artifactUpdater = FakeArtifactUpdater();
|
|
final FlutterWebSdk webSdk = FlutterWebSdk(cache);
|
|
|
|
final List<String> messages = <String>[];
|
|
final List<String> downloads = <String>[];
|
|
final List<String> locations = <String>[];
|
|
artifactUpdater.onDownloadZipArchive = (String message, Uri uri, Directory location) {
|
|
messages.add(message);
|
|
downloads.add(uri.toString());
|
|
locations.add(location.path);
|
|
location.createSync(recursive: true);
|
|
location.childFile('foo').createSync();
|
|
};
|
|
webCacheDirectory.childFile('bar').createSync(recursive: true);
|
|
|
|
await webSdk.updateInner(artifactUpdater, fileSystem, FakeOperatingSystemUtils());
|
|
|
|
expect(messages, <String>[
|
|
'Downloading Web SDK...',
|
|
]);
|
|
|
|
expect(downloads, <String>[
|
|
'https://storage.googleapis.com/flutter_infra_release/flutter/hijklmnop/flutter-web-sdk.zip',
|
|
]);
|
|
|
|
expect(locations, <String>[
|
|
'cache/bin/cache/flutter_web_sdk',
|
|
]);
|
|
|
|
expect(webCacheDirectory.childFile('foo'), exists);
|
|
expect(webCacheDirectory.childFile('bar'), isNot(exists));
|
|
});
|
|
|
|
testWithoutContext('FlutterWebSdk CanvasKit URL can be overridden via FLUTTER_STORAGE_BASE_URL', () async {
|
|
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
|
final Directory internalDir = fileSystem.currentDirectory
|
|
.childDirectory('cache')
|
|
.childDirectory('bin')
|
|
.childDirectory('internal');
|
|
final File canvasKitVersionFile = internalDir.childFile('canvaskit.version');
|
|
canvasKitVersionFile.createSync(recursive: true);
|
|
canvasKitVersionFile.writeAsStringSync('abcdefg');
|
|
|
|
final File engineVersionFile = internalDir.childFile('engine.version');
|
|
engineVersionFile.createSync(recursive: true);
|
|
engineVersionFile.writeAsStringSync('hijklmnop');
|
|
|
|
final Cache cache = Cache.test(
|
|
processManager: FakeProcessManager.any(),
|
|
fileSystem: fileSystem,
|
|
platform: FakePlatform(
|
|
environment: <String, String>{
|
|
'FLUTTER_STORAGE_BASE_URL': 'https://flutter.storage.com/override',
|
|
},
|
|
),
|
|
);
|
|
final Directory webCacheDirectory = cache.getWebSdkDirectory();
|
|
final FakeArtifactUpdater artifactUpdater = FakeArtifactUpdater();
|
|
final FlutterWebSdk webSdk = FlutterWebSdk(cache);
|
|
|
|
final List<String> downloads = <String>[];
|
|
final List<String> locations = <String>[];
|
|
artifactUpdater.onDownloadZipArchive = (String message, Uri uri, Directory location) {
|
|
downloads.add(uri.toString());
|
|
locations.add(location.path);
|
|
location.createSync(recursive: true);
|
|
location.childFile('foo').createSync();
|
|
};
|
|
webCacheDirectory.childFile('bar').createSync(recursive: true);
|
|
|
|
await webSdk.updateInner(artifactUpdater, fileSystem, FakeOperatingSystemUtils());
|
|
|
|
expect(downloads, <String>[
|
|
'https://flutter.storage.com/override/flutter_infra_release/flutter/hijklmnop/flutter-web-sdk.zip',
|
|
]);
|
|
});
|
|
|
|
testWithoutContext('FlutterWebSdk uses tryToDelete to handle directory edge cases', () async {
|
|
final FileExceptionHandler handler = FileExceptionHandler();
|
|
final MemoryFileSystem fileSystem = MemoryFileSystem.test(opHandle: handler.opHandle);
|
|
final Cache cache = Cache.test(processManager: FakeProcessManager.any(), fileSystem: fileSystem);
|
|
final Directory webCacheDirectory = cache.getWebSdkDirectory();
|
|
final FakeArtifactUpdater artifactUpdater = FakeArtifactUpdater();
|
|
final FlutterWebSdk webSdk = FlutterWebSdk(cache);
|
|
|
|
artifactUpdater.onDownloadZipArchive = (String message, Uri uri, Directory location) {
|
|
location.createSync(recursive: true);
|
|
location.childFile('foo').createSync();
|
|
};
|
|
webCacheDirectory.childFile('bar').createSync(recursive: true);
|
|
handler.addError(webCacheDirectory, FileSystemOp.delete, const FileSystemException('', '', OSError('', 2)));
|
|
|
|
await expectLater(() => webSdk.updateInner(artifactUpdater, fileSystem, FakeOperatingSystemUtils()), throwsToolExit(
|
|
message: RegExp('The Flutter tool tried to delete the file or directory cache/bin/cache/flutter_web_sdk but was unable to'),
|
|
));
|
|
});
|
|
|
|
testWithoutContext('LegacyCanvasKitRemover removes old canvaskit artifacts if they exist', () async {
|
|
final FileExceptionHandler handler = FileExceptionHandler();
|
|
final MemoryFileSystem fileSystem = MemoryFileSystem.test(opHandle: handler.opHandle);
|
|
final Cache cache = Cache.test(processManager: FakeProcessManager.any(), fileSystem: fileSystem);
|
|
final File canvasKitWasm = fileSystem.file(fileSystem.path.join(
|
|
cache.getRoot().path,
|
|
'canvaskit',
|
|
'canvaskit.wasm',
|
|
));
|
|
canvasKitWasm.createSync(recursive: true);
|
|
canvasKitWasm.writeAsStringSync('hello world');
|
|
|
|
final LegacyCanvasKitRemover remover = LegacyCanvasKitRemover(cache);
|
|
expect(await remover.isUpToDate(fileSystem), false);
|
|
await remover.update(
|
|
FakeArtifactUpdater(),
|
|
BufferLogger.test(),
|
|
fileSystem,
|
|
FakeOperatingSystemUtils(),
|
|
);
|
|
expect(await remover.isUpToDate(fileSystem), true);
|
|
|
|
expect(canvasKitWasm.existsSync(), isFalse);
|
|
});
|
|
|
|
testWithoutContext('Cache handles exception thrown if stamp file cannot be parsed', () {
|
|
final FileExceptionHandler exceptionHandler = FileExceptionHandler();
|
|
final FileSystem fileSystem = MemoryFileSystem.test(opHandle: exceptionHandler.opHandle);
|
|
final Logger logger = BufferLogger.test();
|
|
final FakeCache cache = FakeCache(
|
|
fileSystem: fileSystem,
|
|
logger: logger,
|
|
platform: FakePlatform(),
|
|
osUtils: FakeOperatingSystemUtils()
|
|
);
|
|
final File file = fileSystem.file('stamp');
|
|
cache.stampFile = file;
|
|
|
|
expect(cache.getStampFor('foo'), null);
|
|
|
|
file.createSync();
|
|
exceptionHandler.addError(
|
|
file,
|
|
FileSystemOp.read,
|
|
const FileSystemException(),
|
|
);
|
|
|
|
expect(cache.getStampFor('foo'), null);
|
|
});
|
|
|
|
testWithoutContext('Cache parses stamp file', () {
|
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
|
final Logger logger = BufferLogger.test();
|
|
final FakeCache cache = FakeCache(
|
|
fileSystem: fileSystem,
|
|
logger: logger,
|
|
platform: FakePlatform(),
|
|
osUtils: FakeOperatingSystemUtils()
|
|
);
|
|
|
|
final File file = fileSystem.file('stamp')..writeAsStringSync('ABC ');
|
|
cache.stampFile = file;
|
|
|
|
expect(cache.getStampFor('foo'), 'ABC');
|
|
});
|
|
|
|
testWithoutContext('PubDependencies needs to be updated if the package config'
|
|
' file or the source directories are missing', () async {
|
|
final BufferLogger logger = BufferLogger.test();
|
|
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
|
final PubDependencies pubDependencies = PubDependencies(
|
|
flutterRoot: () => '',
|
|
logger: logger,
|
|
pub: () => FakePub(),
|
|
projectFactory: FakeFlutterProjectFactory(),
|
|
);
|
|
|
|
expect(await pubDependencies.isUpToDate(fileSystem), false); // no package config
|
|
|
|
fileSystem.file('packages/flutter_tools/.packages')
|
|
..createSync(recursive: true)
|
|
..writeAsStringSync('\n');
|
|
fileSystem.file('packages/flutter_tools/.dart_tool/package_config.json')
|
|
..createSync(recursive: true)
|
|
..writeAsStringSync('''
|
|
{
|
|
"configVersion": 2,
|
|
"packages": [
|
|
{
|
|
"name": "example",
|
|
"rootUri": "file:///.pub-cache/hosted/pub.dartlang.org/example-7.0.0",
|
|
"packageUri": "lib/",
|
|
"languageVersion": "2.7"
|
|
}
|
|
],
|
|
"generated": "2020-09-15T20:29:20.691147Z",
|
|
"generator": "pub",
|
|
"generatorVersion": "2.10.0-121.0.dev"
|
|
}
|
|
''');
|
|
|
|
expect(await pubDependencies.isUpToDate(fileSystem), false); // dependencies are missing.
|
|
|
|
fileSystem.file('.pub-cache/hosted/pub.dartlang.org/example-7.0.0/pubspec.yaml')
|
|
.createSync(recursive: true);
|
|
|
|
expect(await pubDependencies.isUpToDate(fileSystem), true);
|
|
});
|
|
|
|
testWithoutContext('PubDependencies updates via pub get', () async {
|
|
final BufferLogger logger = BufferLogger.test();
|
|
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
|
final FakePub pub = FakePub();
|
|
final PubDependencies pubDependencies = PubDependencies(
|
|
flutterRoot: () => '',
|
|
logger: logger,
|
|
pub: () => pub,
|
|
projectFactory: FakeFlutterProjectFactory()
|
|
);
|
|
|
|
await pubDependencies.update(FakeArtifactUpdater(), logger, fileSystem, FakeOperatingSystemUtils());
|
|
|
|
expect(pub.calledGet, 1);
|
|
expect(
|
|
pub.invocations.first,
|
|
predicate<FakePubInvocation>(
|
|
(FakePubInvocation invocation) => invocation.outputMode == PubOutputMode.none,
|
|
'Pub invoked with PubOutputMode.none',
|
|
),
|
|
);
|
|
});
|
|
|
|
testUsingContext('Check current DevTools version', () async {
|
|
final String currentDevToolsVersion = globals.cache.devToolsVersion;
|
|
final RegExp devToolsVersionFormat = RegExp(r'\d+\.\d+\.\d+(?:-\S+)?');
|
|
expect(devToolsVersionFormat.allMatches(currentDevToolsVersion).length, 1,);
|
|
});
|
|
|
|
// Check that the build number matches the format documented here:
|
|
// https://dart.dev/get-dart#release-channels
|
|
testUsingContext('Check current Dart SDK build number', () async {
|
|
final String currentDartSdkVersion = globals.cache.dartSdkBuild;
|
|
final RegExp dartSdkVersionFormat = RegExp(r'\d+\.\d+\.\d+(?:-\S+)?');
|
|
|
|
expect(dartSdkVersionFormat.allMatches(currentDartSdkVersion).length, 1,);
|
|
});
|
|
|
|
group('AndroidMavenArtifacts', () {
|
|
MemoryFileSystem? memoryFileSystem;
|
|
Cache? cache;
|
|
FakeAndroidSdk? fakeAndroidSdk;
|
|
|
|
setUp(() {
|
|
memoryFileSystem = MemoryFileSystem.test();
|
|
cache = Cache.test(
|
|
fileSystem: memoryFileSystem,
|
|
processManager: FakeProcessManager.any(),
|
|
);
|
|
fakeAndroidSdk = FakeAndroidSdk();
|
|
});
|
|
|
|
testWithoutContext('AndroidMavenArtifacts has a specified development artifact', () async {
|
|
final AndroidMavenArtifacts mavenArtifacts = AndroidMavenArtifacts(
|
|
cache!,
|
|
java: FakeJava(),
|
|
platform: FakePlatform(),
|
|
);
|
|
expect(mavenArtifacts.developmentArtifact, DevelopmentArtifact.androidMaven);
|
|
});
|
|
|
|
testUsingContext('AndroidMavenArtifacts can invoke Gradle resolve dependencies if Android SDK is present', () async {
|
|
final String? oldRoot = Cache.flutterRoot;
|
|
Cache.flutterRoot = '';
|
|
try {
|
|
final AndroidMavenArtifacts mavenArtifacts = AndroidMavenArtifacts(
|
|
cache!,
|
|
java: FakeJava(),
|
|
platform: FakePlatform(),
|
|
);
|
|
expect(await mavenArtifacts.isUpToDate(memoryFileSystem!), isFalse);
|
|
|
|
final Directory gradleWrapperDir = cache!.getArtifactDirectory('gradle_wrapper')..createSync(recursive: true);
|
|
gradleWrapperDir.childFile('gradlew').writeAsStringSync('irrelevant');
|
|
gradleWrapperDir.childFile('gradlew.bat').writeAsStringSync('irrelevant');
|
|
|
|
await mavenArtifacts.update(FakeArtifactUpdater(), BufferLogger.test(), memoryFileSystem!, FakeOperatingSystemUtils());
|
|
|
|
expect(await mavenArtifacts.isUpToDate(memoryFileSystem!), isFalse);
|
|
expect(fakeAndroidSdk!.reinitialized, true);
|
|
} finally {
|
|
Cache.flutterRoot = oldRoot;
|
|
}
|
|
}, overrides: <Type, Generator>{
|
|
Cache: () => cache,
|
|
FileSystem: () => memoryFileSystem,
|
|
Platform: () => FakePlatform(),
|
|
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
|
|
const FakeCommand(command: <String>[
|
|
'/cache/bin/cache/flutter_gradle_wrapper.rand0/gradlew',
|
|
'-b',
|
|
'packages/flutter_tools/gradle/resolve_dependencies.gradle',
|
|
'--project-cache-dir',
|
|
'cache/bin/cache/flutter_gradle_wrapper.rand0',
|
|
'resolveDependencies',
|
|
]),
|
|
]),
|
|
AndroidSdk: () => fakeAndroidSdk,
|
|
});
|
|
|
|
testUsingContext('AndroidMavenArtifacts is a no-op if the Android SDK is absent', () async {
|
|
final AndroidMavenArtifacts mavenArtifacts = AndroidMavenArtifacts(
|
|
cache!,
|
|
java: FakeJava(),
|
|
platform: FakePlatform(),
|
|
);
|
|
expect(await mavenArtifacts.isUpToDate(memoryFileSystem!), isFalse);
|
|
|
|
await mavenArtifacts.update(FakeArtifactUpdater(), BufferLogger.test(), memoryFileSystem!, FakeOperatingSystemUtils());
|
|
|
|
expect(await mavenArtifacts.isUpToDate(memoryFileSystem!), isFalse);
|
|
}, overrides: <Type, Generator>{
|
|
Cache: () => cache,
|
|
FileSystem: () => memoryFileSystem,
|
|
ProcessManager: () => FakeProcessManager.empty(),
|
|
AndroidSdk: () => null, // Android SDK was not located.
|
|
});
|
|
});
|
|
}
|
|
|
|
class FakeCachedArtifact extends EngineCachedArtifact {
|
|
FakeCachedArtifact({
|
|
String stampName = 'STAMP',
|
|
required Cache cache,
|
|
required 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(ArtifactUpdater artifactUpdater, FileSystem fileSystem, OperatingSystemUtils operatingSystemUtils) async { }
|
|
}
|
|
|
|
class FakeSecondaryCachedArtifact extends Fake implements CachedArtifact {
|
|
bool upToDate = false;
|
|
bool didUpdate = false;
|
|
Exception? updateException;
|
|
|
|
@override
|
|
Future<bool> isUpToDate(FileSystem fileSystem) async => upToDate;
|
|
|
|
@override
|
|
Future<void> update(ArtifactUpdater artifactUpdater, Logger logger, FileSystem fileSystem, OperatingSystemUtils operatingSystemUtils, {bool offline = false}) async {
|
|
if (updateException != null) {
|
|
throw updateException!;
|
|
}
|
|
didUpdate = true;
|
|
}
|
|
|
|
@override
|
|
DevelopmentArtifact get developmentArtifact => DevelopmentArtifact.universal;
|
|
}
|
|
|
|
class FakeIosUsbArtifacts extends Fake implements IosUsbArtifacts {
|
|
@override
|
|
Map<String, String> environment = <String, String>{};
|
|
|
|
@override
|
|
String stampName = 'ios-usb';
|
|
}
|
|
|
|
class FakeSecondaryCache extends Fake implements Cache {
|
|
Directory? downloadDir;
|
|
late Directory artifactDirectory;
|
|
String? version;
|
|
late void Function(String artifactName, String version) onSetStamp;
|
|
|
|
@override
|
|
String get storageBaseUrl => 'https://storage.googleapis.com';
|
|
|
|
@override
|
|
Directory getDownloadDir() => artifactDirectory;
|
|
|
|
@override
|
|
Directory getArtifactDirectory(String name) => artifactDirectory;
|
|
|
|
@override
|
|
Directory getCacheDir(String name, { bool shouldCreate = true }) {
|
|
return artifactDirectory.childDirectory(name);
|
|
}
|
|
|
|
@override
|
|
File getLicenseFile() {
|
|
return artifactDirectory.childFile('LICENSE');
|
|
}
|
|
|
|
@override
|
|
String? getVersionFor(String artifactName) => version;
|
|
|
|
@override
|
|
void setStampFor(String artifactName, String version) {
|
|
onSetStamp(artifactName, version);
|
|
}
|
|
}
|
|
|
|
class FakeVersionedPackageResolver extends Fake implements VersionedPackageResolver {
|
|
final List<List<String>> resolved = <List<String>>[];
|
|
|
|
@override
|
|
String resolveUrl(String packageName, String version) {
|
|
resolved.add(<String>[packageName, version]);
|
|
return '';
|
|
}
|
|
}
|
|
|
|
class FakePubInvocation {
|
|
FakePubInvocation({
|
|
required this.outputMode,
|
|
});
|
|
|
|
final PubOutputMode outputMode;
|
|
}
|
|
|
|
class FakePub extends Fake implements Pub {
|
|
final List<FakePubInvocation> invocations = <FakePubInvocation>[];
|
|
int get calledGet => invocations.length;
|
|
|
|
@override
|
|
Future<void> get({
|
|
PubContext? context,
|
|
required FlutterProject project,
|
|
bool upgrade = false,
|
|
bool offline = false,
|
|
bool generateSyntheticPackage = false,
|
|
String? flutterRootOverride,
|
|
bool checkUpToDate = false,
|
|
bool shouldSkipThirdPartyGenerator = true,
|
|
bool printProgress = true,
|
|
PubOutputMode outputMode = PubOutputMode.all,
|
|
}) async {
|
|
invocations.add(FakePubInvocation(outputMode: outputMode));
|
|
}
|
|
}
|
|
|
|
class FakeCache extends Cache {
|
|
FakeCache({
|
|
required super.logger,
|
|
required super.fileSystem,
|
|
required super.platform,
|
|
required super.osUtils,
|
|
}) : super(
|
|
artifacts: <ArtifactSet>[],
|
|
);
|
|
|
|
late File stampFile;
|
|
|
|
@override
|
|
File getStampFileFor(String artifactName) {
|
|
return stampFile;
|
|
}
|
|
}
|
|
|
|
class FakeAndroidSdk extends Fake implements AndroidSdk {
|
|
bool reinitialized = false;
|
|
|
|
@override
|
|
void reinitialize() {
|
|
reinitialized = true;
|
|
}
|
|
}
|
|
|
|
class FakeArtifactUpdater extends Fake implements ArtifactUpdater {
|
|
void Function(String, Uri, Directory)? onDownloadZipArchive;
|
|
void Function(String, Uri, Directory)? onDownloadZipTarball;
|
|
|
|
@override
|
|
Future<void> downloadZippedTarball(String message, Uri url, Directory location) async {
|
|
onDownloadZipTarball?.call(message, url, location);
|
|
}
|
|
|
|
@override
|
|
Future<void> downloadZipArchive(String message, Uri url, Directory location) async {
|
|
onDownloadZipArchive?.call(message, url, location);
|
|
}
|
|
|
|
@override
|
|
void removeDownloadedFiles() { }
|
|
}
|
|
|
|
class FakeArtifactUpdaterDownload extends ArtifactUpdater {
|
|
FakeArtifactUpdaterDownload({
|
|
required super.operatingSystemUtils,
|
|
required super.logger,
|
|
required super.fileSystem,
|
|
required super.tempStorage,
|
|
required super.httpClient,
|
|
required super.platform,
|
|
required super.allowedBaseUrls
|
|
});
|
|
|
|
void addFiles(List<File> files) {
|
|
downloadedFiles.addAll(files);
|
|
}
|
|
}
|