1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15#include <gtest/gtest.h>
16#include <map>
17#include <unistd.h>
18#include <vector>
19#include <v1_0/imemory_tracker_interface.h>
20
21#define private public
22#include "executor/memory_dumper.h"
23#undef private
24#include "dump_client_main.h"
25#include "dump_utils.h"
26#include "hdf_base.h"
27#include "executor/memory/memory_filter.h"
28#include "executor/memory/memory_util.h"
29#include "hidumper_test_utils.h"
30#include "util/string_utils.h"
31
32using namespace testing::ext;
33using namespace OHOS::HDI::Memorytracker::V1_0;
34namespace OHOS {
35namespace HiviewDFX {
36class MemoryDumperTest : public testing::Test {
37public:
38    static void SetUpTestCase(void);
39    static void TearDownTestCase(void);
40    void SetUp();
41    void TearDown();
42};
43
44void MemoryDumperTest::SetUpTestCase(void)
45{
46}
47void MemoryDumperTest::TearDownTestCase(void)
48{
49}
50void MemoryDumperTest::SetUp(void)
51{
52}
53void MemoryDumperTest::TearDown(void)
54{
55}
56
57/**
58 * @tc.name: MemoryDumperTest001
59 * @tc.desc: Test MemoryDumper has correct group.
60 * @tc.type: FUNC
61 * @tc.require: issueI5NWZQ
62 */
63HWTEST_F(MemoryDumperTest, MemoryDumperTest001, TestSize.Level3)
64{
65    std::string cmd = "hidumper --mem";
66    std::string str = "Anonymous Page";
67    ASSERT_TRUE(HidumperTestUtils::GetInstance().IsExistInCmdResult(cmd, str));
68}
69
70/**
71 * @tc.name: MemoryDumperTest002
72 * @tc.desc: Test MemoryDumper has DMA group.
73 * @tc.type: FUNC
74 * @tc.require: issueI5NX04
75 */
76HWTEST_F(MemoryDumperTest, MemoryDumperTest002, TestSize.Level3)
77{
78    std::string cmd = "hidumper --mem";
79    std::string str = "DMA";
80    ASSERT_TRUE(HidumperTestUtils::GetInstance().IsExistInCmdResult(cmd, str));
81}
82
83/**
84 * @tc.name: MemoryDumperTest003
85 * @tc.desc: Test MemoryDumper has correct group.
86 * @tc.type: FUNC
87 * @tc.require: issueI5NWZQ
88 */
89HWTEST_F(MemoryDumperTest, MemoryDumperTest003, TestSize.Level3)
90{
91    std::string cmd = "hidumper --mem 1";
92    std::string str = "Total";
93    ASSERT_TRUE(HidumperTestUtils::GetInstance().IsExistInCmdResult(cmd, str));
94    str = "native heap:";
95    ASSERT_TRUE(HidumperTestUtils::GetInstance().IsExistInCmdResult(cmd, str));
96    str = "Purgeable:";
97    ASSERT_TRUE(HidumperTestUtils::GetInstance().IsExistInCmdResult(cmd, str));
98    str = "DMA:";
99    ASSERT_TRUE(HidumperTestUtils::GetInstance().IsExistInCmdResult(cmd, str));
100}
101
102/**
103 * @tc.name: MemoryDumperTest004
104 * @tc.desc: Test MemoryDumper has GPU group.
105 * @tc.type: FUNC
106 * @tc.require: issueI5NWZQ
107 */
108HWTEST_F(MemoryDumperTest, MemoryDumperTest004, TestSize.Level3)
109{
110    std::string cmd = "hidumper --mem";
111    std::string str = "GPU";
112    ASSERT_TRUE(HidumperTestUtils::GetInstance().IsExistInCmdResult(cmd, str));
113}
114
115/**
116 * @tc.name: MemoryDumperTest005
117 * @tc.desc: Test MemoryDumper has Purgeable group.
118 * @tc.type: FUNC
119 * @tc.require: issueI5NWZQ
120 */
121HWTEST_F(MemoryDumperTest, MemoryDumperTest005, TestSize.Level3)
122{
123    std::string cmd = "hidumper --mem";
124    std::string str = "Total Purgeable";
125    ASSERT_TRUE(HidumperTestUtils::GetInstance().IsExistInCmdResult(cmd, str));
126    str = "Total PurgSum";
127    ASSERT_TRUE(HidumperTestUtils::GetInstance().IsExistInCmdResult(cmd, str));
128    str = "Total PurgPin";
129    ASSERT_TRUE(HidumperTestUtils::GetInstance().IsExistInCmdResult(cmd, str));
130}
131
132/**
133 * @tc.name: MemoryDumperTest006
134 * @tc.desc: Test MemoryDumper has Dma/PurgSum/PurgPin group.
135 * @tc.type: FUNC
136 * @tc.require: issueI5NWZQ
137 */
138HWTEST_F(MemoryDumperTest, MemoryDumperTest006, TestSize.Level3)
139{
140    std::string cmd = "hidumper --mem";
141    std::string str = "Dma     PurgSum     PurgPin";
142    ASSERT_TRUE(HidumperTestUtils::GetInstance().IsExistInCmdResult(cmd, str));
143}
144
145/**
146 * @tc.name: MemoryDumperTest007
147 * @tc.desc: Test zip memory not contain "Total Memory Usage by PID".
148 * @tc.type: FUNC
149 * @tc.require: issueI5NWZQ
150 */
151HWTEST_F(MemoryDumperTest, MemoryDumperTest007, TestSize.Level3)
152{
153    std::string cmd = "hidumper --mem --zip";
154    std::string str = "Total Memory Usage by PID";
155    ASSERT_FALSE(HidumperTestUtils::GetInstance().IsExistInCmdResult(cmd, str));
156}
157
158/**
159 * @tc.name: MemoryDumperTest008
160 * @tc.desc: Test dma is equal graph.
161 * @tc.type: FUNC
162 * @tc.require: issueI5NWZQ
163 */
164HWTEST_F(MemoryDumperTest, MemoryDumperTest008, TestSize.Level3)
165{
166    auto rsPid = static_cast<int32_t>(HidumperTestUtils::GetInstance().GetPidByName("render_service"));
167    int pid = rsPid > 0 ? rsPid : 1;
168    ASSERT_GT(pid, 0);
169    std::string cmd = "hidumper --mem " + std::to_string(pid);
170    std::string str = "Graph";
171    std::string result = "";
172    ASSERT_TRUE(HidumperTestUtils::GetInstance().GetSpecialLine(cmd, str, result));
173    std::string graphPss = HidumperTestUtils::GetInstance().GetValueInLine(result, 1);
174    ASSERT_TRUE(IsNumericStr(graphPss));
175    str = "Dma";
176    result = "";
177    ASSERT_TRUE(HidumperTestUtils::GetInstance().GetSpecialLine(cmd, str, result));
178    vector<string> values;
179    StringUtils::GetInstance().StringSplit(result, ":", values); // Dma:0 kB
180    std::string dmaStr = "";
181    if (!values.empty() && values.size() >= 2) { // 2: Dma, 0 kB
182        dmaStr = values[1];
183        if (dmaStr.size() >= 3) {
184            dmaStr = dmaStr.substr(0, dmaStr.size() - 4);  // 4: ' kB' + 1(index from to 0,1,2...)
185            ASSERT_TRUE(IsNumericStr(dmaStr));
186        }
187    }
188    ASSERT_TRUE(graphPss == dmaStr);
189}
190
191/**
192 * @tc.name: MemoryDumperTest009
193 * @tc.desc: Test GL not out of bounds.
194 * @tc.type: FUNC
195 * @tc.require: issueI5NWZQ
196 */
197HWTEST_F(MemoryDumperTest, MemoryDumperTest009, TestSize.Level3)
198{
199    auto rsPid = static_cast<int32_t>(HidumperTestUtils::GetInstance().GetPidByName("render_service"));
200    int pid = rsPid > 0 ? rsPid : 1;
201    ASSERT_GT(pid, 0);
202    std::string cmd = "hidumper --mem " + std::to_string(pid);
203    std::string str = "GL";
204    std::string result = "";
205    ASSERT_TRUE(HidumperTestUtils::GetInstance().GetSpecialLine(cmd, str, result));
206    std::string glPss = HidumperTestUtils::GetInstance().GetValueInLine(result, 1);
207    ASSERT_TRUE(IsNumericStr(glPss));
208    uint64_t gl = static_cast<uint64_t>(std::stoi(glPss));
209    ASSERT_FALSE(gl < 0 || gl > UINT64_MAX);
210}
211
212/**
213 * @tc.name: MemoryDumperTest010
214 * @tc.desc: Test HeapSize for "hidumper --mem `pidof com.ohos.sceneboard`"".
215 * @tc.type: FUNC
216 * @tc.require: issueI5NWZQ
217 */
218HWTEST_F(MemoryDumperTest, MemoryDumperTest010, TestSize.Level3)
219{
220    auto sceneboardPid = static_cast<int32_t>(HidumperTestUtils::GetInstance().GetPidByName("com.ohos.sceneboard"));
221    int pid = sceneboardPid > 0 ? sceneboardPid : 1;
222    ASSERT_GT(pid, 0);
223    std::string cmd = "hidumper --mem " + std::to_string(pid);
224    std::string str = "native heap";
225    std::string result = "";
226    ASSERT_TRUE(HidumperTestUtils::GetInstance().GetSpecialLine(cmd, str, result));
227    // 9: HeapSize index
228    std::string nativeHeapSizeStr = HidumperTestUtils::GetInstance().GetValueInLine(result, 9);
229    ASSERT_TRUE(IsNumericStr(nativeHeapSizeStr));
230    if (DumpUtils::IsHmKernel()) {
231        uint64_t nativeHeapSize = static_cast<uint64_t>(std::stoi(nativeHeapSizeStr));
232        ASSERT_TRUE(nativeHeapSize > 0);
233    }
234}
235
236/**
237 * @tc.name: MemoryUtilTest001
238 * @tc.desc: Test IsNameLine has correct ret.
239 * @tc.type: FUNC
240 */
241HWTEST_F(MemoryDumperTest, MemoryUtilTest001, TestSize.Level1)
242{
243    const std::string valueLine = "Rss:                  24 kB";
244    std::string name;
245    uint64_t iNode = 0;
246    ASSERT_FALSE(MemoryUtil::GetInstance().IsNameLine(valueLine, name, iNode));
247    ASSERT_EQ(name, "");
248    const std::string nameLine = "ffb84000-ffba5000 rw-p 00000000 00:00 0                                  [stack]";
249    ASSERT_TRUE(MemoryUtil::GetInstance().IsNameLine(nameLine, name, iNode));
250    ASSERT_EQ(name, "[stack]");
251}
252
253/**
254 * @tc.name: MemoryUtilTest002
255 * @tc.desc: Test GetTypeAndValue has correct ret.
256 * @tc.type: FUNC
257 */
258HWTEST_F(MemoryDumperTest, MemoryUtilTest002, TestSize.Level1)
259{
260    std::string type;
261    uint64_t value = 0;
262    const std::string illegalStr = "aaaaaa";
263    ASSERT_FALSE(MemoryUtil::GetInstance().GetTypeAndValue(illegalStr, type, value));
264    const std::string valueStr = "MemTotal:        2010244 kB";
265    ASSERT_TRUE(MemoryUtil::GetInstance().GetTypeAndValue(valueStr, type, value));
266    ASSERT_EQ(type, "MemTotal");
267    ASSERT_EQ(value, 2010244);
268}
269
270/**
271 * @tc.name: MemoryUtilTest003
272 * @tc.desc: Test RunCMD has correct ret.
273 * @tc.type: FUNC
274 */
275HWTEST_F(MemoryDumperTest, MemoryUtilTest003, TestSize.Level1)
276{
277    const std::string cmd = "ps -ef";
278    std::vector<std::string> vec;
279    ASSERT_TRUE(MemoryUtil::GetInstance().RunCMD(cmd, vec));
280    ASSERT_GT(vec.size(), 0);
281}
282
283/**
284 * @tc.name: MemoryUtilTest004
285 * @tc.desc: Test hidumper some cmd.
286 * @tc.type: FUNC
287 */
288HWTEST_F(MemoryDumperTest, MemoryUtilTest004, TestSize.Level1)
289{
290    std::string cmd = "hidumper --mem-smaps 1";
291    std::vector<std::string> vec;
292    ASSERT_TRUE(MemoryUtil::GetInstance().RunCMD(cmd, vec));
293    cmd = "hidumper --mem-smaps 1 -v";
294    ASSERT_TRUE(MemoryUtil::GetInstance().RunCMD(cmd, vec));
295    cmd = "hidumper --net 1";
296    ASSERT_TRUE(MemoryUtil::GetInstance().RunCMD(cmd, vec));
297    cmd = "hidumper --storage 1";
298    ASSERT_TRUE(MemoryUtil::GetInstance().RunCMD(cmd, vec));
299}
300
301/**
302 * @tc.name: MemoryUtilTest005
303 * @tc.desc: Test no such pid.
304 * @tc.type: FUNC
305 */
306HWTEST_F(MemoryDumperTest, MemoryUtilTest005, TestSize.Level1)
307{
308    std::string cmd = "hidumper --mem-smaps 100000";
309    std::vector<std::string> vec;
310    ASSERT_TRUE(MemoryUtil::GetInstance().RunCMD(cmd, vec));
311    cmd = "hidumper --mem-smaps 100000 -v";
312    ASSERT_TRUE(MemoryUtil::GetInstance().RunCMD(cmd, vec));
313    cmd = "hidumper --cpuusage 100000";
314    ASSERT_TRUE(MemoryUtil::GetInstance().RunCMD(cmd, vec));
315    cmd = "hidumper --mem 100000";
316    ASSERT_TRUE(MemoryUtil::GetInstance().RunCMD(cmd, vec));
317    cmd = "hidumper -p 100000";
318    ASSERT_TRUE(MemoryUtil::GetInstance().RunCMD(cmd, vec));
319    cmd = "hidumper --storage 100000";
320    ASSERT_TRUE(MemoryUtil::GetInstance().RunCMD(cmd, vec));
321    cmd = "hidumper --net 100000";
322    ASSERT_TRUE(MemoryUtil::GetInstance().RunCMD(cmd, vec));
323    cmd = "hidumper --mem-jsheap 100000";
324    ASSERT_TRUE(MemoryUtil::GetInstance().RunCMD(cmd, vec));
325    cmd = "hidumper --mem-jsheap 0";
326    ASSERT_TRUE(MemoryUtil::GetInstance().RunCMD(cmd, vec));
327    cmd = "hidumper --ipc --stat 100000";
328    ASSERT_TRUE(MemoryUtil::GetInstance().RunCMD(cmd, vec));
329}
330} // namespace HiviewDFX
331} // namespace OHOS