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