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 }