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