1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3""" 4Copyright (c) 2024 Huawei Device Co., Ltd. 5Licensed under the Apache License, Version 2.0 (the "License"); 6you may not use this file except in compliance with the License. 7You may obtain a copy of the License at 8 9 http://www.apache.org/licenses/LICENSE-2.0 10 11Unless required by applicable law or agreed to in writing, software 12distributed under the License is distributed on an "AS IS" BASIS, 13WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14See the License for the specific language governing permissions and 15limitations under the License. 16 17Description: Scenario test case. 18""" 19 20import logging 21import os 22import time 23 24import pytest 25 26from aw import Application 27from aw import Utils 28from aw import debugger, runtime 29from aw.api import debugger_api, runtime_api 30 31 32@pytest.mark.debug 33@pytest.mark.timeout(30) 34class TestDebug01: 35 """ 36 测试用例:多实例 debug 调试 37 测试步骤: 38 1. 连接 connect server 和主线程 debugger server 39 2. 主线程使能 Runtime 和 Debugger 40 3. 主线程 Index.ts 文件设置断点(Debugger.getPossibleAndSetBreakpointByUrl) 41 4. 主线程 stepOut,暂停在下一断点(Debugger.stepOut) 42 5. 创建第一个子线程,连接子线程 debugger server 43 6. 主线程 resume,暂停在下一断点(Debugger.resume) 44 7. 创建另一个子线程,连接子线程 debugger server 45 8. 所有子线程使能 Runtime 和 Debugger 46 9. 所有子线程 Worker.ts 文件设置断点(Debugger.getPossibleAndSetBreakpointByUrl) 47 10. 触发点击事件,主线程命中断点 48 11. 销毁其中一个子线程 49 12. 主线程 stepInto,暂停在下一行(Debugger.stepInto) 50 13. 主线程 getProperties,返回给定对象的属性(Runtime.getProperties) 51 14. 主线程 resume,暂停在下一断点(Debugger.resume) 52 15. 重新创建一个子线程,使能并设置断点 53 16. 主线程 resume,发送消息给子线程,主线程暂停在下一断点(Debugger.resume) 54 17. 子线程命中断点后 getProperties(Runtime.getProperties) 55 18. 子线程 stepOut 发消息给主线程(Debugger.stepOut) 56 19. 主线程 stepOver,发送消息给另一子线程,主线程暂停在下一行(Debugger.stepOver) 57 20. 子线程命中断点后 resume,发消息给主线程(Debugger.resume) 58 21. 销毁所有子线程,对应的 debugger server 连接断开 59 22. 关闭主线程 debugger server 和 connect server 连接 60 """ 61 62 def setup_method(self): 63 logging.info('Start running TestDebug01: setup') 64 65 self.log_path = rf'{os.path.dirname(__file__)}\..\log' 66 self.hilog_file_name = 'test_debug_01.hilog.txt' 67 self.id_generator = Utils.message_id_generator() 68 69 # receive the hilog before the test start 70 Utils.clear_fault_log() 71 self.hilog_process, self.write_thread = Utils.save_hilog(log_path=self.log_path, 72 file_name=self.hilog_file_name, 73 debug_on=True) 74 75 def teardown_method(self): 76 Application.uninstall(self.config['bundle_name']) 77 78 # terminate the hilog receive process after the test done 79 time.sleep(3) 80 self.hilog_process.stdout.close() 81 self.hilog_process.terminate() 82 self.hilog_process.wait() 83 self.write_thread.join() 84 85 Utils.save_fault_log(log_path=self.log_path) 86 logging.info('TestDebug01 done') 87 88 def test(self, test_suite_worker_01_debug): 89 logging.info('Start running TestDebug01: test') 90 self.config = test_suite_worker_01_debug 91 websocket = self.config['websocket'] 92 taskpool = self.config['taskpool'] 93 pid = self.config['pid'] 94 self.debugger_impl = debugger_api.DebuggerImpl(self.id_generator, websocket) 95 self.runtime_impl = runtime_api.RuntimeImpl(self.id_generator, websocket) 96 97 taskpool.submit(websocket.main_task(taskpool, self.procedure, pid)) 98 taskpool.await_taskpool() 99 taskpool.task_join() 100 if taskpool.task_exception: 101 raise taskpool.task_exception 102 103 async def procedure(self, websocket): 104 ################################################################################################################ 105 # main thread: connect the debugger server 106 ################################################################################################################ 107 main_thread = await self.debugger_impl.connect_to_debugger_server(self.config['pid'], True) 108 logging.info(f'Connect to the debugger server of instance: {main_thread.instance_id}') 109 ################################################################################################################ 110 # main thread: Runtime.enable 111 ################################################################################################################ 112 await self.runtime_impl.send("Runtime.enable", main_thread) 113 ################################################################################################################ 114 # main thread: Debugger.enable 115 ################################################################################################################ 116 await self.debugger_impl.send("Debugger.enable", main_thread) 117 ################################################################################################################ 118 # main thread: Runtime.runIfWaitingForDebugger 119 ################################################################################################################ 120 await self.runtime_impl.send("Runtime.runIfWaitingForDebugger", main_thread) 121 ################################################################################################################ 122 # main thread: Debugger.scriptParsed 123 ################################################################################################################ 124 response = await self.debugger_impl.recv("Debugger.scriptParsed", main_thread) 125 assert response['params']['url'] == self.config['file_path']['entry_ability'] 126 assert response['params']['endLine'] == 0 127 ################################################################################################################ 128 # main thread: Debugger.paused 129 ################################################################################################################ 130 response = await self.debugger_impl.recv("Debugger.paused", main_thread) 131 assert response['params']['callFrames'][0]['url'] == self.config['file_path']['entry_ability'] 132 assert response['params']['reason'] == 'Break on start' 133 ################################################################################################################ 134 # main thread: Debugger.resume 135 ################################################################################################################ 136 await self.debugger_impl.send("Debugger.resume", main_thread) 137 ################################################################################################################ 138 # main thread: Debugger.scriptParsed 139 ################################################################################################################ 140 response = await self.debugger_impl.recv("Debugger.scriptParsed", main_thread) 141 assert response['params']['url'] == self.config['file_path']['index'] 142 assert response['params']['endLine'] == 0 143 ################################################################################################################ 144 # main thread: Debugger.paused 145 ################################################################################################################ 146 response = await self.debugger_impl.recv("Debugger.paused", main_thread) 147 assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index'] 148 assert response['params']['reason'] == 'Break on start' 149 ################################################################################################################ 150 # main thread: Debugger.removeBreakpointsByUrl 151 ################################################################################################################ 152 params = debugger.RemoveBreakpointsUrl(self.config['file_path']['index']) 153 await self.debugger_impl.send("Debugger.removeBreakpointsByUrl", main_thread, params) 154 ################################################################################################################ 155 # main thread: Debugger.getPossibleAndSetBreakpointByUrl 156 ################################################################################################################ 157 locations = [debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=12), 158 debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=53), 159 debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=57)] 160 params = debugger.SetBreakpointsLocations(locations) 161 response = await self.debugger_impl.send("Debugger.getPossibleAndSetBreakpointsByUrl", 162 main_thread, params) 163 assert response['result']['locations'][0]['id'] == 'id:12:0:' + self.config['file_path']['index'] 164 assert response['result']['locations'][1]['id'] == 'id:53:0:' + self.config['file_path']['index'] 165 assert response['result']['locations'][2]['id'] == 'id:57:0:' + self.config['file_path']['index'] 166 ################################################################################################################ 167 # main thread: Debugger.resume 168 ################################################################################################################ 169 await self.debugger_impl.send("Debugger.resume", main_thread) 170 ################################################################################################################ 171 # main thread: Debugger.paused, hit breakpoint 172 ################################################################################################################ 173 response = await self.debugger_impl.recv("Debugger.paused", main_thread) 174 assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index'] 175 assert response['params']['hitBreakpoints'] == ['id:12:4:' + self.config['file_path']['index']] 176 ################################################################################################################ 177 # main thread: Debugger.stepOut 178 ################################################################################################################ 179 await self.debugger_impl.send("Debugger.stepOut", main_thread) 180 response = await self.debugger_impl.recv("Debugger.paused", main_thread) 181 assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index'] 182 assert response['params']['hitBreakpoints'] == ['id:12:4:' + self.config['file_path']['index']] 183 ################################################################################################################ 184 # worker thread: connect the debugger server 185 ################################################################################################################ 186 worker_thread_1 = await self.debugger_impl.connect_to_debugger_server(self.config['pid'], False) 187 logging.info(f'Connect to the debugger server of instance: {worker_thread_1.instance_id}') 188 ################################################################################################################ 189 # main thread: Debugger.resume 190 ################################################################################################################ 191 await self.debugger_impl.send("Debugger.resume", main_thread) 192 ################################################################################################################ 193 # worker thread: connect the debugger server 194 ################################################################################################################ 195 worker_thread_2 = await self.debugger_impl.connect_to_debugger_server(self.config['pid'], False) 196 logging.info(f'Connect to the debugger server of instance: {worker_thread_2.instance_id}') 197 ################################################################################################################ 198 # worker thread: Runtime.enable 199 ################################################################################################################ 200 await self.runtime_impl.send("Runtime.enable", worker_thread_1) 201 await self.runtime_impl.send("Runtime.enable", worker_thread_2) 202 ################################################################################################################ 203 # worker thread: Debugger.enable 204 ################################################################################################################ 205 await self.debugger_impl.send("Debugger.enable", worker_thread_1) 206 await self.debugger_impl.send("Debugger.enable", worker_thread_2) 207 ################################################################################################################ 208 # worker thread: Runtime.runIfWaitingForDebugger 209 ################################################################################################################ 210 # worker thread 1: Runtime.runIfWaitingForDebugger 211 await self.runtime_impl.send("Runtime.runIfWaitingForDebugger", worker_thread_1) 212 # worker thread 1: Debugger.scriptParsed 213 response = await self.debugger_impl.recv("Debugger.scriptParsed", worker_thread_1) 214 assert response['params']['url'] == self.config['file_path']['worker'] 215 assert response['params']['endLine'] == 0 216 # worker thread 1: Debugger.paused 217 response = await self.debugger_impl.recv("Debugger.paused", worker_thread_1) 218 assert response['params']['callFrames'][0]['url'] == self.config['file_path']['worker'] 219 assert response['params']['reason'] == 'Break on start' 220 # worker thread 2: Runtime.runIfWaitingForDebugger 221 await self.runtime_impl.send("Runtime.runIfWaitingForDebugger", worker_thread_2) 222 # worker thread 2: Debugger.scriptParsed 223 response = await self.debugger_impl.recv("Debugger.scriptParsed", worker_thread_2) 224 assert response['params']['url'] == self.config['file_path']['worker'] 225 assert response['params']['endLine'] == 0 226 # worker thread 2: Debugger.paused 227 response = await self.debugger_impl.recv("Debugger.paused", worker_thread_2) 228 assert response['params']['callFrames'][0]['url'] == self.config['file_path']['worker'] 229 assert response['params']['reason'] == 'Break on start' 230 ################################################################################################################ 231 # worker thread: Debugger.removeBreakpointsByUrl 232 ################################################################################################################ 233 params = debugger.RemoveBreakpointsUrl(self.config['file_path']['worker']) 234 await self.debugger_impl.send("Debugger.removeBreakpointsByUrl", worker_thread_1, params) 235 await self.debugger_impl.send("Debugger.removeBreakpointsByUrl", worker_thread_2, params) 236 ################################################################################################################ 237 # worker thread: Debugger.getPossibleAndSetBreakpointByUrl 238 ################################################################################################################ 239 locations = [debugger.BreakLocationUrl(url=self.config['file_path']['worker'], line_number=11)] 240 params = debugger.SetBreakpointsLocations(locations) 241 response = await self.debugger_impl.send("Debugger.getPossibleAndSetBreakpointsByUrl", 242 worker_thread_1, params) 243 assert response['result']['locations'][0]['id'] == 'id:11:0:' + self.config['file_path']['worker'] 244 response = await self.debugger_impl.send("Debugger.getPossibleAndSetBreakpointsByUrl", 245 worker_thread_2, params) 246 assert response['result']['locations'][0]['id'] == 'id:11:0:' + self.config['file_path']['worker'] 247 ################################################################################################################ 248 # worker thread: Debugger.resume 249 ################################################################################################################ 250 await self.debugger_impl.send("Debugger.resume", worker_thread_1) 251 await self.debugger_impl.send("Debugger.resume", worker_thread_2) 252 ################################################################################################################ 253 # main thread: click on the screen 254 ################################################################################################################ 255 Application.click_on_middle() 256 ################################################################################################################ 257 # main thread: Debugger.paused, hit breakpoint 258 ################################################################################################################ 259 response = await self.debugger_impl.recv("Debugger.paused", main_thread) 260 assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index'] 261 assert response['params']['hitBreakpoints'] == ['id:53:16:' + self.config['file_path']['index']] 262 ################################################################################################################ 263 # worker thread: destroy instance 264 ################################################################################################################ 265 # worker thread 2 destroyed 266 response = await self.debugger_impl.destroy_instance() 267 assert response['instanceId'] == worker_thread_2.instance_id 268 ################################################################################################################ 269 # main thread: Debugger.stepInto 270 ################################################################################################################ 271 await self.debugger_impl.send("Debugger.stepInto", main_thread) 272 await self.debugger_impl.recv("Debugger.paused", main_thread) 273 ################################################################################################################ 274 # main thread: Runtime.getProperties 275 ################################################################################################################ 276 params = runtime.GetPropertiesParams('0', True, False, True) 277 response = await self.runtime_impl.send("Runtime.getProperties", main_thread, params) 278 assert response['result']['result'][0]['name'] == 'set message' 279 assert response['result']['result'][0]['value']['type'] == 'function' 280 assert response['result']['result'][1]['name'] == 'newValue' 281 assert response['result']['result'][1]['value']['type'] == 'string' 282 ################################################################################################################ 283 # main thread: Debugger.resume 284 ################################################################################################################ 285 await self.debugger_impl.send("Debugger.resume", main_thread) 286 ################################################################################################################ 287 # main thread: Debugger.paused, hit breakpoint 288 ################################################################################################################ 289 response = await self.debugger_impl.recv("Debugger.paused", main_thread) 290 assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index'] 291 assert response['params']['hitBreakpoints'] == ['id:57:20:' + self.config['file_path']['index']] 292 ################################################################################################################ 293 # worker thread: connect the debugger server 294 ################################################################################################################ 295 worker_thread_2 = await self.debugger_impl.connect_to_debugger_server(self.config['pid'], False) 296 logging.info(f'Connect to the debugger server of instance: {worker_thread_2.instance_id}') 297 ################################################################################################################ 298 # worker thread: Runtime.enable 299 ################################################################################################################ 300 await self.runtime_impl.send("Runtime.enable", worker_thread_2) 301 ################################################################################################################ 302 # worker thread: Debugger.enable 303 ################################################################################################################ 304 await self.debugger_impl.send("Debugger.enable", worker_thread_2) 305 ################################################################################################################ 306 # worker thread: Runtime.runIfWaitingForDebugger 307 ################################################################################################################ 308 await self.runtime_impl.send("Runtime.runIfWaitingForDebugger", worker_thread_2) 309 # worker thread: Debugger.scriptParsed 310 response = await self.debugger_impl.recv("Debugger.scriptParsed", worker_thread_2) 311 assert response['params']['url'] == self.config['file_path']['worker'] 312 assert response['params']['endLine'] == 0 313 # worker thread: Debugger.paused 314 response = await self.debugger_impl.recv("Debugger.paused", worker_thread_2) 315 assert response['params']['callFrames'][0]['url'] == self.config['file_path']['worker'] 316 assert response['params']['reason'] == 'Break on start' 317 ################################################################################################################ 318 # worker thread: Debugger.removeBreakpointsByUrl 319 ################################################################################################################ 320 params = debugger.RemoveBreakpointsUrl(self.config['file_path']['worker']) 321 await self.debugger_impl.send("Debugger.removeBreakpointsByUrl", worker_thread_2, params) 322 ################################################################################################################ 323 # worker thread: Debugger.getPossibleAndSetBreakpointByUrl 324 ################################################################################################################ 325 locations = [debugger.BreakLocationUrl(url=self.config['file_path']['worker'], line_number=11)] 326 params = debugger.SetBreakpointsLocations(locations) 327 response = await self.debugger_impl.send("Debugger.getPossibleAndSetBreakpointsByUrl", 328 worker_thread_2, params) 329 assert response['result']['locations'][0]['id'] == 'id:11:0:' + self.config['file_path']['worker'] 330 ################################################################################################################ 331 # worker thread: Debugger.resume 332 ################################################################################################################ 333 await self.debugger_impl.send("Debugger.resume", worker_thread_2) 334 ################################################################################################################ 335 # main thread: Debugger.stepOut 336 ################################################################################################################ 337 await self.debugger_impl.send("Debugger.stepOut", main_thread) 338 # main thread: Debugger.paused 339 response = await self.debugger_impl.recv("Debugger.paused", main_thread) 340 assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index'] 341 assert response['params']['reason'] == 'other' 342 assert response['params']['hitBreakpoints'] == ['id:57:20:' + self.config['file_path']['index']] 343 # worker thread: Debugger.paused 344 response = await self.debugger_impl.recv("Debugger.paused", worker_thread_1) 345 assert response['params']['callFrames'][0]['url'] == self.config['file_path']['worker'] 346 assert response['params']['reason'] == 'other' 347 assert response['params']['hitBreakpoints'] == ['id:11:4:' + self.config['file_path']['worker']] 348 ################################################################################################################ 349 # worker thread: Runtime.getProperties 350 ################################################################################################################ 351 params = runtime.GetPropertiesParams('0', True, False, True) 352 response = await self.runtime_impl.send("Runtime.getProperties", worker_thread_1, params) 353 assert response['result']['result'][0]['name'] == '' 354 assert response['result']['result'][0]['value']['type'] == 'function' 355 assert response['result']['result'][1]['name'] == 'e' 356 assert response['result']['result'][1]['value']['type'] == 'object' 357 ################################################################################################################ 358 # worker thread: Debugger.stepOut 359 ################################################################################################################ 360 await self.debugger_impl.send("Debugger.stepOut", worker_thread_1) 361 ################################################################################################################ 362 # worker thread: Debugger.disable 363 ################################################################################################################ 364 await self.debugger_impl.send("Debugger.disable", worker_thread_1) 365 ################################################################################################################ 366 # main thread: Debugger.stepInto 367 ################################################################################################################ 368 await self.debugger_impl.send("Debugger.stepInto", main_thread) 369 # main thread: Debugger.paused 370 response = await self.debugger_impl.recv("Debugger.paused", main_thread) 371 assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index'] 372 assert response['params']['reason'] == 'other' 373 assert response['params']['hitBreakpoints'] == [] 374 # worker thread: Debugger.paused 375 response = await self.debugger_impl.recv("Debugger.paused", worker_thread_2) 376 assert response['params']['callFrames'][0]['url'] == self.config['file_path']['worker'] 377 assert response['params']['reason'] == 'other' 378 assert response['params']['hitBreakpoints'] == ['id:11:4:' + self.config['file_path']['worker']] 379 ################################################################################################################ 380 # worker thread: Debugger.resume 381 ################################################################################################################ 382 await self.debugger_impl.send("Debugger.resume", worker_thread_2) 383 ################################################################################################################ 384 # worker thread: Debugger.disable 385 ################################################################################################################ 386 await self.debugger_impl.send("Debugger.disable", worker_thread_2) 387 ################################################################################################################ 388 # main thread: Debugger.resume 389 ################################################################################################################ 390 await self.debugger_impl.send("Debugger.resume", main_thread) 391 ################################################################################################################ 392 # worker thread: destroy instance 393 ################################################################################################################ 394 response = await self.debugger_impl.destroy_instance() 395 assert response['instanceId'] != self.config['pid'] 396 response = await self.debugger_impl.destroy_instance() 397 assert response['instanceId'] != self.config['pid'] 398 ################################################################################################################ 399 # main thread: Debugger.disable 400 ################################################################################################################ 401 await self.debugger_impl.send("Debugger.disable", main_thread) 402 ################################################################################################################ 403 # close the websocket connections 404 ################################################################################################################ 405 await websocket.send_msg_to_debugger_server(main_thread.instance_id, main_thread.send_msg_queue, 'close') 406 await websocket.send_msg_to_connect_server('close') 407 ################################################################################################################