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
31using base::FilePath;
32using base::TimeDelta;
33using std::string;
34using std::vector;
35using ::testing::_;
36using ::testing::AnyNumber;
37using ::testing::AtLeast;
38using ::testing::Return;
39using ::testing::StrictMock;
40using chromeos_metrics::PersistentIntegerMock;
41
42
43class MetricsCollectorTest : public testing::Test {
44 protected:
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.
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|.
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
87TEST_F(MetricsCollectorTest, SendSample) {
88  ExpectSample("Dummy.Metric", 3);
89  daemon_.SendSample("Dummy.Metric", /* sample */ 3,
90                     /* min */ 1, /* max */ 100, /* buckets */ 50);
91}
92
93TEST_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
130TEST_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
136TEST_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