Ensure that cache dirs and files have appropriate permissions (#28090)
This is a partial re-application of #24669, which was
reverted due to Fuchsia breakages.
https://github.com/flutter/flutter/issues/24413
diff --git a/packages/flutter_tools/test/general.shard/artifacts_test.dart b/packages/flutter_tools/test/general.shard/artifacts_test.dart
index fc522c8..ee78164 100644
--- a/packages/flutter_tools/test/general.shard/artifacts_test.dart
+++ b/packages/flutter_tools/test/general.shard/artifacts_test.dart
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/build_info.dart';
@@ -12,102 +13,106 @@
import '../src/context.dart';
void main() {
- group('CachedArtifacts', () {
-
+ group('Artifacts', () {
+ MemoryFileSystem memoryFileSystem;
Directory tempDir;
- CachedArtifacts artifacts;
setUp(() {
- tempDir = fs.systemTempDirectory.createTempSync('flutter_tools_artifacts_test_cached.');
- artifacts = CachedArtifacts();
+ memoryFileSystem = MemoryFileSystem();
+ tempDir = memoryFileSystem.systemTempDirectory.createTempSync('artifacts_test.');
});
tearDown(() {
tryToDelete(tempDir);
});
- testUsingContext('getArtifactPath', () {
- expect(
+ group('CachedArtifacts', () {
+ CachedArtifacts artifacts;
+
+ setUp(() {
+ artifacts = CachedArtifacts();
+ });
+
+ testUsingContext('getArtifactPath', () {
+ expect(
artifacts.getArtifactPath(Artifact.flutterFramework, platform: TargetPlatform.ios, mode: BuildMode.release),
fs.path.join(tempDir.path, 'bin', 'cache', 'artifacts', 'engine', 'ios-release', 'Flutter.framework'),
- );
- expect(
+ );
+ expect(
artifacts.getArtifactPath(Artifact.flutterTester),
fs.path.join(tempDir.path, 'bin', 'cache', 'artifacts', 'engine', 'linux-x64', 'flutter_tester'),
- );
- }, overrides: <Type, Generator>{
- Cache: () => Cache(rootOverride: tempDir),
- Platform: () => FakePlatform(operatingSystem: 'linux'),
- });
+ );
+ }, overrides: <Type, Generator>{
+ Cache: () => Cache(rootOverride: tempDir),
+ FileSystem: () => memoryFileSystem,
+ Platform: () => FakePlatform(operatingSystem: 'linux'),
+ });
- testUsingContext('getEngineType', () {
- expect(
+ testUsingContext('getEngineType', () {
+ expect(
artifacts.getEngineType(TargetPlatform.android_arm, BuildMode.debug),
'android-arm',
- );
- expect(
+ );
+ expect(
artifacts.getEngineType(TargetPlatform.ios, BuildMode.release),
'ios-release',
- );
- expect(
+ );
+ expect(
artifacts.getEngineType(TargetPlatform.darwin_x64),
'darwin-x64',
- );
- }, overrides: <Type, Generator>{
- Cache: () => Cache(rootOverride: tempDir),
- Platform: () => FakePlatform(operatingSystem: 'linux'),
- });
- });
-
- group('LocalEngineArtifacts', () {
-
- Directory tempDir;
- LocalEngineArtifacts artifacts;
-
- setUp(() {
- tempDir = fs.systemTempDirectory.createTempSync('flutter_tools_artifacts_test_local.');
- artifacts = LocalEngineArtifacts(tempDir.path,
- fs.path.join(tempDir.path, 'out', 'android_debug_unopt'),
- fs.path.join(tempDir.path, 'out', 'host_debug_unopt'),
- );
+ );
+ }, overrides: <Type, Generator>{
+ Cache: () => Cache(rootOverride: tempDir),
+ FileSystem: () => memoryFileSystem,
+ Platform: () => FakePlatform(operatingSystem: 'linux'),
+ });
});
- tearDown(() {
- tryToDelete(tempDir);
- });
+ group('LocalEngineArtifacts', () {
+ LocalEngineArtifacts artifacts;
- testUsingContext('getArtifactPath', () {
- expect(
+ setUp(() {
+ artifacts = LocalEngineArtifacts(tempDir.path,
+ memoryFileSystem.path.join(tempDir.path, 'out', 'android_debug_unopt'),
+ memoryFileSystem.path.join(tempDir.path, 'out', 'host_debug_unopt'),
+ );
+ });
+
+ testUsingContext('getArtifactPath', () {
+ expect(
artifacts.getArtifactPath(Artifact.flutterFramework, platform: TargetPlatform.ios, mode: BuildMode.release),
fs.path.join(tempDir.path, 'out', 'android_debug_unopt', 'Flutter.framework'),
- );
- expect(
+ );
+ expect(
artifacts.getArtifactPath(Artifact.flutterTester),
fs.path.join(tempDir.path, 'out', 'android_debug_unopt', 'flutter_tester'),
- );
- expect(
- artifacts.getArtifactPath(Artifact.engineDartSdkPath),
- fs.path.join(tempDir.path, 'out', 'host_debug_unopt', 'dart-sdk'),
- );
- }, overrides: <Type, Generator>{
- Platform: () => FakePlatform(operatingSystem: 'linux'),
- });
+ );
+ expect(
+ artifacts.getArtifactPath(Artifact.engineDartSdkPath),
+ fs.path.join(tempDir.path, 'out', 'host_debug_unopt', 'dart-sdk'),
+ );
+ }, overrides: <Type, Generator>{
+ FileSystem: () => memoryFileSystem,
+ Platform: () => FakePlatform(operatingSystem: 'linux'),
+ });
- testUsingContext('getEngineType', () {
- expect(
+ testUsingContext('getEngineType', () {
+ expect(
artifacts.getEngineType(TargetPlatform.android_arm, BuildMode.debug),
'android_debug_unopt',
- );
- expect(
+ );
+ expect(
artifacts.getEngineType(TargetPlatform.ios, BuildMode.release),
'android_debug_unopt',
- );
- expect(
+ );
+ expect(
artifacts.getEngineType(TargetPlatform.darwin_x64),
'android_debug_unopt',
- );
- }, overrides: <Type, Generator>{
- Platform: () => FakePlatform(operatingSystem: 'linux'),
+ );
+ }, overrides: <Type, Generator>{
+ FileSystem: () => memoryFileSystem,
+ Platform: () => FakePlatform(operatingSystem: 'linux'),
+ });
});
});
}
diff --git a/packages/flutter_tools/test/general.shard/cache_test.dart b/packages/flutter_tools/test/general.shard/cache_test.dart
index ca29c69..e2fe07e 100644
--- a/packages/flutter_tools/test/general.shard/cache_test.dart
+++ b/packages/flutter_tools/test/general.shard/cache_test.dart
@@ -6,14 +6,20 @@
import 'package:file/file.dart';
import 'package:file/memory.dart';
+import 'package:file_testing/file_testing.dart';
+import 'package:meta/meta.dart';
import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
import 'package:flutter_tools/src/cache.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/net.dart';
+import 'package:flutter_tools/src/base/os.dart';
import '../src/common.dart';
import '../src/context.dart';
+import '../src/testbed.dart';
void main() {
group('$Cache.checkLockAcquired', () {
@@ -51,8 +57,13 @@
});
group('Cache', () {
- final MockCache mockCache = MockCache();
- final MemoryFileSystem fs = MemoryFileSystem();
+ MockCache mockCache;
+ MemoryFileSystem memoryFileSystem;
+
+ setUp(() {
+ mockCache = MockCache();
+ memoryFileSystem = MemoryFileSystem();
+ });
testUsingContext('Gradle wrapper should not be up to date, if some cached artifact is not available', () {
final GradleWrapper gradleWrapper = GradleWrapper(mockCache);
@@ -63,7 +74,7 @@
expect(gradleWrapper.isUpToDateInner(), false);
}, overrides: <Type, Generator>{
Cache: ()=> mockCache,
- FileSystem: () => fs,
+ FileSystem: () => memoryFileSystem,
});
testUsingContext('Gradle wrapper should be up to date, only if all cached artifact are available', () {
@@ -78,7 +89,7 @@
expect(gradleWrapper.isUpToDateInner(), true);
}, overrides: <Type, Generator>{
Cache: ()=> mockCache,
- FileSystem: () => fs,
+ FileSystem: () => memoryFileSystem,
});
test('should not be up to date, if some cached artifact is not', () {
@@ -157,6 +168,74 @@
}, overrides: <Type, Generator>{
FileSystem: () => MockFileSystem(),
});
+
+ group('EngineCachedArtifact', () {
+ FakeHttpClient fakeHttpClient;
+ FakePlatform fakePlatform;
+ MemoryFileSystem memoryFileSystem;
+ MockCache mockCache;
+ MockOperatingSystemUtils mockOperatingSystemUtils;
+
+ setUp(() {
+ fakeHttpClient = FakeHttpClient();
+ fakePlatform = FakePlatform()..environment = const <String, String>{};
+ memoryFileSystem = MemoryFileSystem();
+ mockCache = MockCache();
+ mockOperatingSystemUtils = MockOperatingSystemUtils();
+ when(mockOperatingSystemUtils.verifyZip(any)).thenReturn(true);
+ });
+
+ testUsingContext('makes binary dirs readable and executable by all', () async {
+ final Directory artifactDir = fs.systemTempDirectory.createTempSync('artifact.');
+ final Directory downloadDir = fs.systemTempDirectory.createTempSync('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'],
+ ],
+ );
+ 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,
+ HttpClientFactory: () => () => fakeHttpClient,
+ OperatingSystemUtils: () => mockOperatingSystemUtils,
+ Platform: () => fakePlatform,
+ });
+ });
+}
+
+class FakeCachedArtifact extends EngineCachedArtifact {
+ FakeCachedArtifact({
+ String stampName = 'STAMP',
+ @required Cache cache,
+ Set<DevelopmentArtifact> requiredArtifacts = const <DevelopmentArtifact>{},
+ 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 MockFileSystem extends ForwardingFileSystem {
@@ -179,3 +258,4 @@
class MockCachedArtifact extends Mock implements CachedArtifact {}
class MockInternetAddress extends Mock implements InternetAddress {}
class MockCache extends Mock implements Cache {}
+class MockOperatingSystemUtils extends Mock implements OperatingSystemUtils {}
diff --git a/packages/flutter_tools/test/general.shard/commands/create_usage_test.dart b/packages/flutter_tools/test/general.shard/commands/create_usage_test.dart
index 8ab8118..6b80557 100644
--- a/packages/flutter_tools/test/general.shard/commands/create_usage_test.dart
+++ b/packages/flutter_tools/test/general.shard/commands/create_usage_test.dart
@@ -10,9 +10,9 @@
import 'package:flutter_tools/src/reporting/usage.dart';
import '../../src/common.dart';
+import '../../src/context.dart';
import '../../src/testbed.dart';
-
void main() {
group('usageValues', () {
Testbed testbed;
diff --git a/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_test.dart b/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_test.dart
index e63ec84..a3a0369 100644
--- a/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_test.dart
+++ b/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_test.dart
@@ -401,16 +401,14 @@
group('fuchsia app start and stop: ', () {
MemoryFileSystem memoryFileSystem;
- MockOperatingSystemUtils osUtils;
+ FakeOperatingSystemUtils osUtils;
FakeFuchsiaDeviceTools fuchsiaDeviceTools;
MockFuchsiaSdk fuchsiaSdk;
setUp(() {
memoryFileSystem = MemoryFileSystem();
- osUtils = MockOperatingSystemUtils();
+ osUtils = FakeOperatingSystemUtils();
fuchsiaDeviceTools = FakeFuchsiaDeviceTools();
fuchsiaSdk = MockFuchsiaSdk();
-
- when(osUtils.findFreePort()).thenAnswer((_) => Future<int>.value(12345));
});
Future<LaunchResult> setupAndStartApp({
@@ -640,8 +638,6 @@
class MockProcessResult extends Mock implements ProcessResult {}
-class MockOperatingSystemUtils extends Mock implements OperatingSystemUtils {}
-
class MockFile extends Mock implements File {}
class MockProcess extends Mock implements Process {}
diff --git a/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_workflow_test.dart b/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_workflow_test.dart
index 6b6c973..caf1dc7 100644
--- a/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_workflow_test.dart
+++ b/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_workflow_test.dart
@@ -3,7 +3,6 @@
// found in the LICENSE file.
import 'package:flutter_tools/src/base/file_system.dart';
-import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/fuchsia/fuchsia_sdk.dart';
import 'package:flutter_tools/src/fuchsia/fuchsia_workflow.dart';
import 'package:mockito/mockito.dart';
@@ -11,8 +10,6 @@
import '../../src/common.dart';
import '../../src/context.dart';
-class MockOperatingSystemUtils extends Mock implements OperatingSystemUtils {}
-
class MockFile extends Mock implements File {}
void main() {
diff --git a/packages/flutter_tools/test/general.shard/resident_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_runner_test.dart
index 0a457ea..3b181ab 100644
--- a/packages/flutter_tools/test/general.shard/resident_runner_test.dart
+++ b/packages/flutter_tools/test/general.shard/resident_runner_test.dart
@@ -19,6 +19,7 @@
import 'package:mockito/mockito.dart';
import '../src/common.dart';
+import '../src/context.dart';
import '../src/testbed.dart';
void main() {
diff --git a/packages/flutter_tools/test/src/context.dart b/packages/flutter_tools/test/src/context.dart
index fa28b05..eb1ed6e 100644
--- a/packages/flutter_tools/test/src/context.dart
+++ b/packages/flutter_tools/test/src/context.dart
@@ -33,8 +33,8 @@
/// Return the test logger. This assumes that the current Logger is a BufferLogger.
BufferLogger get testLogger => context.get<Logger>();
-MockDeviceManager get testDeviceManager => context.get<DeviceManager>();
-MockDoctor get testDoctor => context.get<Doctor>();
+FakeDeviceManager get testDeviceManager => context.get<DeviceManager>();
+FakeDoctor get testDoctor => context.get<Doctor>();
typedef ContextInitializer = void Function(AppContext testContext);
@@ -71,8 +71,8 @@
name: 'mocks',
overrides: <Type, Generator>{
Config: () => buildConfig(fs),
- DeviceManager: () => MockDeviceManager(),
- Doctor: () => MockDoctor(),
+ DeviceManager: () => FakeDeviceManager(),
+ Doctor: () => FakeDoctor(),
FlutterVersion: () => MockFlutterVersion(),
HttpClient: () => MockHttpClient(),
IOSSimulatorUtils: () {
@@ -82,10 +82,10 @@
},
OutputPreferences: () => OutputPreferences(showColor: false),
Logger: () => BufferLogger(),
- OperatingSystemUtils: () => MockOperatingSystemUtils(),
+ OperatingSystemUtils: () => FakeOperatingSystemUtils(),
SimControl: () => MockSimControl(),
- Usage: () => MockUsage(),
- XcodeProjectInterpreter: () => MockXcodeProjectInterpreter(),
+ Usage: () => FakeUsage(),
+ XcodeProjectInterpreter: () => FakeXcodeProjectInterpreter(),
FileSystem: () => LocalFileSystemBlockingSetCurrentDirectory(),
TimeoutConfiguration: () => const TimeoutConfiguration(),
},
@@ -135,7 +135,7 @@
}
}
-class MockDeviceManager implements DeviceManager {
+class FakeDeviceManager implements DeviceManager {
List<Device> devices = <Device>[];
String _specifiedDeviceId;
@@ -198,12 +198,12 @@
}
}
-class MockAndroidLicenseValidator extends AndroidLicenseValidator {
+class FakeAndroidLicenseValidator extends AndroidLicenseValidator {
@override
Future<LicensesAccepted> get licensesAccepted async => LicensesAccepted.all;
}
-class MockDoctor extends Doctor {
+class FakeDoctor extends Doctor {
// True for testing.
@override
bool get canListAnything => true;
@@ -220,7 +220,7 @@
final List<DoctorValidator> superValidators = super.validators;
return superValidators.map<DoctorValidator>((DoctorValidator v) {
if (v is AndroidLicenseValidator) {
- return MockAndroidLicenseValidator();
+ return FakeAndroidLicenseValidator();
}
return v;
}).toList();
@@ -233,11 +233,14 @@
}
}
-class MockOperatingSystemUtils implements OperatingSystemUtils {
+class FakeOperatingSystemUtils implements OperatingSystemUtils {
@override
ProcessResult makeExecutable(File file) => null;
@override
+ void chmod(FileSystemEntity entity, String mode) { }
+
+ @override
File which(String execName) => null;
@override
@@ -273,7 +276,7 @@
class MockIOSSimulatorUtils extends Mock implements IOSSimulatorUtils {}
-class MockUsage implements Usage {
+class FakeUsage implements Usage {
@override
bool get isFirstRun => false;
@@ -314,7 +317,7 @@
void printWelcome() { }
}
-class MockXcodeProjectInterpreter implements XcodeProjectInterpreter {
+class FakeXcodeProjectInterpreter implements XcodeProjectInterpreter {
@override
bool get isInstalled => true;
diff --git a/packages/flutter_tools/test/src/testbed.dart b/packages/flutter_tools/test/src/testbed.dart
index d01a0cd..ac4901c 100644
--- a/packages/flutter_tools/test/src/testbed.dart
+++ b/packages/flutter_tools/test/src/testbed.dart
@@ -9,6 +9,7 @@
import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/io.dart';
+import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/file_system.dart';
@@ -33,6 +34,7 @@
? FileSystemStyle.windows
: FileSystemStyle.posix),
Logger: () => BufferLogger(), // Allows reading logs and prevents stdout.
+ OperatingSystemUtils: () => FakeOperatingSystemUtils(),
OutputPreferences: () => OutputPreferences(showColor: false), // configures BufferLogger to avoid color codes.
Usage: () => NoOpUsage(), // prevent addition of analytics from burdening test mocks
FlutterVersion: () => FakeFlutterVersion() // prevent requirement to mock git for test runner.