go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/analysis/proto/bq/clustered_failure_row.proto (about)

     1  // Copyright 2022 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  syntax = "proto3";
    16  
    17  package luci.analysis.bq;
    18  
    19  import "google/protobuf/timestamp.proto";
    20  import "go.chromium.org/luci/analysis/proto/v1/common.proto";
    21  import "go.chromium.org/luci/analysis/proto/v1/sources.proto";
    22  import "go.chromium.org/luci/analysis/proto/v1/failure_reason.proto";
    23  
    24  option go_package = "go.chromium.org/luci/analysis/proto/bq;bqpb";
    25  
    26  // ClusteredFailureRow represents a row in a BigQuery table for a clustered
    27  // test failure.
    28  message ClusteredFailureRow {
    29    // The LUCI project that the test failure belongs to.
    30    string project = 39;
    31  
    32    // The clustering algorithm which clustered the test failure.
    33    string cluster_algorithm = 1;
    34  
    35    // The algorithm-defined cluster ID. Together with the cluster algorithm,
    36    // this uniquely defines a cluster the test failure was clustered into.
    37    //
    38    // Note that each test failure may appear in multiple clusters (due to
    39    // the presence of multiple clustering algorithms), but each clustering
    40    // algorithm may only cluster the test result into one cluster.
    41    //
    42    // Note that the cluster ID is split over two fields (cluster_algorithm,
    43    // cluster_id), rather than as one field with a record type, so that
    44    // BigQuery clustering can be defined over the ID (not possible if a
    45    // record type was used).
    46    string cluster_id = 2;
    47  
    48    // The test results system from which the test originated.
    49    //
    50    // Currently, the only valid value is "resultdb".
    51    string test_result_system = 3;
    52  
    53    // The invocation from which this test result was ingested. This is
    54    // the top-level invocation that was ingested, an "invocation" being
    55    // a container of test results as identified by the source test result
    56    // system.
    57    //
    58    // For ResultDB, LUCI Analysis ingests invocations corresponding to
    59    // buildbucket builds.
    60    //
    61    // All test results ingested from the same invocation (i.e. with the
    62    // same ingested_invocation_id) will have the same partition time.
    63    string ingested_invocation_id = 21;
    64  
    65    // The identity of the test result in the test results system. Together
    66    // with the test results system and the ingested invocation ID, this uniquely
    67    // identifies the failure that was clustered.
    68    //
    69    // In some test result systems (e.g. ResultDB), a test result might be
    70    // included in multiple invocations. Where this occurs, the test result may be
    71    // ingested by LUCI Analysis multiple times, once for each top-level
    72    // invocation it appears in. The same test result may have different
    73    // attributes (e.g. presubmit_run_owner) depending on which top-level
    74    // invocation it is ingested under.
    75    //
    76    // For test results in ResultDB, the format is:
    77    // "invocations/{INVOCATION_ID}/tests/{URL_ESCAPED_TEST_ID}/results/{RESULT_ID}"
    78    // Where INVOCATION_ID, URL_ESCAPED_TEST_ID and RESULT_ID are values
    79    // defined in ResultDB.
    80    //
    81    // Note that the test result ID is split over three fields
    82    // (test_result_system, ingested_invocation_id, test_result_id), rather than
    83    // as one field with a record type, so that BigQuery clustering can be defined
    84    // over the ID (not possible if a record type was used).
    85    string test_result_id = 4;
    86  
    87    // Last Updated defines the version of test result-cluster inclusion status,
    88    // as represented by this row. During its lifetime, due to changing
    89    // failure association rules and clustering algorithm revisions, the
    90    // clusters a test result is in may be updated.
    91    //
    92    // To achieve deletion in an append-optimised datastore like BigQuery,
    93    // a new row will be exported for a given (cluster_algorithm, cluster_id,
    94    // test_result_system, ingested_invocation_id, test_result_id) tuple with a
    95    // later last_updated time that changes the is_included and/or
    96    // is_included_with_high_priority fields. A scheduled query periodically
    97    // purges superseded rows, to avoid excessive growth in the table.
    98    //
    99    // Clients should filter the rows they read to ensure they only use the
   100    // rows with the latest last_updated time.
   101    //
   102    // The following is the definition of a view that correctly uses
   103    // the last updated time column to query the table:
   104    //   SELECT
   105    //     ARRAY_AGG(cf ORDER BY last_updated DESC LIMIT 1)[OFFSET(0)] as row
   106    //   FROM clustered_failures cf
   107    //   -- Recommended: Apply restriction on partitions (e.g. last 14 days) as
   108    //   -- desired.
   109    //   -- WHERE partition_time >= TIMESTAMP_SUB(@as_at_time, INTERVAL 14 DAY)
   110    //   GROUP BY project, cluster_algorithm, cluster_id, test_result_system, ingested_invocation_id, test_result_id
   111    //   HAVING row.is_included
   112    //
   113    // This is based on the query design in [1].
   114    // [1]: https://cloud.google.com/blog/products/bigquery/performing-large-scale-mutations-in-bigquery
   115    google.protobuf.Timestamp last_updated = 5;
   116  
   117    // The test result partition time identifies the beginning of the test
   118    // result retention period, and corresponds approximately to the time
   119    // the test result was produced.
   120    //
   121    // It is guaranteed that all test results from one presubmit run
   122    // will have the same partition time. It is also guaranteed that all
   123    // test results from one build will have the same partition time (in
   124    // case of builds associated with presubmit runs this was implied by
   125    // previous guarantee, but for testing that occurs outside presubmit
   126    // this is an added guarantee).
   127    google.protobuf.Timestamp partition_time = 6;
   128  
   129    // Whether the test result is included in the cluster. Set to false if
   130    // the test result has been removed from the cluster.
   131    // False values appear in BigQuery as NULL.
   132    bool is_included = 7;
   133  
   134    // Whether the test result is included in the cluster with high priority.
   135    // True if either:
   136    // 1. this cluster is a bug cluster (i.e. cluster defined by failure
   137    //    association rule), OR
   138    // 2. this cluster is a suggested cluster, and the test result is NOT
   139    //    also in a bug cluster.
   140    // False values appear in BigQuery as NULL.
   141    bool is_included_with_high_priority = 8;
   142  
   143    // The chunk this failure was processed and stored in. Assigned by
   144    // LUCI Analysis ingestion.
   145    string chunk_id = 9;
   146  
   147    // The zero-based index of this failure within the chunk. Assigned by
   148    // LUCI Analysis ingestion.
   149    int64 chunk_index = 10;
   150  
   151    // Security realm of the test result.
   152    // For test results from ResultDB, this must be set. The format is
   153    // "{LUCI_PROJECT}:{REALM_SUFFIX}", for example "chromium:ci".
   154    string realm = 11;
   155  
   156    // The unique identifier of the test.
   157    // For test results from ResultDB, see luci.resultdb.v1.TestResult.test_id.
   158    string test_id = 12;
   159  
   160    // key:value pairs to specify the way of running a particular test.
   161    // e.g. a specific bucket, builder and a test suite.
   162    // For ResultDB, this is the known field.
   163    repeated luci.analysis.v1.StringPair variant = 13;
   164  
   165    // Metadata key value pairs for this test result.
   166    // It might describe this particular execution or the test case.
   167    // A key can be repeated.
   168    repeated luci.analysis.v1.StringPair tags = 32;
   169  
   170    // Hash of the variant.
   171    // hex(sha256(''.join(sorted('%s:%s\n' for k, v in variant.items())))).
   172    string variant_hash = 14;
   173  
   174    // A failure reason describing why the test failed.
   175    luci.analysis.v1.FailureReason failure_reason = 15;
   176  
   177    // The bug tracking component corresponding to this test case, as identified
   178    // by the test results system. If no information is available, this is
   179    // unset.
   180    luci.analysis.v1.BugTrackingComponent bug_tracking_component = 16;
   181  
   182    // The point in time when the test case started to execute.
   183    google.protobuf.Timestamp start_time = 17;
   184  
   185    // The amount of time the test case took to execute, in seconds.
   186    double duration = 18;
   187  
   188    reserved 19;
   189  
   190    reserved 31;
   191  
   192    message TestExoneration {
   193      // Machine-readable reasons describing why the test failure was exonerated
   194      // (if any).
   195      luci.analysis.v1.ExonerationReason reason = 1;
   196    }
   197  
   198    // The exonerations applied to the test verdict.
   199    // An empty list indicates the test verdict this test result was a part of
   200    // was not exonerated.
   201    repeated TestExoneration exonerations = 33;
   202  
   203    // Identity of the presubmit run that contains this test result.
   204    // This should be unique per "CQ+1"/"CQ+2" attempt on gerrit.
   205    //
   206    // One presumbit run MAY have many ingested invocation IDs (e.g. for its
   207    // various tryjobs), but every ingested invocation ID only ever has one
   208    // presubmit run ID (if any).
   209    //
   210    // All test results for the same presubmit run will have one
   211    // partition_time.
   212    //
   213    // If the test result was not collected as part of a presubmit run,
   214    // this is unset.
   215    luci.analysis.v1.PresubmitRunId presubmit_run_id = 20;
   216  
   217    // The owner of the presubmit run (if any).
   218    // This is the owner of the CL on which CQ+1/CQ+2 was clicked
   219    // (even in case of presubmit run with multiple CLs).
   220    // There is scope for this field to become an email address if privacy
   221    // approval is obtained, until then it is "automation" (for automation
   222    // service accounts) and "user" otherwise.
   223    string presubmit_run_owner = 29;
   224  
   225    // The mode of the presubmit run (if any).
   226    // E.g. DRY_RUN, FULL_RUN, QUICK_DRY_RUN.
   227    // If this test result does not relate to a presubmit run, this field
   228    // is left as its default value (""). In BigQuery, this results in a
   229    // NULL value.
   230    string presubmit_run_mode = 34;
   231  
   232    // The presubmit run's ending status.
   233    // Notionally luci.analysis.v1.PresubmitRunStatus, but string so that
   234    // we can chop off the "PRESUBMIT_RUN_STATUS_" prefix and have
   235    // only the status, e.g. SUCCESS, FAILURE, CANCELED.
   236    // If this test result does not relate to a presubmit run, this field
   237    // is left as its default value (""). In BigQuery, this results in a
   238    // NULL value.
   239    string presubmit_run_status = 35;
   240  
   241    reserved 30;
   242  
   243    // The status of the build that contained this test result. Can be used
   244    // to filter incomplete results (e.g. where build was cancelled or had
   245    // an infra failure). Can also be used to filter builds with incomplete
   246    // exonerations (e.g. build succeeded but some tests not exonerated).
   247    // This is the build corresponding to ingested_invocation_id.
   248    // Notionally luci.analysis.v1.BuildStatus, but string so that we can chop
   249    // off the BUILD_STATUS_ prefix that would otherwise appear on every value.
   250    string build_status = 36;
   251  
   252    // Whether the build was critical to a presubmit run succeeding.
   253    // If the build did not relate presubmit run (i.e. because it was a tryjob
   254    // for a presubmit run), this is false.
   255    // Note that both possible false values (from the build is not critical
   256    // or because the build was not part of a presubmit run) appear in
   257    // BigQuery as NULL.
   258    // You can identify which of these cases applies by
   259    // checking if presubmit_run_id is populated.
   260    bool build_critical = 37;
   261  
   262    reserved 38;
   263  
   264    // The zero-based index for this test result, in the sequence of the
   265    // ingested invocation's results for this test variant. Within the sequence,
   266    // test results are ordered by start_time and then by test result ID.
   267    // The first test result is 0, the last test result is
   268    // ingested_invocation_result_count - 1.
   269    int64 ingested_invocation_result_index = 22;
   270  
   271    // The number of test results having this test variant in the ingested
   272    // invocation.
   273    int64 ingested_invocation_result_count = 23;
   274  
   275    // Is the ingested invocation blocked by this test variant? This is
   276    // only true if all (non-skipped) test results for this test variant
   277    // (in the ingested invocation) are unexpected failures.
   278    //
   279    // Exoneration does not factor into this value; check is_exonerated
   280    // to see if the impact of this ingested invocation being blocked was
   281    // mitigated by exoneration.
   282    bool is_ingested_invocation_blocked = 24;
   283  
   284    // The identifier of the test run the test ran in. Test results in different
   285    // test runs are generally considered independent as they should be unable
   286    // to leak state to one another.
   287    //
   288    // In Chrome and Chrome OS, a test run logically corresponds to a swarming
   289    // task that runs tests, but this ID is not necessarily the ID of that
   290    // task, but rather any other ID that is unique per such task.
   291    //
   292    // If test result system is ResultDB, this is the ID of the ResultDB
   293    // invocation the test result was immediately contained within, not including
   294    // any "invocations/" prefix.
   295    string test_run_id = 25;
   296  
   297    // The zero-based index for this test result, in the sequence of results
   298    // having this test variant and test run. Within the sequence, test
   299    // results are ordered by start_time and then by test result ID.
   300    // The first test result is 0, the last test result is
   301    // test_run_result_count - 1.
   302    int64 test_run_result_index = 26;
   303  
   304    // The number of test results having this test variant and test run.
   305    int64 test_run_result_count = 27;
   306  
   307    // Is the test run blocked by this test variant? This is only true if all
   308    // (non-skipped) test results for this test variant (in the test run)
   309    // are unexpected failures.
   310    //
   311    // Exoneration does not factor into this value; check is_exonerated
   312    // to see if the impact of this test run being blocked was
   313    // mitigated by exoneration.
   314    bool is_test_run_blocked = 28;
   315  
   316    // The code sources tested, if known.
   317    luci.analysis.v1.Sources sources = 40;
   318  
   319    // The branch in source control that was tested, if known.
   320    // For example, the `refs/heads/main` branch in the `chromium/src` repo
   321    // hosted by `chromium.googlesource.com`.
   322    // This is a subset of the information in the `sources` field.
   323    luci.analysis.v1.SourceRef source_ref = 41;
   324  
   325    // Hash of the source_ref field, as 16 lowercase hexadecimal characters.
   326    // Can be used to uniquely identify a branch in a source code
   327    // version control system.
   328    string source_ref_hash = 42;
   329  
   330    // The gardener rotations the build is a part of. Corresponds to the
   331    // `sheriff_rotations` field of the build input properties.
   332    repeated string build_gardener_rotations = 43;
   333  
   334    // Information about the (test,variant,source ref) the verdict is from.
   335    // Source ref refers to the source branch that was tested, see
   336    // `source_ref`.
   337    message TestVariantBranch {
   338      // The counts of verdicts observed for this (test, variant, source ref)
   339      // with a partition time equal or less than the partition time of the
   340      // clustered failure. This figure only considers verdicts ingested by
   341      // LUCI Analysis prior to the clustered failure.
   342      // Hourly bucketing is used internally, so data is aligned to hour
   343      // boundaries.
   344  
   345      // The number of flaky verdicts in the preceding 24 hours. A verdict
   346      // is considered flaky for this count if it has both expected and
   347      // unexpected test results (excluding skips). Whether the verdict
   348      // was exonerated is irrelevant.
   349      int64 flaky_verdicts_24h = 1;
   350  
   351      // The number of unexpected verdicts in the preceding 24 hours. A verdict
   352      // is considered unexpected for this count if has only unexpected test
   353      // results (excluding skips). Whether the verdict was exonerated is
   354      // irrelevant.
   355      int64 unexpected_verdicts_24h = 2;
   356  
   357      // The total number of verdicts in the preceding 24 hours, excluding
   358      // verdicts with only skipped test results.
   359      int64 total_verdicts_24h = 3;
   360    }
   361  
   362    // Information about the test variant branch the result is from.
   363    TestVariantBranch test_variant_branch = 44;
   364  
   365    // Next ID: 45.
   366  }