1 /*
2  * Copyright (C) 2021 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 
17 #include "odr_metrics_record.h"
18 
19 #include <string.h>
20 
21 #include <fstream>
22 
23 #include "android-base/result-gmock.h"
24 #include "android-base/stringprintf.h"
25 #include "base/common_art_test.h"
26 
27 namespace art {
28 namespace odrefresh {
29 
30 class OdrMetricsRecordTest : public CommonArtTest {
31  protected:
WriteFile()32   void WriteFile() {
33     std::ofstream ofs(file_path_);
34 
35     ofs << "<odrefresh_metrics>";
36     ofs << metrics_version_;
37     ofs << "<art_apex_version>81966764218039518</art_apex_version>";
38     ofs << "<trigger>16909060</trigger>";
39     ofs << "<stage_reached>286397204</stage_reached>";
40     ofs << status_;
41     ofs << "<cache_space_free_start_mib>1633837924</cache_space_free_start_mib>";
42     ofs << "<cache_space_free_end_mib>1903326068</cache_space_free_end_mib>";
43     ofs << "<primary_bcp_compilation_millis>825373492</primary_bcp_compilation_millis>";
44     ofs << "<secondary_bcp_compilation_millis>1094861636</secondary_bcp_compilation_millis>";
45     ofs << "<system_server_compilation_millis>1364349780</system_server_compilation_millis>";
46     ofs << primary_bcp_dex2oat_result_;
47     ofs << secondary_bcp_dex2oat_result_;
48     ofs << system_server_dex2oat_result_;
49     ofs << "</odrefresh_metrics>";
50 
51     ofs.close();
52   }
53 
SetUp()54   void SetUp() override {
55     CommonArtTest::SetUp();
56     scratch_dir_ = std::make_unique<ScratchDir>(/*keep_files=*/false);
57     file_path_ = scratch_dir_->GetPath() + "/metrics-record.xml";
58   }
59 
TearDown()60   void TearDown() override { scratch_dir_.reset(); }
61 
62   std::unique_ptr<ScratchDir> scratch_dir_;
63   std::string file_path_;
64   std::string metrics_version_ = android::base::StringPrintf(
65       "<odrefresh_metrics_version>%d</odrefresh_metrics_version>", kOdrefreshMetricsVersion);
66   std::string status_ = "<status>30</status>";
67   std::string primary_bcp_dex2oat_result_ =
68       R"(<primary_bcp_dex2oat_result status="1" exit-code="-1" signal="0" />)";
69   std::string secondary_bcp_dex2oat_result_ =
70       R"(<secondary_bcp_dex2oat_result status="2" exit-code="15" signal="0" />)";
71   std::string system_server_dex2oat_result_ =
72       R"(<system_server_dex2oat_result status="3" exit-code="-1" signal="9" />)";
73 };
74 
75 using android::base::testing::HasError;
76 using android::base::testing::Ok;
77 using android::base::testing::WithMessage;
78 
TEST_F(OdrMetricsRecordTest,HappyPath)79 TEST_F(OdrMetricsRecordTest, HappyPath) {
80   OdrMetricsRecord expected{};
81   expected.odrefresh_metrics_version = art::odrefresh::kOdrefreshMetricsVersion;
82   expected.art_apex_version = 0x01233456'789abcde;
83   expected.trigger = 0x01020304;
84   expected.stage_reached = 0x11121314;
85   expected.status = 0x21222324;
86   expected.cache_space_free_start_mib = 0x61626364;
87   expected.cache_space_free_end_mib = 0x71727374;
88   expected.primary_bcp_compilation_millis = 0x31323334;
89   expected.secondary_bcp_compilation_millis = 0x41424344;
90   expected.system_server_compilation_millis = 0x51525354;
91   expected.primary_bcp_dex2oat_result = OdrMetricsRecord::Dex2OatExecResult(1, -1, 0);
92   expected.secondary_bcp_dex2oat_result = OdrMetricsRecord::Dex2OatExecResult(2, 15, 0);
93   expected.system_server_dex2oat_result = OdrMetricsRecord::Dex2OatExecResult(3, -1, 9);
94   expected.primary_bcp_compilation_type = 0x82837192;
95   expected.secondary_bcp_compilation_type = 0x91827312;
96 
97   ASSERT_THAT(expected.WriteToFile(file_path_), Ok());
98 
99   OdrMetricsRecord actual{};
100   ASSERT_THAT(actual.ReadFromFile(file_path_), Ok());
101 
102   ASSERT_EQ(expected.odrefresh_metrics_version, actual.odrefresh_metrics_version);
103   ASSERT_EQ(expected.art_apex_version, actual.art_apex_version);
104   ASSERT_EQ(expected.trigger, actual.trigger);
105   ASSERT_EQ(expected.stage_reached, actual.stage_reached);
106   ASSERT_EQ(expected.status, actual.status);
107   ASSERT_EQ(expected.cache_space_free_start_mib, actual.cache_space_free_start_mib);
108   ASSERT_EQ(expected.cache_space_free_end_mib, actual.cache_space_free_end_mib);
109   ASSERT_EQ(expected.primary_bcp_compilation_millis, actual.primary_bcp_compilation_millis);
110   ASSERT_EQ(expected.secondary_bcp_compilation_millis, actual.secondary_bcp_compilation_millis);
111   ASSERT_EQ(expected.system_server_compilation_millis, actual.system_server_compilation_millis);
112   ASSERT_EQ(expected.primary_bcp_dex2oat_result.status, actual.primary_bcp_dex2oat_result.status);
113   ASSERT_EQ(expected.primary_bcp_dex2oat_result.exit_code,
114             actual.primary_bcp_dex2oat_result.exit_code);
115   ASSERT_EQ(expected.primary_bcp_dex2oat_result.signal, actual.primary_bcp_dex2oat_result.signal);
116   ASSERT_EQ(expected.secondary_bcp_dex2oat_result.status,
117             actual.secondary_bcp_dex2oat_result.status);
118   ASSERT_EQ(expected.secondary_bcp_dex2oat_result.exit_code,
119             actual.secondary_bcp_dex2oat_result.exit_code);
120   ASSERT_EQ(expected.secondary_bcp_dex2oat_result.signal,
121             actual.secondary_bcp_dex2oat_result.signal);
122   ASSERT_EQ(expected.system_server_dex2oat_result.status,
123             actual.system_server_dex2oat_result.status);
124   ASSERT_EQ(expected.system_server_dex2oat_result.exit_code,
125             actual.system_server_dex2oat_result.exit_code);
126   ASSERT_EQ(expected.system_server_dex2oat_result.signal,
127             actual.system_server_dex2oat_result.signal);
128   ASSERT_EQ(expected.primary_bcp_compilation_type, actual.primary_bcp_compilation_type);
129   ASSERT_EQ(expected.secondary_bcp_compilation_type, actual.secondary_bcp_compilation_type);
130   ASSERT_EQ(0, memcmp(&expected, &actual, sizeof(expected)));
131 }
132 
TEST_F(OdrMetricsRecordTest,EmptyInput)133 TEST_F(OdrMetricsRecordTest, EmptyInput) {
134   OdrMetricsRecord record{};
135   ASSERT_THAT(record.ReadFromFile(file_path_), testing::Not(Ok()));
136 }
137 
TEST_F(OdrMetricsRecordTest,UnexpectedInput)138 TEST_F(OdrMetricsRecordTest, UnexpectedInput) {
139   std::ofstream ofs(file_path_);
140   ofs << "<not_odrefresh_metrics></not_odrefresh_metrics>";
141   ofs.close();
142 
143   OdrMetricsRecord record{};
144   ASSERT_THAT(record.ReadFromFile(file_path_),
145               HasError(WithMessage("odrefresh_metrics element not found in " + file_path_)));
146 }
147 
TEST_F(OdrMetricsRecordTest,ExpectedElementNotFound)148 TEST_F(OdrMetricsRecordTest, ExpectedElementNotFound) {
149   metrics_version_ = "<not_valid_metric>25</not_valid_metric>";
150   WriteFile();
151 
152   OdrMetricsRecord record{};
153   ASSERT_THAT(
154       record.ReadFromFile(file_path_),
155       HasError(WithMessage("Expected Odrefresh metric odrefresh_metrics_version not found")));
156 }
157 
TEST_F(OdrMetricsRecordTest,ExpectedAttributeNotFound)158 TEST_F(OdrMetricsRecordTest, ExpectedAttributeNotFound) {
159   // Missing "status".
160   primary_bcp_dex2oat_result_ = R"(<primary_bcp_dex2oat_result exit-code="17" signal="18" />)";
161   WriteFile();
162 
163   OdrMetricsRecord record{};
164   ASSERT_THAT(record.ReadFromFile(file_path_),
165               HasError(WithMessage(
166                   "Expected Odrefresh metric primary_bcp_dex2oat_result.status is not an int32")));
167 }
168 
TEST_F(OdrMetricsRecordTest,UnexpectedOdrefreshMetricsVersion)169 TEST_F(OdrMetricsRecordTest, UnexpectedOdrefreshMetricsVersion) {
170   metrics_version_ = "<odrefresh_metrics_version>0</odrefresh_metrics_version>";
171   WriteFile();
172 
173   OdrMetricsRecord record{};
174   std::string expected_error = android::base::StringPrintf(
175       "odrefresh_metrics_version 0 is different than expected (%d)", kOdrefreshMetricsVersion);
176   ASSERT_THAT(record.ReadFromFile(file_path_), HasError(WithMessage(expected_error)));
177 }
178 
TEST_F(OdrMetricsRecordTest,UnexpectedType)179 TEST_F(OdrMetricsRecordTest, UnexpectedType) {
180   status_ = "<status>abcd</status>";  // It should be an int32.
181   WriteFile();
182 
183   OdrMetricsRecord record{};
184   ASSERT_THAT(record.ReadFromFile(file_path_),
185               HasError(WithMessage("Odrefresh metric status is not an int32")));
186 }
187 
TEST_F(OdrMetricsRecordTest,ResultStatusOutsideOfRange)188 TEST_F(OdrMetricsRecordTest, ResultStatusOutsideOfRange) {
189   // Status is valid between 0 and 5 (5 being NOT_RUN)
190   primary_bcp_dex2oat_result_ =
191       R"(<primary_bcp_dex2oat_result status="-1" exit-code="-1" signal="0" />)";
192   WriteFile();
193 
194   OdrMetricsRecord record{};
195   ASSERT_THAT(
196       record.ReadFromFile(file_path_),
197       HasError(WithMessage("Odrefresh metric primary_bcp_dex2oat_result.status has a value (-1) "
198                            "outside of the expected range ([0, 5])")));
199 
200   primary_bcp_dex2oat_result_ =
201       R"(<primary_bcp_dex2oat_result status="9" exit-code="-1" signal="0" />)";
202   WriteFile();
203 
204   ASSERT_THAT(
205       record.ReadFromFile(file_path_),
206       HasError(WithMessage("Odrefresh metric primary_bcp_dex2oat_result.status has a value (9) "
207                            "outside of the expected range ([0, 5])")));
208 }
209 
TEST_F(OdrMetricsRecordTest,ResultExitCodeOutsideOfRange)210 TEST_F(OdrMetricsRecordTest, ResultExitCodeOutsideOfRange) {
211   // Exit Code is valid between -1 and 255
212   secondary_bcp_dex2oat_result_ =
213       R"(<secondary_bcp_dex2oat_result status="2" exit-code="-2" signal="0" />)";
214   WriteFile();
215 
216   OdrMetricsRecord record{};
217   ASSERT_THAT(record.ReadFromFile(file_path_),
218               HasError(WithMessage(
219                   "Odrefresh metric secondary_bcp_dex2oat_result.exit-code has a value (-2) "
220                   "outside of the expected range ([-1, 255])")));
221 
222   secondary_bcp_dex2oat_result_ =
223       R"(<secondary_bcp_dex2oat_result status="2" exit-code="258" signal="0" />)";
224   WriteFile();
225 
226   ASSERT_THAT(record.ReadFromFile(file_path_),
227               HasError(WithMessage(
228                   "Odrefresh metric secondary_bcp_dex2oat_result.exit-code has a value (258) "
229                   "outside of the expected range ([-1, 255])")));
230 }
231 
TEST_F(OdrMetricsRecordTest,ResultSignalOutsideOfRange)232 TEST_F(OdrMetricsRecordTest, ResultSignalOutsideOfRange) {
233   // Signal is valid between 0 and SIGRTMAX
234   system_server_dex2oat_result_ =
235       R"(<system_server_dex2oat_result status="3" exit-code="0" signal="-6" />)";
236   WriteFile();
237 
238   OdrMetricsRecord record{};
239   ASSERT_THAT(record.ReadFromFile(file_path_),
240               HasError(WithMessage(android::base::StringPrintf(
241                   "Odrefresh metric system_server_dex2oat_result.signal has a value (-6) "
242                   "outside of the expected range ([0, %d])",
243                   SIGRTMAX))));
244 
245   system_server_dex2oat_result_ =
246       R"(<system_server_dex2oat_result status="3" exit-code="0" signal="65" />)";
247   WriteFile();
248 
249   ASSERT_THAT(record.ReadFromFile(file_path_),
250               HasError(WithMessage(android::base::StringPrintf(
251                   "Odrefresh metric system_server_dex2oat_result.signal has a value (65) "
252                   "outside of the expected range ([0, %d])",
253                   SIGRTMAX))));
254 }
255 
256 }  // namespace odrefresh
257 }  // namespace art
258