• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3# Copyright (C) 2025 Huawei Device Co., Ltd.
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
16import pytest
17import re
18import threading
19import time
20import json
21from utils import *
22
23PSS_TOTAL_INDEX = 0
24SWAP_PSS_INDEX = 6
25COLUMN_NUM = 10
26
27def WaitUntillOutputAppear(command, targetStr, second):
28    time.sleep(1)
29    command = None
30    if IsRootVersion():
31        command = "hdc shell \"ls -l /data/log/faultlog/temp |grep jsheap\""
32    else:
33        command = "hdc shell \"ls -l /data/log/reliability/resource_leak/memory_leak |grep jsheap\""
34    output = subprocess.check_output(command, shell=True, text=True, encoding="utf-8").strip()
35    return output != ""
36
37def PreOperationHap():
38    # 单击【Enable】按钮
39    TouchButtonByText("Enable")
40    time.sleep(3)
41    # 单击【2_全局变量未使用造成js内存泄露】按钮
42    TouchButtonByText("2_全局变量未使用造成js内存泄露")
43    time.sleep(3)
44    command = "rm -rf /data/log/reliability/resource_leak/memory_leak/hidumper-*"
45    output = subprocess.check_output(f"hdc shell \"{command}\"", shell=True, text=True, encoding="utf-8")
46
47def ParseJsLeakListOutput():
48    jsleakDir = "/data/log/reliability/resource_leak/memory_leak"
49    if IsOpenHarmonyVersion() or not IsRootVersion():
50        jsleakDir = "/data/log/faultlog/temp"
51    command = f"ls {jsleakDir} |grep -e leaklist"
52    output = subprocess.check_output(f"hdc shell \"{command}\"", shell=True, text=True, encoding="utf-8")
53    assert "leaklist" in output
54    filename = output.strip('\n')
55    print(f"leaklist filename:{filename} \n")
56    command = f"cat {jsleakDir}/" + filename
57    output = subprocess.check_output(f"hdc shell \"{command}\"", shell=True, text=True, encoding="utf-8")
58    output = output.strip('\n')
59    return output
60
61def ParseJsHeapOutput(hash_val, name, msg):
62    jsleakDir = "/data/log/reliability/resource_leak/memory_leak"
63    if IsOpenHarmonyVersion() or not IsRootVersion():
64        jsleakDir = "/data/log/faultlog/temp"
65    command = f"ls {jsleakDir} |grep -e jsheap"
66    output = subprocess.check_output(f"hdc shell \"{command}\"", shell=True, text=True, encoding="utf-8")
67    assert "jsheap" in output
68    filename = output.strip('\n')
69    print(f"jsheap filename:{filename} \n")
70    command = f"cat {jsleakDir}/" + filename + " |grep -e " + str(hash_val) + " -e " + name + " -e " + msg
71    output = subprocess.check_output(f"hdc shell \"{command}\"", shell=True, text=True, encoding="utf-8")
72    return output
73
74class TestHidumperMemoryJsheap:
75    @classmethod
76    def setup_class(cls):
77        subprocess.check_call("hdc shell aa start -a EntryAbility -b com.example.jsleakwatcher", shell=True)
78
79    @classmethod
80    def teardown_class(cls):
81        subprocess.check_call("hdc shell aa force-stop -b com.example.jsleakwatcher", shell=True)
82
83    def teardown_method(self):
84        if not IsOpenHarmonyVersion():
85            subprocess.check_call("hdc shell \"rm -rf /data/log/reliability/resource_leak/memory_leak/*\"", shell=True)
86        else:
87            subprocess.check_call("hdc shell \"rm -rf /data/log/faultlog/temp/*\"", shell=True)
88
89    @pytest.mark.L0
90    def test_mem_jsheap(self):
91        pid = None
92        if IsOpenHarmonyVersion():
93            pid = GetPidByProcessName("com.ohos.launcher")
94        elif IsRootVersion():
95            pid = GetPidByProcessName("com.ohos.sceneboard")
96        else:
97            pid = GetPidByProcessName("com.example.myapplication")
98            if pid == "":
99                pytest.skip("test application not found")
100        command = f"hdc shell \"hidumper --mem-jsheap {pid}\""
101        # 校验命令行输出
102        subprocess.check_call(command, shell=True)
103        ret = WaitUntillOutputAppear("hdc shell \"ls -l /data/log/faultlog/temp |grep jsheap\"", "jsheap", 10)
104        if not ret:
105            ret = WaitUntillOutputAppear("hdc shell \"ls -l /data/log/reliability/resource_leak/memory_leak |grep jsheap\"", "jsheap", 10)
106        assert ret
107
108    @pytest.mark.L0
109    def test_mem_jsheap_T(self):
110        pid = None
111        if IsOpenHarmonyVersion():
112            pid = GetPidByProcessName("com.ohos.launcher")
113        elif IsRootVersion():
114            pid = GetPidByProcessName("com.ohos.sceneboard")
115        else:
116            pid = GetPidByProcessName("com.example.myapplication")
117            if pid == "":
118                pytest.skip("test application not found")
119        command = f"hdc shell \"hidumper --mem-jsheap {pid} -T {pid}\""
120        # 校验命令行输出
121        subprocess.check_call(command, shell=True)
122        ret = WaitUntillOutputAppear("hdc shell \"ls -l /data/log/faultlog/temp |grep jsheap\"", "jsheap", 10)
123        if not ret:
124            ret = WaitUntillOutputAppear("hdc shell \"ls -l /data/log/reliability/resource_leak/memory_leak |grep jsheap\"", "jsheap", 10)
125        assert ret
126
127    @pytest.mark.L0
128    def test_mem_jsheap_gc(self):
129        pid = None
130        if IsOpenHarmonyVersion():
131            pid = GetPidByProcessName("com.ohos.launcher")
132        elif IsRootVersion():
133            pid = GetPidByProcessName("com.ohos.sceneboard")
134        else:
135            pid = GetPidByProcessName("com.example.myapplication")
136            if pid == "":
137                pytest.skip("test application not found")
138        process_hilog = subprocess.Popen(['hdc', 'shell', 'hilog | grep ArkCompiler > /data/local/tmp/test_mem_jsheap_gc.txt'])
139        command = f"hdc shell \"hidumper --mem-jsheap {pid} --gc\""
140        # 校验命令行输出
141        subprocess.check_call(command, shell=True)
142        time.sleep(3)
143        process_hilog.terminate()
144        output = subprocess.check_output(f"hdc shell cat /data/local/tmp/test_mem_jsheap_gc.txt", text=True, encoding="utf-8")
145        log = "TriggerGC tid 0 curTid " + str(pid)
146        assert log in output
147
148    @pytest.mark.L0
149    def test_mem_jsheap_T_gc(self):
150        pid = None
151        if IsOpenHarmonyVersion():
152            pid = GetPidByProcessName("com.ohos.launcher")
153        elif IsRootVersion():
154            pid = GetPidByProcessName("com.ohos.sceneboard")
155        else:
156            pid = GetPidByProcessName("com.example.myapplication")
157            if pid == "":
158                pytest.skip("test application not found")
159        process_hilog = subprocess.Popen(['hdc', 'shell', 'hilog | grep ArkCompiler > /data/local/tmp/test_mem_jsheap_T_gc.txt'])
160        command = f"hdc shell \"hidumper --mem-jsheap {pid} -T {pid} --gc\""
161        # 校验命令行输出
162        subprocess.check_call(command, shell=True)
163        time.sleep(3)
164        process_hilog.terminate()
165        output = subprocess.check_output(f"hdc shell cat /data/local/tmp/test_mem_jsheap_T_gc.txt", text=True, encoding="utf-8")
166        log = "TriggerGC tid " + str(pid) + " curTid " + str(pid)
167        assert log in output
168
169    @pytest.mark.L0
170    def test_mem_jsheap_leakobj(self):
171        PreOperationHap()
172        pid = GetPidByProcessName("com.example.jsleakwatcher")
173        if pid == "":
174            pytest.skip("com.example.jsleakwatcher not found")
175        command = f"hdc shell \"hidumper --mem-jsheap {pid} --leakobj\""
176        subprocess.check_call(command, shell=True)
177        time.sleep(3)
178        # 解析leaklist文件
179        output = ParseJsLeakListOutput()
180        json_data = json.loads(output)
181        hash_val = json_data[0]['hash']
182        name = json_data[0]['name']
183        msg = json_data[0]['msg']
184        # 解析heapsnapshot文件,判断heapsnapshot中是否包含leaklist对象
185        output = ParseJsHeapOutput(hash_val, name, msg)
186        print(f"output:{output}\n")
187        assert str(hash_val) in output
188        assert "Int:" + str(hash_val) in output
189        assert name in output
190        assert msg in output
191
192    @pytest.mark.L3
193    def test_mem_jsheap_error_pid(self):
194        command = f"hidumper --mem-jsheap 2147483647;hidumper --mem-jsheap -2147483647"
195        hidumperTmpCmd = "OPT:mem-jsheap SUB_OPT:"
196        # 校验命令行输出
197        CheckCmd(command, lambda output : "hidumper: No such process: 2147483647\nhidumper: invalid arg: -2147483647" in output, hidumperTmpCmd)
198        command = f"hidumper --mem-jsheap 2147483648;hidumper --mem-jsheap -2147483648"
199        CheckCmd(command, lambda output : "hidumper: invalid arg: -2147483648" in output, hidumperTmpCmd)
200
201