/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <vector> #include <base/at_exit.h> #include <base/files/file_util.h> #include <base/files/scoped_temp_dir.h> #include <base/strings/string_number_conversions.h> #include <brillo/flag_helper.h> #include <gtest/gtest.h> #include "constants.h" #include "metrics_collector.h" #include "metrics/metrics_library_mock.h" #include "persistent_integer_mock.h" using base::FilePath; using base::TimeDelta; using std::string; using std::vector; using ::testing::_; using ::testing::AnyNumber; using ::testing::AtLeast; using ::testing::Return; using ::testing::StrictMock; using chromeos_metrics::PersistentIntegerMock; class MetricsCollectorTest : public testing::Test { protected: virtual void SetUp() { brillo::FlagHelper::Init(0, nullptr, ""); EXPECT_TRUE(temp_dir_.CreateUniqueTempDir()); base::FilePath private_dir = temp_dir_.path().Append("private"); base::FilePath shared_dir = temp_dir_.path().Append("shared"); EXPECT_TRUE(base::CreateDirectory(private_dir)); EXPECT_TRUE(base::CreateDirectory(shared_dir)); daemon_.Init(true, &metrics_lib_, "", private_dir, shared_dir); } // Adds a metrics library mock expectation that the specified metric // will be generated. void ExpectSample(const std::string& name, int sample) { EXPECT_CALL(metrics_lib_, SendToUMA(name, sample, _, _, _)) .Times(1) .WillOnce(Return(true)) .RetiresOnSaturation(); } // Creates or overwrites the file in |path| so that it contains the printable // representation of |value|. void CreateUint64ValueFile(const base::FilePath& path, uint64_t value) { std::string value_string = base::Uint64ToString(value); ASSERT_EQ(value_string.length(), base::WriteFile(path, value_string.c_str(), value_string.length())); } // The MetricsCollector under test. MetricsCollector daemon_; // Temporary directory used for tests. base::ScopedTempDir temp_dir_; // Mocks. They are strict mock so that all unexpected // calls are marked as failures. StrictMock<MetricsLibraryMock> metrics_lib_; }; TEST_F(MetricsCollectorTest, SendSample) { ExpectSample("Dummy.Metric", 3); daemon_.SendSample("Dummy.Metric", /* sample */ 3, /* min */ 1, /* max */ 100, /* buckets */ 50); } TEST_F(MetricsCollectorTest, ProcessMeminfo) { string meminfo = "MemTotal: 2000000 kB\nMemFree: 500000 kB\n" "Buffers: 1000000 kB\nCached: 213652 kB\n" "SwapCached: 0 kB\nActive: 133400 kB\n" "Inactive: 183396 kB\nActive(anon): 92984 kB\n" "Inactive(anon): 58860 kB\nActive(file): 40416 kB\n" "Inactive(file): 124536 kB\nUnevictable: 0 kB\n" "Mlocked: 0 kB\nSwapTotal: 0 kB\n" "SwapFree: 0 kB\nDirty: 40 kB\n" "Writeback: 0 kB\nAnonPages: 92652 kB\n" "Mapped: 59716 kB\nShmem: 59196 kB\n" "Slab: 16656 kB\nSReclaimable: 6132 kB\n" "SUnreclaim: 10524 kB\nKernelStack: 1648 kB\n" "PageTables: 2780 kB\nNFS_Unstable: 0 kB\n" "Bounce: 0 kB\nWritebackTmp: 0 kB\n" "CommitLimit: 970656 kB\nCommitted_AS: 1260528 kB\n" "VmallocTotal: 122880 kB\nVmallocUsed: 12144 kB\n" "VmallocChunk: 103824 kB\nDirectMap4k: 9636 kB\n" "DirectMap2M: 1955840 kB\n"; // All enum calls must report percents. EXPECT_CALL(metrics_lib_, SendEnumToUMA(_, _, 100)).Times(AtLeast(1)); // Check that MemFree is correctly computed at 25%. EXPECT_CALL(metrics_lib_, SendEnumToUMA("Platform.MeminfoMemFree", 25, 100)) .Times(AtLeast(1)); // Check that we call SendToUma at least once (log histogram). EXPECT_CALL(metrics_lib_, SendToUMA(_, _, _, _, _)) .Times(AtLeast(1)); // Make sure we don't report fields not in the list. EXPECT_CALL(metrics_lib_, SendToUMA("Platform.MeminfoMlocked", _, _, _, _)) .Times(0); EXPECT_CALL(metrics_lib_, SendEnumToUMA("Platform.MeminfoMlocked", _, _)) .Times(0); EXPECT_TRUE(daemon_.ProcessMeminfo(meminfo)); } TEST_F(MetricsCollectorTest, ProcessMeminfo2) { string meminfo = "MemTotal: 2000000 kB\nMemFree: 1000000 kB\n"; // Not enough fields. EXPECT_FALSE(daemon_.ProcessMeminfo(meminfo)); } TEST_F(MetricsCollectorTest, SendZramMetrics) { EXPECT_TRUE(daemon_.testing_); // |compr_data_size| is the size in bytes of compressed data. const uint64_t compr_data_size = 50 * 1000 * 1000; // The constant '3' is a realistic but random choice. // |orig_data_size| does not include zero pages. const uint64_t orig_data_size = compr_data_size * 3; const uint64_t page_size = 4096; const uint64_t zero_pages = 10 * 1000 * 1000 / page_size; CreateUint64ValueFile( temp_dir_.path().Append(MetricsCollector::kComprDataSizeName), compr_data_size); CreateUint64ValueFile( temp_dir_.path().Append(MetricsCollector::kOrigDataSizeName), orig_data_size); CreateUint64ValueFile( temp_dir_.path().Append(MetricsCollector::kZeroPagesName), zero_pages); const uint64_t real_orig_size = orig_data_size + zero_pages * page_size; const uint64_t zero_ratio_percent = zero_pages * page_size * 100 / real_orig_size; // Ratio samples are in percents. const uint64_t actual_ratio_sample = real_orig_size * 100 / compr_data_size; EXPECT_CALL(metrics_lib_, SendToUMA(_, compr_data_size >> 20, _, _, _)); EXPECT_CALL(metrics_lib_, SendToUMA(_, (real_orig_size - compr_data_size) >> 20, _, _, _)); EXPECT_CALL(metrics_lib_, SendToUMA(_, actual_ratio_sample, _, _, _)); EXPECT_CALL(metrics_lib_, SendToUMA(_, zero_pages, _, _, _)); EXPECT_CALL(metrics_lib_, SendToUMA(_, zero_ratio_percent, _, _, _)); EXPECT_TRUE(daemon_.ReportZram(temp_dir_.path())); }