1/* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17syntax = "proto3"; 18 19package luci.resultdb.v1; 20 21import "google/api/field_behavior.proto"; 22import "google/protobuf/duration.proto"; 23import "google/protobuf/struct.proto"; 24import "google/protobuf/timestamp.proto"; 25import public "tools/tradefederation/core/proto/resultdb/common.proto"; 26import public "tools/tradefederation/core/proto/resultdb/test_metadata.proto"; 27import public "tools/tradefederation/core/proto/resultdb/failure_reason.proto"; 28 29option go_package = "go.chromium.org/luci/resultdb/proto/v1;resultpb"; 30option java_package = "com.android.resultdb.proto"; 31option java_multiple_files = true; 32 33// A result of a functional test case. 34// Often a single test case is executed multiple times and has multiple results, 35// a single test suite has multiple test cases, 36// and the same test suite can be executed in different variants 37// (OS, GPU, compile flags, etc). 38// 39// This message does not specify the test id. 40// It should be available in the message that embeds this message. 41// 42// Next id: 17. 43message TestResult { 44 reserved 11; // test_location 45 46 // Can be used to refer to this test result, e.g. in ResultDB.GetTestResult 47 // RPC. 48 // Format: 49 // "invocations/{INVOCATION_ID}/tests/{URL_ESCAPED_TEST_ID}/results/{RESULT_ID}". 50 // where URL_ESCAPED_TEST_ID is test_id escaped with 51 // https://golang.org/pkg/net/url/#PathEscape See also https://aip.dev/122. 52 // 53 // Output only. 54 string name = 1 [ 55 (google.api.field_behavior) = OUTPUT_ONLY, 56 (google.api.field_behavior) = IMMUTABLE 57 ]; 58 59 // Test id, a unique identifier of the test in a LUCI project. 60 // Regex: ^[[::print::]]{1,512}$ 61 // 62 // If two tests have a common test id prefix that ends with a 63 // non-alphanumeric character, they considered a part of a group. Examples: 64 // - "a/b/c" 65 // - "a/b/d" 66 // - "a/b/e:x" 67 // - "a/b/e:y" 68 // - "a/f" 69 // This defines the following groups: 70 // - All items belong to one group because of the common prefix "a/" 71 // - Within that group, the first 4 form a sub-group because of the common 72 // prefix "a/b/" 73 // - Within that group, "a/b/e:x" and "a/b/e:y" form a sub-group because of 74 // the common prefix "a/b/e:". 75 // This can be used in UI. 76 // LUCI does not interpret test ids in any other way. 77 string test_id = 2 [(google.api.field_behavior) = IMMUTABLE]; 78 79 // Identifies a test result in a given invocation and test id. 80 // Regex: ^[a-z0-9\-_.]{1,32}$ 81 string result_id = 3 [ 82 (google.api.field_behavior) = IMMUTABLE, 83 (google.api.field_behavior) = REQUIRED 84 ]; 85 86 // Description of one specific way of running the test, 87 // e.g. a specific bucket, builder and a test suite. 88 Variant variant = 4 [(google.api.field_behavior) = IMMUTABLE]; 89 90 // Whether the result of test case execution is expected. 91 // In a typical Chromium CL, 99%+ of test results are expected. 92 // Users are typically interested only in the unexpected results. 93 // 94 // An unexpected result != test case failure. There are test cases that are 95 // expected to fail/skip/crash. The test harness compares the actual status 96 // with the expected one(s) and this field is the result of the comparison. 97 bool expected = 5 [(google.api.field_behavior) = IMMUTABLE]; 98 99 // Machine-readable status of the test case. 100 // MUST NOT be STATUS_UNSPECIFIED. 101 TestStatus status = 6 [(google.api.field_behavior) = IMMUTABLE]; 102 103 // Human-readable explanation of the result, in HTML. 104 // MUST be sanitized before rendering in the browser. 105 // 106 // The size of the summary must be equal to or smaller than 4096 bytes in 107 // UTF-8. 108 // 109 // Supports artifact embedding using custom tags: 110 // * <text-artifact> renders contents of an artifact as text. 111 // Usage: 112 // * To embed result level artifact: <text-artifact 113 // artifact-id="<artifact_id>"> 114 // * To embed invocation level artifact: <text-artifact 115 // artifact-id="<artifact_id>" inv-level> 116 string summary_html = 7 [(google.api.field_behavior) = IMMUTABLE]; 117 118 // The point in time when the test case started to execute. 119 google.protobuf.Timestamp start_time = 8 120 [(google.api.field_behavior) = IMMUTABLE]; 121 122 // Duration of the test case execution. 123 // MUST be equal to or greater than 0. 124 google.protobuf.Duration duration = 9 125 [(google.api.field_behavior) = IMMUTABLE]; 126 127 // Metadata for this test result. 128 // It might describe this particular execution or the test case. 129 // A key can be repeated. 130 repeated StringPair tags = 10 [(google.api.field_behavior) = IMMUTABLE]; 131 132 // Hash of the variant. 133 // hex(sha256(sorted(''.join('%s:%s\n' for k, v in variant.items())))). 134 // 135 // Output only. 136 string variant_hash = 12 [ 137 (google.api.field_behavior) = OUTPUT_ONLY, 138 (google.api.field_behavior) = IMMUTABLE 139 ]; 140 141 // Information about the test at the time of its execution. 142 TestMetadata test_metadata = 13; 143 144 // Information about the test failure. Only present if the test failed. 145 FailureReason failure_reason = 14; 146 147 // Arbitrary JSON object that contains structured, domain-specific properties 148 // of the test result. 149 // 150 // The serialized size must be <= 8 KB. 151 google.protobuf.Struct properties = 15; 152 153 // Whether the test result has been masked so that it includes only metadata. 154 // The metadata fields for a TestResult are: 155 // * name 156 // * test_id 157 // * result_id 158 // * expected 159 // * status 160 // * start_time 161 // * duration 162 // * variant_hash 163 // * failure_reason.primary_error_message (truncated to 140 characters) 164 // * skip_reason 165 // 166 // Output only. 167 bool is_masked = 16 [(google.api.field_behavior) = OUTPUT_ONLY]; 168 169 // Reasoning behind a test skip, in machine-readable form. 170 // Used to assist downstream analyses, such as automatic bug-filing. 171 // MUST not be set unless status is SKIP. 172 SkipReason skip_reason = 18; 173} 174 175// Machine-readable status of a test result. 176enum TestStatus { 177 // Status was not specified. 178 // Not to be used in actual test results; serves as a default value for an 179 // unset field. 180 STATUS_UNSPECIFIED = 0; 181 182 // The test case has passed. 183 PASS = 1; 184 185 // The test case has failed. 186 // Suggests that the code under test is incorrect, but it is also possible 187 // that the test is incorrect or it is a flake. 188 FAIL = 2; 189 190 // The test case has crashed during execution. 191 // The outcome is inconclusive: the code under test might or might not be 192 // correct, but the test+code is incorrect. 193 CRASH = 3; 194 195 // The test case has started, but was aborted before finishing. 196 // A common reason: timeout. 197 ABORT = 4; 198 199 // The test case did not execute. 200 // Examples: 201 // - The execution of the collection of test cases, such as a test 202 // binary, was aborted prematurely and execution of some test cases was 203 // skipped. 204 // - The test harness configuration specified that the test case MUST be 205 // skipped. 206 SKIP = 5; 207} 208 209// Machine-readable reason that a test execution was skipped. 210// Only reasons actually used are listed here, if you need a new reason 211// please add it here and send a CL to the OWNERS. 212enum SkipReason { 213 // Skip reason was not specified. 214 // This represents an unset field which should be used for non-skip test 215 // result statuses. It can also be used if none of the other statuses 216 // apply. 217 SKIP_REASON_UNSPECIFIED = 0; 218 219 // Disabled automatically in response to a test skipping policy that skips 220 // flaky tests. 221 // Used for ChromeOS CQ test filtering. 222 AUTOMATICALLY_DISABLED_FOR_FLAKINESS = 1; 223} 224 225// Indicates the test subject (e.g. a CL) is absolved from blame 226// for an unexpected result of a test variant. 227// For example, the test variant fails both with and without CL, so it is not 228// CL's fault. 229message TestExoneration { 230 // Can be used to refer to this test exoneration, e.g. in 231 // ResultDB.GetTestExoneration RPC. 232 // Format: 233 // invocations/{INVOCATION_ID}/tests/{URL_ESCAPED_TEST_ID}/exonerations/{EXONERATION_ID}. 234 // URL_ESCAPED_TEST_ID is test_variant.test_id escaped with 235 // https://golang.org/pkg/net/url/#PathEscape See also https://aip.dev/122. 236 // 237 // Output only. 238 string name = 1 [ 239 (google.api.field_behavior) = OUTPUT_ONLY, 240 (google.api.field_behavior) = IMMUTABLE 241 ]; 242 243 // Test identifier, see TestResult.test_id. 244 string test_id = 2; 245 246 // Description of the variant of the test, see Variant type. 247 // Unlike TestResult.extra_variant_pairs, this one must be a full definition 248 // of the variant, i.e. it is not combined with Invocation.base_test_variant. 249 Variant variant = 3; 250 251 // Identifies an exoneration in a given invocation and test id. 252 // It is server-generated. 253 string exoneration_id = 4 [ 254 (google.api.field_behavior) = OUTPUT_ONLY, 255 (google.api.field_behavior) = IMMUTABLE 256 ]; 257 258 // Reasoning behind the exoneration, in HTML. 259 // MUST be sanitized before rendering in the browser. 260 string explanation_html = 5 [(google.api.field_behavior) = IMMUTABLE]; 261 262 // Hash of the variant. 263 // hex(sha256(sorted(''.join('%s:%s\n' for k, v in variant.items())))). 264 string variant_hash = 6 [(google.api.field_behavior) = IMMUTABLE]; 265 266 // Reasoning behind the exoneration, in machine-readable form. 267 // Used to assist downstream analyses, such as automatic bug-filing. 268 // This allow detection of e.g. critical tests failing in presubmit, 269 // even if they are being exonerated because they fail on other CLs. 270 ExonerationReason reason = 7 [(google.api.field_behavior) = IMMUTABLE]; 271 272 // Whether the test exoneration has been masked so that it includes only 273 // metadata. The metadata fields for a TestExoneration are: 274 // * name 275 // * test_id 276 // * exoneration_id 277 // * variant_hash 278 // * explanation_html 279 // * reason 280 // 281 // Output only. 282 bool is_masked = 8 [(google.api.field_behavior) = OUTPUT_ONLY]; 283} 284 285// Reason why a test variant was exonerated. 286enum ExonerationReason { 287 // Reason was not specified. 288 // Not to be used in actual test exonerations; serves as a default value for 289 // an unset field. 290 EXONERATION_REASON_UNSPECIFIED = 0; 291 292 // Similar unexpected results were observed on a mainline branch 293 // (i.e. against a build without unsubmitted changes applied). 294 // (For avoidance of doubt, this includes both flakily and 295 // deterministically occurring unexpected results.) 296 // Applies to unexpected results in presubmit/CQ runs only. 297 OCCURS_ON_MAINLINE = 1; 298 299 // Similar unexpected results were observed in presubmit run(s) for other, 300 // unrelated CL(s). (This is suggestive of the issue being present 301 // on mainline but is not confirmed as there are possible confounding 302 // factors, like how tests are run on CLs vs how tests are run on 303 // mainline branches.) 304 // Applies to unexpected results in presubmit/CQ runs only. 305 OCCURS_ON_OTHER_CLS = 2; 306 307 // The tests are not critical to the test subject (e.g. CL) passing. 308 // This could be because more data is being collected to determine if 309 // the tests are stable enough to be made critical (as is often the 310 // case for experimental test suites). 311 // If information exists indicating the tests are producing unexpected 312 // results, and the tests are not critical for that reason, 313 // prefer more specific reasons OCCURS_ON_MAINLINE or OCCURS_ON_OTHER_CLS. 314 NOT_CRITICAL = 3; 315 316 // The test result was an unexpected pass. (Note that such an exoneration is 317 // not automatically created for unexpected passes, unless the option is 318 // specified to ResultSink or the project manually creates one). 319 UNEXPECTED_PASS = 4; 320} 321