1 /*
2 * Copyright (C) 2015 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 <vector>
18
19 #include <base/at_exit.h>
20 #include <base/files/file_util.h>
21 #include <base/files/scoped_temp_dir.h>
22 #include <base/strings/string_number_conversions.h>
23 #include <brillo/flag_helper.h>
24 #include <gtest/gtest.h>
25
26 #include "constants.h"
27 #include "metrics_collector.h"
28 #include "metrics/metrics_library_mock.h"
29 #include "persistent_integer_mock.h"
30
31 using base::FilePath;
32 using base::TimeDelta;
33 using std::string;
34 using std::vector;
35 using ::testing::_;
36 using ::testing::AnyNumber;
37 using ::testing::AtLeast;
38 using ::testing::Return;
39 using ::testing::StrictMock;
40 using chromeos_metrics::PersistentIntegerMock;
41
42
43 class MetricsCollectorTest : public testing::Test {
44 protected:
SetUp()45 virtual void SetUp() {
46 brillo::FlagHelper::Init(0, nullptr, "");
47 EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
48
49 base::FilePath private_dir = temp_dir_.path().Append("private");
50 base::FilePath shared_dir = temp_dir_.path().Append("shared");
51
52 EXPECT_TRUE(base::CreateDirectory(private_dir));
53 EXPECT_TRUE(base::CreateDirectory(shared_dir));
54
55 daemon_.Init(true, &metrics_lib_, "", private_dir, shared_dir);
56 }
57
58 // Adds a metrics library mock expectation that the specified metric
59 // will be generated.
ExpectSample(const std::string & name,int sample)60 void ExpectSample(const std::string& name, int sample) {
61 EXPECT_CALL(metrics_lib_, SendToUMA(name, sample, _, _, _))
62 .Times(1)
63 .WillOnce(Return(true))
64 .RetiresOnSaturation();
65 }
66
67 // Creates or overwrites the file in |path| so that it contains the printable
68 // representation of |value|.
CreateUint64ValueFile(const base::FilePath & path,uint64_t value)69 void CreateUint64ValueFile(const base::FilePath& path, uint64_t value) {
70 std::string value_string = base::Uint64ToString(value);
71 ASSERT_EQ(value_string.length(),
72 base::WriteFile(path, value_string.c_str(),
73 value_string.length()));
74 }
75
76 // The MetricsCollector under test.
77 MetricsCollector daemon_;
78
79 // Temporary directory used for tests.
80 base::ScopedTempDir temp_dir_;
81
82 // Mocks. They are strict mock so that all unexpected
83 // calls are marked as failures.
84 StrictMock<MetricsLibraryMock> metrics_lib_;
85 };
86
TEST_F(MetricsCollectorTest,SendSample)87 TEST_F(MetricsCollectorTest, SendSample) {
88 ExpectSample("Dummy.Metric", 3);
89 daemon_.SendSample("Dummy.Metric", /* sample */ 3,
90 /* min */ 1, /* max */ 100, /* buckets */ 50);
91 }
92
TEST_F(MetricsCollectorTest,ProcessMeminfo)93 TEST_F(MetricsCollectorTest, ProcessMeminfo) {
94 string meminfo =
95 "MemTotal: 2000000 kB\nMemFree: 500000 kB\n"
96 "Buffers: 1000000 kB\nCached: 213652 kB\n"
97 "SwapCached: 0 kB\nActive: 133400 kB\n"
98 "Inactive: 183396 kB\nActive(anon): 92984 kB\n"
99 "Inactive(anon): 58860 kB\nActive(file): 40416 kB\n"
100 "Inactive(file): 124536 kB\nUnevictable: 0 kB\n"
101 "Mlocked: 0 kB\nSwapTotal: 0 kB\n"
102 "SwapFree: 0 kB\nDirty: 40 kB\n"
103 "Writeback: 0 kB\nAnonPages: 92652 kB\n"
104 "Mapped: 59716 kB\nShmem: 59196 kB\n"
105 "Slab: 16656 kB\nSReclaimable: 6132 kB\n"
106 "SUnreclaim: 10524 kB\nKernelStack: 1648 kB\n"
107 "PageTables: 2780 kB\nNFS_Unstable: 0 kB\n"
108 "Bounce: 0 kB\nWritebackTmp: 0 kB\n"
109 "CommitLimit: 970656 kB\nCommitted_AS: 1260528 kB\n"
110 "VmallocTotal: 122880 kB\nVmallocUsed: 12144 kB\n"
111 "VmallocChunk: 103824 kB\nDirectMap4k: 9636 kB\n"
112 "DirectMap2M: 1955840 kB\n";
113
114 // All enum calls must report percents.
115 EXPECT_CALL(metrics_lib_, SendEnumToUMA(_, _, 100)).Times(AtLeast(1));
116 // Check that MemFree is correctly computed at 25%.
117 EXPECT_CALL(metrics_lib_, SendEnumToUMA("Platform.MeminfoMemFree", 25, 100))
118 .Times(AtLeast(1));
119 // Check that we call SendToUma at least once (log histogram).
120 EXPECT_CALL(metrics_lib_, SendToUMA(_, _, _, _, _))
121 .Times(AtLeast(1));
122 // Make sure we don't report fields not in the list.
123 EXPECT_CALL(metrics_lib_, SendToUMA("Platform.MeminfoMlocked", _, _, _, _))
124 .Times(0);
125 EXPECT_CALL(metrics_lib_, SendEnumToUMA("Platform.MeminfoMlocked", _, _))
126 .Times(0);
127 EXPECT_TRUE(daemon_.ProcessMeminfo(meminfo));
128 }
129
TEST_F(MetricsCollectorTest,ProcessMeminfo2)130 TEST_F(MetricsCollectorTest, ProcessMeminfo2) {
131 string meminfo = "MemTotal: 2000000 kB\nMemFree: 1000000 kB\n";
132 // Not enough fields.
133 EXPECT_FALSE(daemon_.ProcessMeminfo(meminfo));
134 }
135
TEST_F(MetricsCollectorTest,SendZramMetrics)136 TEST_F(MetricsCollectorTest, SendZramMetrics) {
137 EXPECT_TRUE(daemon_.testing_);
138
139 // |compr_data_size| is the size in bytes of compressed data.
140 const uint64_t compr_data_size = 50 * 1000 * 1000;
141 // The constant '3' is a realistic but random choice.
142 // |orig_data_size| does not include zero pages.
143 const uint64_t orig_data_size = compr_data_size * 3;
144 const uint64_t page_size = 4096;
145 const uint64_t zero_pages = 10 * 1000 * 1000 / page_size;
146
147 CreateUint64ValueFile(
148 temp_dir_.path().Append(MetricsCollector::kComprDataSizeName),
149 compr_data_size);
150 CreateUint64ValueFile(
151 temp_dir_.path().Append(MetricsCollector::kOrigDataSizeName),
152 orig_data_size);
153 CreateUint64ValueFile(
154 temp_dir_.path().Append(MetricsCollector::kZeroPagesName), zero_pages);
155
156 const uint64_t real_orig_size = orig_data_size + zero_pages * page_size;
157 const uint64_t zero_ratio_percent =
158 zero_pages * page_size * 100 / real_orig_size;
159 // Ratio samples are in percents.
160 const uint64_t actual_ratio_sample = real_orig_size * 100 / compr_data_size;
161
162 EXPECT_CALL(metrics_lib_, SendToUMA(_, compr_data_size >> 20, _, _, _));
163 EXPECT_CALL(metrics_lib_,
164 SendToUMA(_, (real_orig_size - compr_data_size) >> 20, _, _, _));
165 EXPECT_CALL(metrics_lib_, SendToUMA(_, actual_ratio_sample, _, _, _));
166 EXPECT_CALL(metrics_lib_, SendToUMA(_, zero_pages, _, _, _));
167 EXPECT_CALL(metrics_lib_, SendToUMA(_, zero_ratio_percent, _, _, _));
168
169 EXPECT_TRUE(daemon_.ReportZram(temp_dir_.path()));
170 }
171