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.h"
18 #include "base/casts.h"
19 #include "odr_metrics_record.h"
20
21 #include <unistd.h>
22
23 #include <fstream>
24 #include <memory>
25 #include <string>
26
27 #include "base/common_art_test.h"
28
29 namespace art {
30 namespace odrefresh {
31
32 class OdrMetricsTest : public CommonArtTest {
33 public:
SetUp()34 void SetUp() override {
35 CommonArtTest::SetUp();
36
37 scratch_dir_ = std::make_unique<ScratchDir>();
38 metrics_file_path_ = scratch_dir_->GetPath() + "/metrics.txt";
39 cache_directory_ = scratch_dir_->GetPath() + "/dir";
40 mkdir(cache_directory_.c_str(), S_IRWXU);
41 }
42
TearDown()43 void TearDown() override {
44 scratch_dir_.reset();
45 }
46
MetricsFileExists() const47 bool MetricsFileExists() const {
48 const char* path = metrics_file_path_.c_str();
49 return OS::FileExists(path);
50 }
51
RemoveMetricsFile() const52 bool RemoveMetricsFile() const {
53 const char* path = metrics_file_path_.c_str();
54 if (OS::FileExists(path)) {
55 return unlink(path) == 0;
56 }
57 return true;
58 }
59
GetCacheDirectory() const60 const std::string GetCacheDirectory() const { return cache_directory_; }
GetMetricsFilePath() const61 const std::string GetMetricsFilePath() const { return metrics_file_path_; }
62
63 protected:
64 std::unique_ptr<ScratchDir> scratch_dir_;
65 std::string metrics_file_path_;
66 std::string cache_directory_;
67 };
68
TEST_F(OdrMetricsTest,ToRecordFailsIfNotTriggered)69 TEST_F(OdrMetricsTest, ToRecordFailsIfNotTriggered) {
70 {
71 OdrMetrics metrics(GetCacheDirectory(), GetMetricsFilePath());
72 OdrMetricsRecord record {};
73 EXPECT_FALSE(metrics.ToRecord(&record));
74 }
75
76 {
77 OdrMetrics metrics(GetCacheDirectory(), GetMetricsFilePath());
78 metrics.SetArtApexVersion(99);
79 metrics.SetStage(OdrMetrics::Stage::kCheck);
80 metrics.SetStatus(OdrMetrics::Status::kNoSpace);
81 OdrMetricsRecord record {};
82 EXPECT_FALSE(metrics.ToRecord(&record));
83 }
84 }
85
TEST_F(OdrMetricsTest,ToRecordSucceedsIfTriggered)86 TEST_F(OdrMetricsTest, ToRecordSucceedsIfTriggered) {
87 OdrMetrics metrics(GetCacheDirectory(), GetMetricsFilePath());
88 metrics.SetArtApexVersion(99);
89 metrics.SetTrigger(OdrMetrics::Trigger::kApexVersionMismatch);
90 metrics.SetStage(OdrMetrics::Stage::kCheck);
91 metrics.SetStatus(OdrMetrics::Status::kNoSpace);
92
93 OdrMetricsRecord record{};
94 EXPECT_TRUE(metrics.ToRecord(&record));
95
96 EXPECT_EQ(99, record.art_apex_version);
97 EXPECT_EQ(OdrMetrics::Trigger::kApexVersionMismatch,
98 enum_cast<OdrMetrics::Trigger>(record.trigger));
99 EXPECT_EQ(OdrMetrics::Stage::kCheck, enum_cast<OdrMetrics::Stage>(record.stage_reached));
100 EXPECT_EQ(OdrMetrics::Status::kNoSpace, enum_cast<OdrMetrics::Status>(record.status));
101 }
102
TEST_F(OdrMetricsTest,MetricsFileIsNotCreatedIfNotTriggered)103 TEST_F(OdrMetricsTest, MetricsFileIsNotCreatedIfNotTriggered) {
104 EXPECT_TRUE(RemoveMetricsFile());
105
106 // Metrics file is (potentially) written in OdrMetrics destructor.
107 {
108 OdrMetrics metrics(GetCacheDirectory(), GetMetricsFilePath());
109 metrics.SetArtApexVersion(99);
110 metrics.SetStage(OdrMetrics::Stage::kCheck);
111 metrics.SetStatus(OdrMetrics::Status::kNoSpace);
112 }
113 EXPECT_FALSE(MetricsFileExists());
114 }
115
TEST_F(OdrMetricsTest,NoMetricsFileIsCreatedIfTriggered)116 TEST_F(OdrMetricsTest, NoMetricsFileIsCreatedIfTriggered) {
117 EXPECT_TRUE(RemoveMetricsFile());
118
119 // Metrics file is (potentially) written in OdrMetrics destructor.
120 {
121 OdrMetrics metrics(GetCacheDirectory(), GetMetricsFilePath());
122 metrics.SetArtApexVersion(101);
123 metrics.SetTrigger(OdrMetrics::Trigger::kDexFilesChanged);
124 metrics.SetStage(OdrMetrics::Stage::kCheck);
125 metrics.SetStatus(OdrMetrics::Status::kNoSpace);
126 }
127 EXPECT_TRUE(MetricsFileExists());
128 }
129
TEST_F(OdrMetricsTest,StageDoesNotAdvancedAfterFailure)130 TEST_F(OdrMetricsTest, StageDoesNotAdvancedAfterFailure) {
131 OdrMetrics metrics(GetCacheDirectory(), GetMetricsFilePath());
132 metrics.SetArtApexVersion(1999);
133 metrics.SetTrigger(OdrMetrics::Trigger::kMissingArtifacts);
134 metrics.SetStage(OdrMetrics::Stage::kCheck);
135 metrics.SetStatus(OdrMetrics::Status::kNoSpace);
136 metrics.SetStage(OdrMetrics::Stage::kComplete);
137
138 OdrMetricsRecord record{};
139 EXPECT_TRUE(metrics.ToRecord(&record));
140
141 EXPECT_EQ(OdrMetrics::Stage::kCheck, enum_cast<OdrMetrics::Stage>(record.stage_reached));
142 }
143
TEST_F(OdrMetricsTest,TimeValuesAreRecorded)144 TEST_F(OdrMetricsTest, TimeValuesAreRecorded) {
145 OdrMetrics metrics(GetCacheDirectory(), GetMetricsFilePath());
146 metrics.SetArtApexVersion(1999);
147 metrics.SetTrigger(OdrMetrics::Trigger::kMissingArtifacts);
148 metrics.SetStage(OdrMetrics::Stage::kCheck);
149 metrics.SetStatus(OdrMetrics::Status::kOK);
150
151 // Primary boot classpath compilation time.
152 OdrMetricsRecord record{};
153 {
154 metrics.SetStage(OdrMetrics::Stage::kPrimaryBootClasspath);
155 ScopedOdrCompilationTimer timer(metrics);
156 sleep(2u);
157 }
158 EXPECT_TRUE(metrics.ToRecord(&record));
159 EXPECT_EQ(OdrMetrics::Stage::kPrimaryBootClasspath,
160 enum_cast<OdrMetrics::Stage>(record.stage_reached));
161 EXPECT_NE(0, record.primary_bcp_compilation_seconds);
162 EXPECT_GT(10, record.primary_bcp_compilation_seconds);
163 EXPECT_EQ(0, record.secondary_bcp_compilation_seconds);
164 EXPECT_EQ(0, record.system_server_compilation_seconds);
165
166 // Secondary boot classpath compilation time.
167 {
168 metrics.SetStage(OdrMetrics::Stage::kSecondaryBootClasspath);
169 ScopedOdrCompilationTimer timer(metrics);
170 sleep(2u);
171 }
172 EXPECT_TRUE(metrics.ToRecord(&record));
173 EXPECT_EQ(OdrMetrics::Stage::kSecondaryBootClasspath,
174 enum_cast<OdrMetrics::Stage>(record.stage_reached));
175 EXPECT_NE(0, record.primary_bcp_compilation_seconds);
176 EXPECT_NE(0, record.secondary_bcp_compilation_seconds);
177 EXPECT_GT(10, record.secondary_bcp_compilation_seconds);
178 EXPECT_EQ(0, record.system_server_compilation_seconds);
179
180 // system_server classpath compilation time.
181 {
182 metrics.SetStage(OdrMetrics::Stage::kSystemServerClasspath);
183 ScopedOdrCompilationTimer timer(metrics);
184 sleep(2u);
185 }
186 EXPECT_TRUE(metrics.ToRecord(&record));
187 EXPECT_EQ(OdrMetrics::Stage::kSystemServerClasspath,
188 enum_cast<OdrMetrics::Stage>(record.stage_reached));
189 EXPECT_NE(0, record.primary_bcp_compilation_seconds);
190 EXPECT_NE(0, record.secondary_bcp_compilation_seconds);
191 EXPECT_NE(0, record.system_server_compilation_seconds);
192 EXPECT_GT(10, record.system_server_compilation_seconds);
193 }
194
TEST_F(OdrMetricsTest,CacheSpaceValuesAreUpdated)195 TEST_F(OdrMetricsTest, CacheSpaceValuesAreUpdated) {
196 OdrMetricsRecord snap {};
197 snap.cache_space_free_start_mib = -1;
198 snap.cache_space_free_end_mib = -1;
199 {
200 OdrMetrics metrics(GetCacheDirectory(), GetMetricsFilePath());
201 metrics.SetArtApexVersion(1999);
202 metrics.SetTrigger(OdrMetrics::Trigger::kMissingArtifacts);
203 metrics.SetStage(OdrMetrics::Stage::kCheck);
204 metrics.SetStatus(OdrMetrics::Status::kOK);
205 EXPECT_TRUE(metrics.ToRecord(&snap));
206 EXPECT_NE(0, snap.cache_space_free_start_mib);
207 EXPECT_EQ(0, snap.cache_space_free_end_mib);
208 }
209
210 OdrMetricsRecord on_disk;
211 std::ifstream ifs(GetMetricsFilePath());
212 EXPECT_TRUE(ifs);
213 ifs >> on_disk;
214 EXPECT_TRUE(ifs);
215 EXPECT_EQ(snap.cache_space_free_start_mib, on_disk.cache_space_free_start_mib);
216 EXPECT_NE(0, on_disk.cache_space_free_end_mib);
217 }
218
219 } // namespace odrefresh
220 } // namespace art
221