
Some notable changes are: - Add SkiaPerfDestination - Add LegacyFlutterDestination (for backup options during transitions). - Add GcsLock Related issue: https://github.com/flutter/flutter/issues/73872
106 lines
4.0 KiB
Dart
106 lines
4.0 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 'dart:async';
|
|
|
|
import 'package:googleapis/storage/v1.dart';
|
|
import 'package:fake_async/fake_async.dart';
|
|
import 'package:gcloud/storage.dart';
|
|
import 'package:googleapis_auth/auth_io.dart';
|
|
import 'package:metrics_center/src/gcs_lock.dart';
|
|
import 'package:metrics_center/src/skiaperf.dart';
|
|
import 'package:mockito/mockito.dart';
|
|
|
|
import 'common.dart';
|
|
import 'utility.dart';
|
|
|
|
enum TestPhase {
|
|
run1,
|
|
run2,
|
|
}
|
|
|
|
class MockClient extends Mock implements AuthClient {}
|
|
|
|
void main() {
|
|
const Duration kDelayStep = Duration(milliseconds: 10);
|
|
final Map<String, dynamic> credentialsJson = getTestGcpCredentialsJson();
|
|
|
|
test('GcsLock prints warnings for long waits', () {
|
|
// Capture print to verify error messages.
|
|
final List<String> prints = <String>[];
|
|
final ZoneSpecification spec =
|
|
ZoneSpecification(print: (_, __, ___, String msg) => prints.add(msg));
|
|
|
|
Zone.current.fork(specification: spec).run<void>(() {
|
|
fakeAsync((FakeAsync fakeAsync) {
|
|
final MockClient mockClient = MockClient();
|
|
final GcsLock lock = GcsLock(mockClient, 'mockBucket');
|
|
when(mockClient.send(any)).thenThrow(DetailedApiRequestError(412, ''));
|
|
final Future<void> runFinished =
|
|
lock.protectedRun('mock.lock', () async {});
|
|
fakeAsync.elapse(const Duration(seconds: 10));
|
|
when(mockClient.send(any)).thenThrow(AssertionError('Stop!'));
|
|
runFinished.catchError((dynamic e) {
|
|
final AssertionError error = e as AssertionError;
|
|
expect(error.message, 'Stop!');
|
|
print('${error.message}');
|
|
});
|
|
fakeAsync.elapse(const Duration(seconds: 20));
|
|
});
|
|
});
|
|
|
|
const String kExpectedErrorMessage = 'The lock is waiting for a long time: '
|
|
'0:00:10.240000. If the lock file mock.lock in bucket mockBucket '
|
|
'seems to be stuck (i.e., it was created a long time ago and no one '
|
|
'seems to be owning it currently), delete it manually to unblock this.';
|
|
expect(prints, equals(<String>[kExpectedErrorMessage, 'Stop!']));
|
|
});
|
|
|
|
test('GcsLock integration test: single protectedRun is successful', () async {
|
|
final AutoRefreshingAuthClient client = await clientViaServiceAccount(
|
|
ServiceAccountCredentials.fromJson(credentialsJson), Storage.SCOPES);
|
|
final GcsLock lock = GcsLock(client, SkiaPerfDestination.kTestBucketName);
|
|
int testValue = 0;
|
|
await lock.protectedRun('test.lock', () async {
|
|
testValue = 1;
|
|
});
|
|
expect(testValue, 1);
|
|
}, skip: credentialsJson == null);
|
|
|
|
test('GcsLock integration test: protectedRun is exclusive', () async {
|
|
final AutoRefreshingAuthClient client = await clientViaServiceAccount(
|
|
ServiceAccountCredentials.fromJson(credentialsJson), Storage.SCOPES);
|
|
final GcsLock lock1 = GcsLock(client, SkiaPerfDestination.kTestBucketName);
|
|
final GcsLock lock2 = GcsLock(client, SkiaPerfDestination.kTestBucketName);
|
|
|
|
TestPhase phase = TestPhase.run1;
|
|
final Completer<void> started1 = Completer<void>();
|
|
final Future<void> finished1 = lock1.protectedRun('test.lock', () async {
|
|
started1.complete();
|
|
while (phase == TestPhase.run1) {
|
|
await Future<void>.delayed(kDelayStep);
|
|
}
|
|
});
|
|
|
|
await started1.future;
|
|
|
|
final Completer<void> started2 = Completer<void>();
|
|
final Future<void> finished2 = lock2.protectedRun('test.lock', () async {
|
|
started2.complete();
|
|
});
|
|
|
|
// started2 should not be set even after a long wait because lock1 is
|
|
// holding the GCS lock file.
|
|
await Future<void>.delayed(kDelayStep * 10);
|
|
expect(started2.isCompleted, false);
|
|
|
|
// When phase is switched to run2, lock1 should be released soon and
|
|
// lock2 should soon be able to proceed its protectedRun.
|
|
phase = TestPhase.run2;
|
|
await started2.future;
|
|
await finished1;
|
|
await finished2;
|
|
}, skip: credentialsJson == null);
|
|
}
|