xref: /aosp_15_r20/external/cronet/testing/perf/luci_test_result.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2019 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "testing/perf/luci_test_result.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <utility>
8*6777b538SAndroid Build Coastguard Worker 
9*6777b538SAndroid Build Coastguard Worker #include "base/check.h"
10*6777b538SAndroid Build Coastguard Worker #include "base/files/file_util.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/i18n/time_formatting.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/json/json_writer.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/values.h"
16*6777b538SAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
17*6777b538SAndroid Build Coastguard Worker 
18*6777b538SAndroid Build Coastguard Worker namespace perf_test {
19*6777b538SAndroid Build Coastguard Worker 
20*6777b538SAndroid Build Coastguard Worker namespace {
21*6777b538SAndroid Build Coastguard Worker 
22*6777b538SAndroid Build Coastguard Worker constexpr char kKeyFilePath[] = "filePath";
23*6777b538SAndroid Build Coastguard Worker constexpr char kKeyContents[] = "contents";
24*6777b538SAndroid Build Coastguard Worker constexpr char kKeyContentType[] = "contentType";
25*6777b538SAndroid Build Coastguard Worker constexpr char kKeyTestResult[] = "testResult";
26*6777b538SAndroid Build Coastguard Worker constexpr char kKeyTestPath[] = "testPath";
27*6777b538SAndroid Build Coastguard Worker constexpr char kKeyVariant[] = "variant";
28*6777b538SAndroid Build Coastguard Worker constexpr char kKeyStatus[] = "status";
29*6777b538SAndroid Build Coastguard Worker constexpr char kKeyExpected[] = "expected";
30*6777b538SAndroid Build Coastguard Worker constexpr char kKeyStartTime[] = "startTime";
31*6777b538SAndroid Build Coastguard Worker constexpr char kKeyRunDuration[] = "runDuration";
32*6777b538SAndroid Build Coastguard Worker constexpr char kKeyOutputArtifacts[] = "outputArtifacts";
33*6777b538SAndroid Build Coastguard Worker constexpr char kKeyTags[] = "tags";
34*6777b538SAndroid Build Coastguard Worker constexpr char kKeyKey[] = "key";
35*6777b538SAndroid Build Coastguard Worker constexpr char kKeyValue[] = "value";
36*6777b538SAndroid Build Coastguard Worker 
ToString(LuciTestResult::Status status)37*6777b538SAndroid Build Coastguard Worker std::string ToString(LuciTestResult::Status status) {
38*6777b538SAndroid Build Coastguard Worker   using Status = LuciTestResult::Status;
39*6777b538SAndroid Build Coastguard Worker   switch (status) {
40*6777b538SAndroid Build Coastguard Worker     case Status::kUnspecified:
41*6777b538SAndroid Build Coastguard Worker       return "UNSPECIFIED";
42*6777b538SAndroid Build Coastguard Worker     case Status::kPass:
43*6777b538SAndroid Build Coastguard Worker       return "PASS";
44*6777b538SAndroid Build Coastguard Worker     case Status::kFail:
45*6777b538SAndroid Build Coastguard Worker       return "FAIL";
46*6777b538SAndroid Build Coastguard Worker     case Status::kCrash:
47*6777b538SAndroid Build Coastguard Worker       return "CRASH";
48*6777b538SAndroid Build Coastguard Worker     case Status::kAbort:
49*6777b538SAndroid Build Coastguard Worker       return "ABORT";
50*6777b538SAndroid Build Coastguard Worker     case Status::kSkip:
51*6777b538SAndroid Build Coastguard Worker       return "SKIP";
52*6777b538SAndroid Build Coastguard Worker   }
53*6777b538SAndroid Build Coastguard Worker }
54*6777b538SAndroid Build Coastguard Worker 
ToValue(const LuciTestResult::Artifact & artifact)55*6777b538SAndroid Build Coastguard Worker base::Value ToValue(const LuciTestResult::Artifact& artifact) {
56*6777b538SAndroid Build Coastguard Worker   // One and only one of the two optional fields must have value.
57*6777b538SAndroid Build Coastguard Worker   DCHECK(artifact.file_path.has_value() != artifact.contents.has_value());
58*6777b538SAndroid Build Coastguard Worker 
59*6777b538SAndroid Build Coastguard Worker   base::Value::Dict dict;
60*6777b538SAndroid Build Coastguard Worker 
61*6777b538SAndroid Build Coastguard Worker   if (artifact.file_path.has_value()) {
62*6777b538SAndroid Build Coastguard Worker     dict.Set(kKeyFilePath, artifact.file_path->AsUTF8Unsafe());
63*6777b538SAndroid Build Coastguard Worker   } else {
64*6777b538SAndroid Build Coastguard Worker     DCHECK(artifact.contents.has_value());
65*6777b538SAndroid Build Coastguard Worker     dict.Set(kKeyContents, artifact.contents.value());
66*6777b538SAndroid Build Coastguard Worker   }
67*6777b538SAndroid Build Coastguard Worker 
68*6777b538SAndroid Build Coastguard Worker   dict.Set(kKeyContentType, artifact.content_type);
69*6777b538SAndroid Build Coastguard Worker   return base::Value(std::move(dict));
70*6777b538SAndroid Build Coastguard Worker }
71*6777b538SAndroid Build Coastguard Worker 
ToValue(const LuciTestResult & result)72*6777b538SAndroid Build Coastguard Worker base::Value ToValue(const LuciTestResult& result) {
73*6777b538SAndroid Build Coastguard Worker   base::Value::Dict test_report;
74*6777b538SAndroid Build Coastguard Worker 
75*6777b538SAndroid Build Coastguard Worker   base::Value::Dict* test_result = test_report.EnsureDict(kKeyTestResult);
76*6777b538SAndroid Build Coastguard Worker   test_result->Set(kKeyTestPath, result.test_path());
77*6777b538SAndroid Build Coastguard Worker 
78*6777b538SAndroid Build Coastguard Worker   if (!result.extra_variant_pairs().empty()) {
79*6777b538SAndroid Build Coastguard Worker     base::Value::Dict* variant_dict = test_result->EnsureDict(kKeyVariant);
80*6777b538SAndroid Build Coastguard Worker     for (const auto& pair : result.extra_variant_pairs())
81*6777b538SAndroid Build Coastguard Worker       variant_dict->Set(pair.first, pair.second);
82*6777b538SAndroid Build Coastguard Worker   }
83*6777b538SAndroid Build Coastguard Worker 
84*6777b538SAndroid Build Coastguard Worker   test_result->Set(kKeyStatus, ToString(result.status()));
85*6777b538SAndroid Build Coastguard Worker   test_result->Set(kKeyExpected, result.is_expected());
86*6777b538SAndroid Build Coastguard Worker 
87*6777b538SAndroid Build Coastguard Worker   if (!result.start_time().is_null()) {
88*6777b538SAndroid Build Coastguard Worker     test_result->Set(kKeyStartTime,
89*6777b538SAndroid Build Coastguard Worker                      base::TimeFormatAsIso8601(result.start_time()));
90*6777b538SAndroid Build Coastguard Worker   }
91*6777b538SAndroid Build Coastguard Worker   if (!result.duration().is_zero()) {
92*6777b538SAndroid Build Coastguard Worker     test_result->Set(
93*6777b538SAndroid Build Coastguard Worker         kKeyRunDuration,
94*6777b538SAndroid Build Coastguard Worker         base::StringPrintf("%.2fs", result.duration().InSecondsF()));
95*6777b538SAndroid Build Coastguard Worker   }
96*6777b538SAndroid Build Coastguard Worker 
97*6777b538SAndroid Build Coastguard Worker   if (!result.output_artifacts().empty()) {
98*6777b538SAndroid Build Coastguard Worker     base::Value::Dict* artifacts_dict =
99*6777b538SAndroid Build Coastguard Worker         test_result->EnsureDict(kKeyOutputArtifacts);
100*6777b538SAndroid Build Coastguard Worker     for (const auto& pair : result.output_artifacts())
101*6777b538SAndroid Build Coastguard Worker       artifacts_dict->Set(pair.first, ToValue(pair.second));
102*6777b538SAndroid Build Coastguard Worker   }
103*6777b538SAndroid Build Coastguard Worker 
104*6777b538SAndroid Build Coastguard Worker   if (!result.tags().empty()) {
105*6777b538SAndroid Build Coastguard Worker     base::Value::List* tags_list = test_result->EnsureList(kKeyTags);
106*6777b538SAndroid Build Coastguard Worker     for (const auto& tag : result.tags()) {
107*6777b538SAndroid Build Coastguard Worker       base::Value::Dict tag_dict;
108*6777b538SAndroid Build Coastguard Worker       tag_dict.Set(kKeyKey, tag.key);
109*6777b538SAndroid Build Coastguard Worker       tag_dict.Set(kKeyValue, tag.value);
110*6777b538SAndroid Build Coastguard Worker       tags_list->Append(std::move(tag_dict));
111*6777b538SAndroid Build Coastguard Worker     }
112*6777b538SAndroid Build Coastguard Worker   }
113*6777b538SAndroid Build Coastguard Worker 
114*6777b538SAndroid Build Coastguard Worker   return base::Value(std::move(test_report));
115*6777b538SAndroid Build Coastguard Worker }
116*6777b538SAndroid Build Coastguard Worker 
ToJson(const LuciTestResult & result)117*6777b538SAndroid Build Coastguard Worker std::string ToJson(const LuciTestResult& result) {
118*6777b538SAndroid Build Coastguard Worker   std::string json;
119*6777b538SAndroid Build Coastguard Worker   CHECK(base::JSONWriter::Write(ToValue(result), &json));
120*6777b538SAndroid Build Coastguard Worker   return json;
121*6777b538SAndroid Build Coastguard Worker }
122*6777b538SAndroid Build Coastguard Worker 
123*6777b538SAndroid Build Coastguard Worker }  // namespace
124*6777b538SAndroid Build Coastguard Worker 
125*6777b538SAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
126*6777b538SAndroid Build Coastguard Worker // LuciTestResult::Artifact
127*6777b538SAndroid Build Coastguard Worker 
128*6777b538SAndroid Build Coastguard Worker LuciTestResult::Artifact::Artifact() = default;
129*6777b538SAndroid Build Coastguard Worker LuciTestResult::Artifact::Artifact(const Artifact& other) = default;
Artifact(const base::FilePath file_path,const std::string & content_type)130*6777b538SAndroid Build Coastguard Worker LuciTestResult::Artifact::Artifact(const base::FilePath file_path,
131*6777b538SAndroid Build Coastguard Worker                                    const std::string& content_type)
132*6777b538SAndroid Build Coastguard Worker     : file_path(file_path), content_type(content_type) {}
Artifact(const std::string & contents,const std::string & content_type)133*6777b538SAndroid Build Coastguard Worker LuciTestResult::Artifact::Artifact(const std::string& contents,
134*6777b538SAndroid Build Coastguard Worker                                    const std::string& content_type)
135*6777b538SAndroid Build Coastguard Worker     : contents(contents), content_type(content_type) {}
136*6777b538SAndroid Build Coastguard Worker LuciTestResult::Artifact::~Artifact() = default;
137*6777b538SAndroid Build Coastguard Worker 
138*6777b538SAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
139*6777b538SAndroid Build Coastguard Worker // LuciTestResult
140*6777b538SAndroid Build Coastguard Worker 
141*6777b538SAndroid Build Coastguard Worker LuciTestResult::LuciTestResult() = default;
142*6777b538SAndroid Build Coastguard Worker LuciTestResult::LuciTestResult(const LuciTestResult& other) = default;
143*6777b538SAndroid Build Coastguard Worker LuciTestResult::LuciTestResult(LuciTestResult&& other) = default;
144*6777b538SAndroid Build Coastguard Worker LuciTestResult::~LuciTestResult() = default;
145*6777b538SAndroid Build Coastguard Worker 
146*6777b538SAndroid Build Coastguard Worker // static
CreateForGTest()147*6777b538SAndroid Build Coastguard Worker LuciTestResult LuciTestResult::CreateForGTest() {
148*6777b538SAndroid Build Coastguard Worker   LuciTestResult result;
149*6777b538SAndroid Build Coastguard Worker 
150*6777b538SAndroid Build Coastguard Worker   const testing::TestInfo* const test_info =
151*6777b538SAndroid Build Coastguard Worker       testing::UnitTest::GetInstance()->current_test_info();
152*6777b538SAndroid Build Coastguard Worker 
153*6777b538SAndroid Build Coastguard Worker   std::string test_case_name = test_info->name();
154*6777b538SAndroid Build Coastguard Worker   std::string param_index;
155*6777b538SAndroid Build Coastguard Worker 
156*6777b538SAndroid Build Coastguard Worker   // If there is a "/", extract |param_index| after it and strip it from
157*6777b538SAndroid Build Coastguard Worker   // |test_case_name|.
158*6777b538SAndroid Build Coastguard Worker   auto pos = test_case_name.rfind('/');
159*6777b538SAndroid Build Coastguard Worker   if (pos != std::string::npos) {
160*6777b538SAndroid Build Coastguard Worker     param_index = test_case_name.substr(pos + 1);
161*6777b538SAndroid Build Coastguard Worker     test_case_name.resize(pos);
162*6777b538SAndroid Build Coastguard Worker   }
163*6777b538SAndroid Build Coastguard Worker 
164*6777b538SAndroid Build Coastguard Worker   result.set_test_path(base::StringPrintf("%s.%s", test_info->test_suite_name(),
165*6777b538SAndroid Build Coastguard Worker                                           test_case_name.c_str()));
166*6777b538SAndroid Build Coastguard Worker 
167*6777b538SAndroid Build Coastguard Worker   if (test_info->type_param())
168*6777b538SAndroid Build Coastguard Worker     result.AddVariant("param/instantiation", test_info->type_param());
169*6777b538SAndroid Build Coastguard Worker 
170*6777b538SAndroid Build Coastguard Worker   if (!param_index.empty())
171*6777b538SAndroid Build Coastguard Worker     result.AddVariant("param/index", param_index);
172*6777b538SAndroid Build Coastguard Worker 
173*6777b538SAndroid Build Coastguard Worker   result.set_status(test_info->result()->Passed()
174*6777b538SAndroid Build Coastguard Worker                         ? LuciTestResult::Status::kPass
175*6777b538SAndroid Build Coastguard Worker                         : LuciTestResult::Status::kFail);
176*6777b538SAndroid Build Coastguard Worker   // Assumes that the expectation is test passing.
177*6777b538SAndroid Build Coastguard Worker   result.set_is_expected(result.status() == LuciTestResult::Status::kPass);
178*6777b538SAndroid Build Coastguard Worker 
179*6777b538SAndroid Build Coastguard Worker   // Start timestamp and duration is not set before the test run finishes,
180*6777b538SAndroid Build Coastguard Worker   // e.g. when called from PerformanceTest::TearDownOnMainThread.
181*6777b538SAndroid Build Coastguard Worker   if (test_info->result()->start_timestamp()) {
182*6777b538SAndroid Build Coastguard Worker     result.set_start_time(base::Time::FromTimeT(
183*6777b538SAndroid Build Coastguard Worker         static_cast<time_t>(test_info->result()->start_timestamp() / 1000)));
184*6777b538SAndroid Build Coastguard Worker     result.set_duration(
185*6777b538SAndroid Build Coastguard Worker         base::Milliseconds(test_info->result()->elapsed_time()));
186*6777b538SAndroid Build Coastguard Worker   }
187*6777b538SAndroid Build Coastguard Worker 
188*6777b538SAndroid Build Coastguard Worker   return result;
189*6777b538SAndroid Build Coastguard Worker }
190*6777b538SAndroid Build Coastguard Worker 
AddVariant(const std::string & key,const std::string & value)191*6777b538SAndroid Build Coastguard Worker void LuciTestResult::AddVariant(const std::string& key,
192*6777b538SAndroid Build Coastguard Worker                                 const std::string& value) {
193*6777b538SAndroid Build Coastguard Worker   auto result = extra_variant_pairs_.insert({key, value});
194*6777b538SAndroid Build Coastguard Worker   DCHECK(result.second);
195*6777b538SAndroid Build Coastguard Worker }
196*6777b538SAndroid Build Coastguard Worker 
AddOutputArtifactFile(const std::string & artifact_name,const base::FilePath & file_path,const std::string & content_type)197*6777b538SAndroid Build Coastguard Worker void LuciTestResult::AddOutputArtifactFile(const std::string& artifact_name,
198*6777b538SAndroid Build Coastguard Worker                                            const base::FilePath& file_path,
199*6777b538SAndroid Build Coastguard Worker                                            const std::string& content_type) {
200*6777b538SAndroid Build Coastguard Worker   Artifact artifact(file_path, content_type);
201*6777b538SAndroid Build Coastguard Worker   auto insert_result = output_artifacts_.insert(
202*6777b538SAndroid Build Coastguard Worker       std::make_pair(artifact_name, std::move(artifact)));
203*6777b538SAndroid Build Coastguard Worker   DCHECK(insert_result.second);
204*6777b538SAndroid Build Coastguard Worker }
205*6777b538SAndroid Build Coastguard Worker 
AddOutputArtifactContents(const std::string & artifact_name,const std::string & contents,const std::string & content_type)206*6777b538SAndroid Build Coastguard Worker void LuciTestResult::AddOutputArtifactContents(
207*6777b538SAndroid Build Coastguard Worker     const std::string& artifact_name,
208*6777b538SAndroid Build Coastguard Worker     const std::string& contents,
209*6777b538SAndroid Build Coastguard Worker     const std::string& content_type) {
210*6777b538SAndroid Build Coastguard Worker   Artifact artifact(contents, content_type);
211*6777b538SAndroid Build Coastguard Worker   auto insert_result = output_artifacts_.insert(
212*6777b538SAndroid Build Coastguard Worker       std::make_pair(artifact_name, std::move(artifact)));
213*6777b538SAndroid Build Coastguard Worker   DCHECK(insert_result.second);
214*6777b538SAndroid Build Coastguard Worker }
215*6777b538SAndroid Build Coastguard Worker 
AddTag(const std::string & key,const std::string & value)216*6777b538SAndroid Build Coastguard Worker void LuciTestResult::AddTag(const std::string& key, const std::string& value) {
217*6777b538SAndroid Build Coastguard Worker   tags_.emplace_back(Tag{key, value});
218*6777b538SAndroid Build Coastguard Worker }
219*6777b538SAndroid Build Coastguard Worker 
WriteToFile(const base::FilePath & result_file) const220*6777b538SAndroid Build Coastguard Worker void LuciTestResult::WriteToFile(const base::FilePath& result_file) const {
221*6777b538SAndroid Build Coastguard Worker   const std::string json = ToJson(*this);
222*6777b538SAndroid Build Coastguard Worker   const int json_size = json.size();
223*6777b538SAndroid Build Coastguard Worker   CHECK(WriteFile(result_file, json.data(), json_size) == json_size);
224*6777b538SAndroid Build Coastguard Worker }
225*6777b538SAndroid Build Coastguard Worker 
226*6777b538SAndroid Build Coastguard Worker }  // namespace perf_test
227