[resultdb] Add resultdb/proto/v1/test_result.proto

Modify "proto_in_dir" to import "//third_party/luci-go" in the
proto_library rule.

Bug: crbug.com/1124498
Change-Id: I2b149a8396efefc74319b687a8d68ddf1728c554
Reviewed-on: https://fuchsia-review.googlesource.com/c/third_party/luci-go/+/423954
Reviewed-by: Marc-Antoine Ruel <maruel@google.com>
diff --git a/REAMDME.fuchsia b/REAMDME.fuchsia
new file mode 100644
index 0000000..a7ac5a5
--- /dev/null
+++ b/REAMDME.fuchsia
@@ -0,0 +1,9 @@
+Source: https://chromium.googlesource.com/infra/luci/luci-go
+License: Apache 2.0
+
+Modifications:
+- Added README.fuchsia
+- Imported resultdb/proto/v1/test_result.proto
+- Setup proto_library rule for generating .pb.go code from .proto
+- Modified import rules from "go.chromium.org/luci/..." to relative paths from "//third_party/luci-go/..."
+- Remove dependency to "google/api/field_behavior.proto"
diff --git a/resultdb/proto/v1/BUILD.gn b/resultdb/proto/v1/BUILD.gn
index dad15ed..e72596d 100644
--- a/resultdb/proto/v1/BUILD.gn
+++ b/resultdb/proto/v1/BUILD.gn
@@ -7,6 +7,7 @@
 
 _protos = [
   "common",
+  "test_result",
 ]
 
 proto_library("resultdb_proto") {
@@ -14,7 +15,7 @@
   foreach(name, _protos) {
     sources += [ "${name}.proto" ]
   }
-
+  proto_in_dir = "//third_party/luci-go"
   import_dirs = [
     "//third_party/protobuf/src",
   ]
diff --git a/resultdb/proto/v1/test_result.proto b/resultdb/proto/v1/test_result.proto
new file mode 100644
index 0000000..edcbcb5
--- /dev/null
+++ b/resultdb/proto/v1/test_result.proto
@@ -0,0 +1,195 @@
+// Copyright 2019 The LUCI Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+
+package luci.resultdb.v1;
+
+import "google/protobuf/duration.proto";
+import "google/protobuf/timestamp.proto";
+
+import "resultdb/proto/v1/common.proto";
+
+option go_package = "go.chromium.org/luci/resultdb/proto/v1;resultpb";
+
+// A result of a functional test case.
+// Often a single test case is executed multiple times and has multiple results,
+// a single test suite has multiple test cases,
+// and the same test suite can be executed in different variants
+// (OS, GPU, compile flags, etc).
+//
+// This message does not specify the test id.
+// It should be available in the message that embeds this message.
+message TestResult {
+  // Can be used to refer to this test result, e.g. in ResultDB.GetTestResult
+  // RPC.
+  // Format:
+  // "invocations/{INVOCATION_ID}/tests/{URL_ESCAPED_TEST_ID}/results/{RESULT_ID}".
+  // where URL_ESCAPED_TEST_ID is test_id escaped with
+  // https://golang.org/pkg/net/url/#PathEscape See also https://aip.dev/122.
+  //
+  // Output only.
+  string name = 1;
+
+  // Test id, a unique identifier of the test in a LUCI project.
+  // Regex: ^[[::print::]]{1,256}$
+  //
+  // If two tests have a common test id prefix that ends with a
+  // non-alphanumeric character, they considered a part of a group. Examples:
+  // - "a/b/c"
+  // - "a/b/d"
+  // - "a/b/e:x"
+  // - "a/b/e:y"
+  // - "a/f"
+  // This defines the following groups:
+  // - All items belong to one group because of the common prefix "a/"
+  // - Within that group, the first 4 form a sub-group because of the common
+  //   prefix "a/b/"
+  // - Within that group, "a/b/e:x" and "a/b/e:y" form a sub-group because of
+  //   the common prefix "a/b/e:".
+  // This can be used in UI.
+  // LUCI does not interpret test ids in any other way.
+  string test_id = 2;
+
+  // Identifies a test result in a given invocation and test id.
+  // Regex: ^[a-z0-9\-_.]{1,32}$
+  string result_id = 3;
+
+  // Description of one specific way of running the test,
+  // e.g. a specific bucket, builder and a test suite.
+  Variant variant = 4;
+
+  // Whether the result of test case execution is expected.
+  // In a typical Chromium CL, 99%+ of test results are expected.
+  // Users are typically interested only in the unexpected results.
+  //
+  // An unexpected result != test case failure. There are test cases that are
+  // expected to fail/skip/crash. The test harness compares the actual status
+  // with the expected one(s) and this field is the result of the comparison.
+  bool expected = 5;
+
+  // Machine-readable status of the test case.
+  // MUST NOT be STATUS_UNSPECIFIED.
+  TestStatus status = 6;
+
+  // Human-readable explanation of the result, in HTML.
+  // MUST be sanitized before rendering in the browser.
+  //
+  // The size of the summary must be equal to or smaller than 4096 bytes in
+  // UTF-8.
+  string summary_html = 7;
+
+  // The point in time when the test case started to execute.
+  google.protobuf.Timestamp start_time = 8;
+
+  // Duration of the test case execution.
+  // MUST be equal to or greater than 0.
+  google.protobuf.Duration duration = 9;
+
+  // Metadata for this test result.
+  // It might describe this particular execution or the test case.
+  repeated StringPair tags = 10;
+
+  // Where the test is defined, e.g. the file name.
+  TestLocation test_location = 11;
+
+  // Hash of the variant.
+  // hex(sha256(sorted(''.join('%s:%s\n' for k, v in variant.items())))).
+  string variant_hash = 12;
+}
+
+// Location of the test definition.
+message TestLocation {
+  reserved 1; // We might want to add repo URL later.
+
+  // Name of the file where the test is defined.
+  // For files in a repository, must start with "//"
+  // Example: "//components/payments/core/payment_request_data_util_unittest.cc"
+  // Max length: 512.
+  // SHOULD not use backslashes.
+  string file_name = 2;
+
+  // One-based line number where the test is defined.
+  int32 line = 3;
+}
+
+// Machine-readable status of a test result.
+enum TestStatus {
+  // Status was not specified.
+  // Not to be used in actual test results; serves as a default value for an
+  // unset field.
+  STATUS_UNSPECIFIED = 0;
+
+  // The test case has passed.
+  PASS = 1;
+
+  // The test case has failed.
+  // Suggests that the code under test is incorrect, but it is also possible
+  // that the test is incorrect or it is a flake.
+  FAIL = 2;
+
+  // The test case has crashed during execution.
+  // The outcome is inconclusive: the code under test might or might not be
+  // correct, but the test+code is incorrect.
+  CRASH = 3;
+
+  // The test case has started, but was aborted before finishing.
+  // A common reason: timeout.
+  ABORT = 4;
+
+  // The test case did not execute.
+  // Examples:
+  // - The execution of the collection of test cases, such as a test
+  //   binary, was aborted prematurely and execution of some test cases was
+  //   skipped.
+  // - The test harness configuration specified that the test case MUST be
+  //   skipped.
+  SKIP = 5;
+}
+
+// Indicates the test subject (e.g. a CL) is absolved from blame
+// for an unexpected result of a test variant.
+// For example, the test variant fails both with and without CL, so it is not
+// CL's fault.
+message TestExoneration {
+  // Can be used to refer to this test exoneration, e.g. in
+  // ResultDB.GetTestExoneration RPC.
+  // Format:
+  // invocations/{INVOCATION_ID}/tests/{URL_ESCAPED_TEST_ID}/exonerations/{EXONERATION_ID}.
+  // URL_ESCAPED_TEST_ID is test_variant.test_id escaped with
+  // https://golang.org/pkg/net/url/#PathEscape See also https://aip.dev/122.
+  //
+  // Output only.
+  string name = 1;
+
+  // Test identifier, see TestResult.test_id.
+  string test_id = 2;
+
+  // Description of the variant of the test, see Variant type.
+  // Unlike TestResult.extra_variant_pairs, this one must be a full definition
+  // of the variant, i.e. it is not combined with Invocation.base_test_variant.
+  Variant variant = 3;
+
+  // Identifies an exoneration in a given invocation and test id.
+  // It is server-generated.
+  string exoneration_id = 4;
+
+  // Reasoning behind the exoneration, in HTML.
+  // MUST be sanitized before rendering in the browser.
+  string explanation_html = 5;
+
+  // Hash of the variant.
+  // hex(sha256(sorted(''.join('%s:%s\n' for k, v in variant.items())))).
+  string variant_hash = 6;
+}
diff --git a/resultdb/sink/proto/v1/BUILD.gn b/resultdb/sink/proto/v1/BUILD.gn
index ae57bca..59858f8 100644
--- a/resultdb/sink/proto/v1/BUILD.gn
+++ b/resultdb/sink/proto/v1/BUILD.gn
@@ -15,10 +15,9 @@
   foreach(name, _protos) {
     sources += [ "${name}.proto" ]
   }
-
+  proto_in_dir = "//third_party/luci-go"
   import_dirs = [
     "//third_party/protobuf/src",
-    "//third_party/luci-go/resultdb/proto/v1"
   ]
   generate_python = false
   generate_cc = false
diff --git a/resultdb/sink/proto/v1/sink.proto b/resultdb/sink/proto/v1/sink.proto
index a2e5c24..d446f00 100644
--- a/resultdb/sink/proto/v1/sink.proto
+++ b/resultdb/sink/proto/v1/sink.proto
@@ -16,7 +16,7 @@
 
 package luci.resultsink.v1;
 
-import "test_result.proto";
+import "resultdb/sink/proto/v1/test_result.proto";
 
 option go_package = "go.chromium.org/luci/resultdb/sink/proto/v1;sinkpb";
 
diff --git a/resultdb/sink/proto/v1/test_result.proto b/resultdb/sink/proto/v1/test_result.proto
index 45a6a82..4d1ef3f 100644
--- a/resultdb/sink/proto/v1/test_result.proto
+++ b/resultdb/sink/proto/v1/test_result.proto
@@ -19,111 +19,48 @@
 
 import "google/protobuf/duration.proto";
 import "google/protobuf/timestamp.proto";
-import "common.proto";
+
+import "resultdb/proto/v1/common.proto";
+import "resultdb/proto/v1/test_result.proto";
 
 option go_package = "go.chromium.org/luci/resultdb/sink/proto/v1;sinkpb";
 
-// A result of a functional test case.
-// Often a single test case is executed multiple times and has multiple results,
-// a single test suite has multiple test cases,
-// and the same test suite can be executed in different variants
-// (OS, GPU, compile flags, etc).
-//
-// This message does not specify the test id.
-// It should be available in the message that embeds this message.
+// A local equivalent of luci.resultdb.TestResult message
+// in ../../v1/test_result.proto.
+// See its comments for details.
 message TestResult {
-  // Test id, a unique identifier of the test in a LUCI project.
-  // Regex: ^[[::print::]]{1,256}$
-  //
-  // If two tests have a common test id prefix that ends with a
-  // non-alphanumeric character, they considered a part of a group. Examples:
-  // - "a/b/c"
-  // - "a/b/d"
-  // - "a/b/e:x"
-  // - "a/b/e:y"
-  // - "a/f"
-  // This defines the following groups:
-  // - All items belong to one group because of the common prefix "a/"
-  // - Within that group, the first 4 form a sub-group because of the common
-  //   prefix "a/b/"
-  // - Within that group, "a/b/e:x" and "a/b/e:y" form a sub-group because of
-  //   the common prefix "a/b/e:".
-  // This can be used in UI.
-  // LUCI does not interpret test ids in any other way.
+  // Equivalent of luci.resultdb.v1.TestResult.TestId.
   string test_id = 1;
 
-  // Identifies a test result in a given invocation and test id.
-  // Regex: ^[[:ascii:]]{1,32}$
+  // Equivalent of luci.resultdb.v1.TestResult.result_id.
+  //
+  // If omitted, a random, unique ID is generated..
   string result_id = 2;
 
-  // Whether the result of test case execution is expected.
-  // In a typical Chromium CL, 99%+ of test results are expected.
-  // Users are typically interested only in the unexpected results.
-  //
-  // An unexpected result != test case failure. There are test cases that are
-  // expected to fail/skip/crash. The test harness compares the actual status
-  // with the expected one(s) and this field is the result of the comparison.
+  // Equivalent of luci.resultdb.v1.TestResult.expected.
   bool expected = 3;
 
-  // Machine-readable status of the test case.
-  // MUST NOT be STATUS_UNSPECIFIED.
-  TestStatus status = 4;
+  // Equivalent of luci.resultdb.v1.TestResult.status.
+  luci.resultdb.v1.TestStatus status = 4;
 
-  // Human-readable explanation of the result, in HTML.
-  // MUST be sanitized before rendering in the browser.
-  //
-  // The size of the summary must be equal to or smaller than 4096 bytes in
-  // UTF-8.
+  // Equivalent of luci.resultdb.v1.TestResult.summary_html.
   string summary_html = 5;
 
-  // The point in time when the test case started to execute.
+  // Equivalent of luci.resultdb.v1.TestResult.start_time.
   google.protobuf.Timestamp start_time = 6;
 
-  // Duration of the test case execution.
-  // MUST be equal to or greater than 0.
+  // Equivalent of luci.resultdb.v1.TestResult.duration.
   google.protobuf.Duration duration = 7;
 
-  // Metadata for this test result.
-  // It might describe this particular execution or the test case.
+  // Equivalent of luci.resultdb.v1.TestResult.tags.
   repeated luci.resultdb.v1.StringPair tags = 8;
 
   // Artifacts to upload and associate with this test result.
   // The map key is an artifact id.
   map<string, Artifact> artifacts = 9;
-}
 
-// Machine-readable status of a test result.
-enum TestStatus {
-  // Status was not specified.
-  // Not to be used in actual test results; serves as a default value for an
-  // unset field.
-  STATUS_UNSPECIFIED = 0;
-
-  // The test case has passed.
-  PASS = 1;
-
-  // The test case has failed.
-  // Suggests that the code under test is incorrect, but it is also possible
-  // that the test is incorrect or it is a flake.
-  FAIL = 2;
-
-  // The test case has crashed during execution.
-  // The outcome is inconclusive: the code under test might or might not be
-  // correct, but the test+code is incorrect.
-  CRASH = 3;
-
-  // The test case has started, but was aborted before finishing.
-  // A common reason: timeout.
-  ABORT = 4;
-
-  // The test case did not execute.
-  // Examples:
-  // - The execution of the collection of test cases, such as a test
-  //   binary, was aborted prematurely and execution of some test cases was
-  //   skipped.
-  // - The test harness configuration specified that the test case MUST be
-  //   skipped.
-  SKIP = 5;
+  // Equivalent of luci.resultdb.v1.TestResult.test_location.
+  luci.resultdb.v1.TestLocation test_location = 10;
 }
 
 // A local equivalent of luci.resultdb.Artifact message
@@ -173,3 +110,38 @@
   // Format of the file.
   Format format = 2;
 }
+
+// TODO(yuanzhi) Delete after http://fxr/425525 is submitted. This is kept around to not break CI
+// Machine-readable status of a test result.
+enum TestStatus {
+  // Status was not specified.
+  // Not to be used in actual test results; serves as a default value for an
+  // unset field.
+  STATUS_UNSPECIFIED = 0;
+
+  // The test case has passed.
+  PASS = 1;
+
+  // The test case has failed.
+  // Suggests that the code under test is incorrect, but it is also possible
+  // that the test is incorrect or it is a flake.
+  FAIL = 2;
+
+  // The test case has crashed during execution.
+  // The outcome is inconclusive: the code under test might or might not be
+  // correct, but the test+code is incorrect.
+  CRASH = 3;
+
+  // The test case has started, but was aborted before finishing.
+  // A common reason: timeout.
+  ABORT = 4;
+
+  // The test case did not execute.
+  // Examples:
+  // - The execution of the collection of test cases, such as a test
+  //   binary, was aborted prematurely and execution of some test cases was
+  //   skipped.
+  // - The test harness configuration specified that the test case MUST be
+  //   skipped.
+  SKIP = 5;
+}