| /** |
| * @license |
| * Copyright 2023 The Chromium 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 {TagColor} from '@gerritcodereview/typescript-api/checks'; |
| import {Attempt, Build} from './checks-fetcher'; |
| import {FaultAttribute, FaultAttributeProperties} from './failure-analysis'; |
| import {TestVariant} from './resultdb-client'; |
| |
| /** |
| * assignFaultAttributesToVariants assigns fault attributes to corresponding test variants. |
| * @param tvsByBuilds mapping of build IDs to test variants |
| * @param attemptsByBuilder mapping of builder names to build attempts |
| */ |
| export function assignFaultAttributesToVariants( |
| tvsByBuilds: {[key: string]: {variants: TestVariant[]; errorMessage: string}}, |
| attemptsByBuilder: {[key: string]: Attempt[]} |
| ) { |
| const cqOrchestratorBuilds = attemptsByBuilder['cq-orchestrator']?.map( |
| (attempt: Attempt) => attempt.build |
| ); |
| |
| if (!cqOrchestratorBuilds) { |
| return; |
| } |
| const faultAttributeEntries = getFaultAttributeEntries(cqOrchestratorBuilds); |
| for (const orchBuild of cqOrchestratorBuilds) { |
| for (const testVariant of tvsByBuilds[orchBuild.id]?.variants ?? []) { |
| const key = getFaultAttributeEntryKey( |
| orchBuild.id, |
| testVariant.variant?.def.build_target, |
| testVariant.variant?.def.model, |
| testVariant.testId ?? '' |
| ); |
| |
| if (!key) { |
| continue; |
| } |
| testVariant.faultAttribute = faultAttributeEntries[key]; |
| } |
| } |
| } |
| |
| /** |
| * getFaultAttributeEntryKey returns an object key using the provided build ID & test variant properties. |
| * @param buildId ID of the relevant orch build the test is contained in |
| * @param buildTarget the build target the test variant was executed on |
| * @param modelName the model (may be empty) that the test variant was executed on |
| * @param testName the relevant test name of the test variant (aka test ID) |
| */ |
| export function getFaultAttributeEntryKey( |
| buildId: string, |
| buildTarget: string, |
| modelName: string, |
| testName: string |
| ) { |
| modelName = modelName ? `-${modelName}` : ''; |
| return `${buildId}-${buildTarget}${modelName}-${testName}`; |
| } |
| |
| /** |
| * getFaultAttributeEntries maps a build ID & fault attribute properties to a particular fault attribute. The build ID & fault attribute properties are combined into a key defined by getFaultAttributeEntryKey |
| * @param builds list of builds to map fault attributes for |
| */ |
| function getFaultAttributeEntries(builds: Build[]) { |
| // Create map by the getFaultAttributeEntryKey function to an entry |
| const faultAttributeEntries: {[key: string]: FaultAttributeProperties} = {}; |
| for (const build of builds) { |
| const faultAttributes = |
| build.output?.properties?.cq_fault_attributions?.testFailureAttributions; |
| if (!faultAttributes) { |
| continue; |
| } |
| for (const faultAttributedBuildTarget of faultAttributes) { |
| const buildTarget = faultAttributedBuildTarget.buildTarget; |
| const model = faultAttributedBuildTarget.model ?? ''; |
| for (const faultAttribute of faultAttributedBuildTarget.faultAttributes) { |
| const key = getFaultAttributeEntryKey( |
| build.id, |
| buildTarget, |
| model, |
| faultAttribute.testName |
| ); |
| faultAttributeEntries[key] = faultAttribute; |
| } |
| } |
| } |
| |
| return faultAttributeEntries; |
| } |
| |
| /** |
| * getFaultAttributeTagDisplayName returns the display name for the fault attribute tag |
| * @param faultAttribute the fault attribute to retrieve a display name for |
| */ |
| export function getFaultAttributeTagDisplayName( |
| faultAttribute: FaultAttributeProperties |
| ) { |
| if (faultAttribute.likelyFlaky) { |
| return 'Likely flaky'; |
| } |
| |
| switch (faultAttribute.snapshotComparisonFaultAttribution) { |
| case FaultAttribute.MATCHING_FAILURE_FOUND: |
| return 'Pre-existing identical failure'; |
| case FaultAttribute.DIFFERING_FAILURE_FOUND: |
| return 'Pre-existing differing failure'; |
| case FaultAttribute.SUCCESS_FOUND: |
| return 'New failure'; |
| case FaultAttribute.NO_COMPARISON: |
| default: |
| return null; |
| } |
| } |
| |
| /** |
| * getFaultAttributeTagColor returns a tag color for relevant types of fault attributes. |
| * @param faultAttribute the fault attribute to retrieve a tag color for |
| */ |
| export function getFaultAttributeTagColor( |
| faultAttribute: FaultAttributeProperties |
| ) { |
| if (faultAttribute.likelyFlaky) { |
| return TagColor.YELLOW; |
| } |
| |
| switch (faultAttribute.snapshotComparisonFaultAttribution) { |
| case FaultAttribute.DIFFERING_FAILURE_FOUND: |
| return TagColor.YELLOW; |
| case FaultAttribute.SUCCESS_FOUND: |
| return TagColor.PINK; |
| case FaultAttribute.MATCHING_FAILURE_FOUND: |
| return TagColor.GRAY; |
| case FaultAttribute.NO_COMPARISON: |
| default: |
| return null; |
| } |
| } |
| |
| /** |
| * getFaultAttributeTagTooltip returns tooltip text for relevant types of fault attributes. |
| * @param faultAttribute the fault attribute to retrieve a tooltip for |
| */ |
| export function getFaultAttributeTagTooltip( |
| faultAttribute: FaultAttributeProperties |
| ) { |
| if (faultAttribute.likelyFlaky) { |
| return 'This test failure is likely flaky'; |
| } |
| |
| switch (faultAttribute.snapshotComparisonFaultAttribution) { |
| case FaultAttribute.MATCHING_FAILURE_FOUND: |
| return 'This test failure occurred in an earlier snapshot build with an identical failure reason'; |
| case FaultAttribute.DIFFERING_FAILURE_FOUND: |
| return 'This test failure occurred in an earlier snapshot build with a different failure reason'; |
| case FaultAttribute.SUCCESS_FOUND: |
| return 'This test failure is not present in ToT and may need some additional debugging'; |
| case FaultAttribute.NO_COMPARISON: |
| default: |
| return null; |
| } |
| } |