Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion app_dart/lib/src/model/common/presubmit_completed_check.dart
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class PresubmitCompletedJob {
Build build,
PresubmitUserData userData, {
TaskStatus? status,
String? summaryPrepend,
}) {
return PresubmitCompletedJob(
name: build.builder.builder,
Expand All @@ -85,7 +86,10 @@ class PresubmitCompletedJob {
attempt: _getAttempt(build),
startTime: build.startTime.toDateTime().millisecondsSinceEpoch,
endTime: build.endTime.toDateTime().millisecondsSinceEpoch,
summary: build.summaryMarkdown,
summary: [
if (summaryPrepend != null && summaryPrepend.isNotEmpty) summaryPrepend,
if (build.summaryMarkdown.isNotEmpty) build.summaryMarkdown,
].join('\n---\n'),
buildNumber: build.number,
buildId: build.id,
);
Expand Down
29 changes: 15 additions & 14 deletions app_dart/lib/src/request_handlers/presubmit_subscription.dart
Original file line number Diff line number Diff line change
Expand Up @@ -173,21 +173,21 @@ base class PresubmitSubscription extends SubscriptionHandler {
}
}
CheckRunConclusion? override;
if (!isUnifiedCheckRun) {
String? suppressedMessage;
if (build.status.isTaskFailed() && !rescheduled) {
// If a test is suppressed; we avoid setting a failing status.
final isSuppressed = await cache.isTestSuppressed(
testName: builderName,
repository: userData.commit.slug,
firestore: _firestore,
);
if (isSuppressed) {
override = CheckRunConclusion.neutral;
suppressedMessage =
'### ⚠️ Test failed but marked as suppressed on dashboard';
}
String? suppressedMessage;
if (build.status.isTaskFailed() && !rescheduled) {
// If a test is suppressed; we avoid setting a failing status.
final isSuppressed = await cache.isTestSuppressed(
testName: builderName,
repository: userData.commit.slug,
firestore: _firestore,
);
if (isSuppressed) {
override = CheckRunConclusion.neutral;
suppressedMessage =
'### ⚠️ Test failed but marked as suppressed on dashboard';
}
}
if (!isUnifiedCheckRun) {
if (userData.checkRunId == null) {
log.error('checkRunId is null for non-unified check run');
return;
Expand All @@ -209,6 +209,7 @@ base class PresubmitSubscription extends SubscriptionHandler {
status: override == CheckRunConclusion.neutral
? TaskStatus.neutral
: null,
summaryPrepend: suppressedMessage,
);
await _scheduler.processCheckRunCompleted(check);
}
Expand Down
27 changes: 27 additions & 0 deletions app_dart/test/model/common/presubmit_completed_check_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,32 @@ void main() {
expect(check.buildNumber, 1234);
expect(check.buildId, Int64.MAX_VALUE);
});

test('fromBuild handles custom status and summaryPrepend', () {
final build = Build(
id: Int64.MAX_VALUE,
builder: BuilderID(builder: 'test_builder'),
status: Status.FAILURE,
summaryMarkdown: 'Build failed.',
);

final userData = PresubmitUserData(
commit: CommitRef(slug: slug, sha: sha, branch: 'master'),
stage: CiStage.fusionEngineBuild,
pullRequestNumber: 1,
guardCheckRunId: 123,
checkSuiteId: 456,
);

final check = PresubmitCompletedJob.fromBuild(
build,
userData,
status: TaskStatus.neutral,
summaryPrepend: 'Suppressed message',
);

expect(check.status, TaskStatus.neutral);
expect(check.summary, 'Suppressed message\n---\nBuild failed.');
});
});
}
199 changes: 199 additions & 0 deletions app_dart/test/request_handlers/presubmit_luci_subscription_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ void main() {
late MockScheduler mockScheduler;
late FakeFirestoreService firestore;
late FakePubSub pubSub;
late FakeBuildBucketClient buildBucketClient;

setUp(() async {
firestore = FakeFirestoreService();
Expand All @@ -50,12 +51,14 @@ void main() {
ciYaml: examplePresubmitRescheduleFusionConfig,
);

buildBucketClient = FakeBuildBucketClient();
handler = PresubmitLuciSubscription(
cache: CacheService.inMemory(),
config: config,
luciBuildService: FakeLuciBuildService(
config: config,
firestore: firestore,
buildBucketClient: buildBucketClient,
),
githubChecksService: mockGithubChecksService,
authProvider: FakeDashboardAuthentication(),
Expand Down Expand Up @@ -647,8 +650,163 @@ void main() {
),
),
).called(1);

final captured = verify(
mockScheduler.processCheckRunCompleted(captureAny),
).captured;
expect(captured, hasLength(1));
expect(
captured[0],
isA<PresubmitCompletedJob>()
.having((e) => e.status, 'status', TaskStatus.neutral)
.having(
(e) => e.summary,
'summary',
contains(
'### ⚠️ Test failed but marked as suppressed on dashboard',
),
),
);
});

test('Requests when unified check run failed and is suppressed', () async {
final userData = PresubmitUserData(
commit: CommitRef(
sha: 'abc',
branch: 'master',
slug: RepositorySlug('flutter', 'flutter'),
),
guardCheckRunId: 1,
checkSuiteId: 2,
);

// Setup Firestore
firestore.putDocument(
SuppressedTest(
name: 'Linux A',
repository: 'flutter/flutter',
issueLink: 'https://github.com/flutter/flutter/issues/123',
isSuppressed: true,
createTimestamp: DateTime.now(),
)
..name = firestore.resolveDocumentName(
SuppressedTest.kCollectionId,
'suppressed_1',
),
);

buildBucketClient.getBuildResponse = Future.value(
bbv2.Build()
..id = Int64(1)
..builder = (bbv2.BuilderID()..builder = 'Linux A')
..status = bbv2.Status.FAILURE
..summaryMarkdown = 'test summary',
);

when(
mockScheduler.processCheckRunCompleted(any),
).thenAnswer((_) async => true);

tester.message = createPushMessage(
Int64(1),
status: bbv2.Status.FAILURE,
builder: 'Linux A',
userData: userData,
);

await tester.post(handler);

verifyNever(
mockGithubChecksService.updateCheckStatus(
build: anyNamed('build'),
checkRunId: anyNamed('checkRunId'),
luciBuildService: anyNamed('luciBuildService'),
slug: anyNamed('slug'),
conclusionOverride: anyNamed('conclusionOverride'),
summaryPrepend: anyNamed('summaryPrepend'),
),
);

final captured = verify(
mockScheduler.processCheckRunCompleted(captureAny),
).captured;
expect(captured, hasLength(1));
expect(
captured[0],
isA<PresubmitCompletedJob>()
.having((e) => e.status, 'status', TaskStatus.neutral)
.having(
(e) => e.summary,
'summary',
contains(
'### ⚠️ Test failed but marked as suppressed on dashboard',
),
),
);
});

test(
'Requests when unified check run failed and is NOT suppressed',
() async {
final userData = PresubmitUserData(
commit: CommitRef(
sha: 'abc',
branch: 'master',
slug: RepositorySlug('flutter', 'flutter'),
),
guardCheckRunId: 1,
checkSuiteId: 2,
);

buildBucketClient.getBuildResponse = Future.value(
bbv2.Build()
..id = Int64(1)
..builder = (bbv2.BuilderID()..builder = 'Linux A')
..status = bbv2.Status.FAILURE
..summaryMarkdown = 'test summary',
);

when(
mockScheduler.processCheckRunCompleted(any),
).thenAnswer((_) async => true);

tester.message = createPushMessage(
Int64(1),
status: bbv2.Status.FAILURE,
builder: 'Linux A',
userData: userData,
);

await tester.post(handler);

verifyNever(
mockGithubChecksService.updateCheckStatus(
build: anyNamed('build'),
checkRunId: anyNamed('checkRunId'),
luciBuildService: anyNamed('luciBuildService'),
slug: anyNamed('slug'),
conclusionOverride: anyNamed('conclusionOverride'),
summaryPrepend: anyNamed('summaryPrepend'),
),
);

final captured = verify(
mockScheduler.processCheckRunCompleted(captureAny),
).captured;
expect(captured, hasLength(1));
expect(
captured[0],
isA<PresubmitCompletedJob>()
.having((e) => e.status, 'status', TaskStatus.failed)
.having(
(e) => e.summary,
'summary',
isNot(contains('marked as suppressed')),
),
);
},
);

test('Suppression check skipped when rescheduled', () async {
tester.message = createPushMessage(
Int64(1),
Expand Down Expand Up @@ -692,6 +850,47 @@ void main() {
).called(1);
});

test('Unified Suppression check skipped when rescheduled', () async {
buildBucketClient.getBuildResponse = Future.value(
bbv2.Build()
..id = Int64(1)
..builder = (bbv2.BuilderID()
..builder = 'Linux presubmit_max_attempts=2')
..status = bbv2.Status.FAILURE
..summaryMarkdown = 'test summary',
);

tester.message = createPushMessage(
Int64(1),
status: bbv2.Status.FAILURE,
builder: 'Linux presubmit_max_attempts=2',
userData: PresubmitUserData(
commit: CommitRef(
sha: 'abc',
branch: 'master',
slug: RepositorySlug('flutter', 'flutter'),
),
guardCheckRunId: 1,
checkSuiteId: 2,
),
);

await tester.post(handler);

verifyNever(
mockGithubChecksService.updateCheckStatus(
build: anyNamed('build'),
checkRunId: anyNamed('checkRunId'),
luciBuildService: anyNamed('luciBuildService'),
slug: anyNamed('slug'),
conclusionOverride: anyNamed('conclusionOverride'),
summaryPrepend: anyNamed('summaryPrepend'),
),
);

verifyNever(mockScheduler.processCheckRunCompleted(any));
});

test(
'publishes build message to ordered-presubmit topic with orderingKey when ordering_key flag exists',
() async {
Expand Down
Loading