in script/tool/lib/src/firebase_test_lab_command.dart [121:207]
Future<PackageResult> runForPackage(RepositoryPackage package) async {
final RepositoryPackage example = package.getSingleExampleDeprecated();
final Directory androidDirectory =
example.directory.childDirectory('android');
if (!androidDirectory.existsSync()) {
return PackageResult.skip(
'${example.displayName} does not support Android.');
}
final Directory uiTestDirectory = androidDirectory
.childDirectory('app')
.childDirectory('src')
.childDirectory('androidTest');
if (!uiTestDirectory.existsSync()) {
printError('No androidTest directory found.');
return PackageResult.fail(
<String>['No tests ran (use --exclude if this is intentional).']);
}
// Ensure that the Dart integration tests will be run, not just native UI
// tests.
if (!await _testsContainDartIntegrationTestRunner(uiTestDirectory)) {
printError('No integration_test runner found. '
'See the integration_test package README for setup instructions.');
return PackageResult.fail(<String>['No integration_test runner.']);
}
// Ensures that gradle wrapper exists
final GradleProject project = GradleProject(example.directory,
processRunner: processRunner, platform: platform);
if (!await _ensureGradleWrapperExists(project)) {
return PackageResult.fail(<String>['Unable to build example apk']);
}
await _configureFirebaseProject();
if (!await _runGradle(project, 'app:assembleAndroidTest')) {
return PackageResult.fail(<String>['Unable to assemble androidTest']);
}
final List<String> errors = <String>[];
// Used within the loop to ensure a unique GCS output location for each
// test file's run.
int resultsCounter = 0;
for (final File test in _findIntegrationTestFiles(package)) {
final String testName =
getRelativePosixPath(test, from: package.directory);
print('Testing $testName...');
if (!await _runGradle(project, 'app:assembleDebug', testFile: test)) {
printError('Could not build $testName');
errors.add('$testName failed to build');
continue;
}
final String buildId = getStringArg('build-id');
final String testRunId = getStringArg('test-run-id');
final String resultsDir =
'plugins_android_test/${package.displayName}/$buildId/$testRunId/${resultsCounter++}/';
// Automatically retry failures; there is significant flake with these
// tests whose cause isn't yet understood, and having to re-run the
// entire shard for a flake in any one test is extremely slow. This should
// be removed once the root cause of the flake is understood.
// See https://github.com/flutter/flutter/issues/95063
const int maxRetries = 2;
bool passing = false;
for (int i = 1; i <= maxRetries && !passing; ++i) {
if (i > 1) {
logWarning('$testName failed on attempt ${i - 1}. Retrying...');
}
passing = await _runFirebaseTest(example, test, resultsDir: resultsDir);
}
if (!passing) {
printError('Test failure for $testName after $maxRetries attempts');
errors.add('$testName failed tests');
}
}
if (errors.isEmpty && resultsCounter == 0) {
printError('No integration tests were run.');
errors.add('No tests ran (use --exclude if this is intentional).');
}
return errors.isEmpty
? PackageResult.success()
: PackageResult.fail(errors);
}