• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
29from aw.api import debugger_api, runtime_api
30
31
32@pytest.mark.debug
33@pytest.mark.timeout(60)
34class TestWorkerExceptionBreakpoints01:
35    """
36    测试用例:多实例 debug 调试异常断点 ALL 和 NONE 模式
37    测试步骤:
38        1.  连接 connect server 和主线程 debugger server
39        2.  主线程使能 Runtime 和 Debugger
40        3.  主线程 Index.ts 文件设置断点(Debugger.getPossibleAndSetBreakpointByUrl)
41        4.  主线程 resume,停在断点处(Debugger.resume)
42        5.  创建子线程1,连接 debugger server
43        6.  主线程 resume,停在断点处(Debugger.resume)
44        7.  创建子线程2,连接 debugger server
45        8.  所有子线程使能 Runtime 和 Debugger
46        9.  子线程1设置异常断点类型为 ALL(Debugger.setPauseOnExceptions)
47        10. 主线程 resume,停在断点处,子线程1停在第一个异常处(Debugger.resume)
48        11. 子线程1 resume,停在第二个异常断点处(Debugger.resume)
49        12. 子线程1 resume,抛出异常
50        13. 子线程2设置异常断点类型为 NONE(Debugger.setPauseOnExceptions)
51        14. 主线程 resume,子线程2抛出异常
52        15. 关闭所有线程 debugger server 和 connect server 连接
53    关键代码:
54        Index.ets
55            let workerIndex = 0
56            function newWorker() {} // 创建一个子线程, workerIndex++
57            function terminateWorker() {} // 销毁一个子线程, workerIndex--
58            for (let i = 0; i < 2; i++) {
59                newWorker()
60            }
61            for (let i = 0; i < workerIndex; i++) {
62                workers[i].postMessage("hello world")
63            }
64        Worker.ets
65            const workerPort: ThreadWorkerGlobalScope = worker.workerPort;
66            workerPort.onmessage = (e: MessageEvents) => {
67                workerPort.postMessage(e.data)
68                try {
69                    throw new Error('[worker] caught error')
70                } catch (e) {
71                    console.info('[worker] caught error')
72                }
73                throw new Error('[worker] uncaught error')
74            }
75    """
76
77    def setup_method(self):
78        logging.info('Start running TestWorkerExceptionBreakpoints01: setup')
79
80        self.log_path = rf'{os.path.dirname(__file__)}\..\log'
81        self.hilog_file_name = 'test_worker_exception_breakpoints_01.hilog.txt'
82        self.id_generator = Utils.message_id_generator()
83
84        # receive the hilog before the test start
85        Utils.clear_fault_log()
86        self.hilog_process, self.write_thread = Utils.save_hilog(log_path=self.log_path,
87                                                                 file_name=self.hilog_file_name,
88                                                                 debug_on=True)
89
90    def teardown_method(self):
91        Application.uninstall(self.config['bundle_name'])
92
93        # terminate the hilog receive process after the test done
94        time.sleep(3)
95        self.hilog_process.stdout.close()
96        self.hilog_process.terminate()
97        self.hilog_process.wait()
98        self.write_thread.join()
99
100        Utils.save_fault_log(log_path=self.log_path)
101        logging.info('TestWorkerExceptionBreakpoints01 done')
102
103    def test(self, test_suite_worker_03_debug):
104        logging.info('Start running TestWorkerExceptionBreakpoints01: test')
105        self.config = test_suite_worker_03_debug
106        websocket = self.config['websocket']
107        taskpool = self.config['taskpool']
108        pid = self.config['pid']
109        self.debugger_impl = debugger_api.DebuggerImpl(self.id_generator, websocket)
110        self.runtime_impl = runtime_api.RuntimeImpl(self.id_generator, websocket)
111
112        taskpool.submit(websocket.main_task(taskpool, self.procedure, pid))
113        taskpool.await_taskpool()
114        taskpool.task_join()
115        if taskpool.task_exception:
116            raise taskpool.task_exception
117
118    async def procedure(self, websocket):
119        ################################################################################################################
120        # main thread: connect the debugger server
121        ################################################################################################################
122        main_thread = await self.debugger_impl.connect_to_debugger_server(self.config['pid'], True)
123        logging.info(f'Connect to the debugger server of instance: {main_thread.instance_id}')
124        ################################################################################################################
125        # main thread: Runtime.enable
126        ################################################################################################################
127        await self.runtime_impl.send("Runtime.enable", main_thread)
128        ################################################################################################################
129        # main thread: Debugger.enable
130        ################################################################################################################
131        await self.debugger_impl.send("Debugger.enable", main_thread)
132        ################################################################################################################
133        # main thread: Runtime.runIfWaitingForDebugger
134        ################################################################################################################
135        await self.runtime_impl.send("Runtime.runIfWaitingForDebugger", main_thread)
136        ################################################################################################################
137        # main thread: Debugger.scriptParsed
138        ################################################################################################################
139        response = await self.debugger_impl.recv("Debugger.scriptParsed", main_thread)
140        assert response['params']['url'] == self.config['file_path']['entry_ability']
141        assert response['params']['endLine'] == 0
142        ################################################################################################################
143        # main thread: Debugger.paused
144        ################################################################################################################
145        response = await self.debugger_impl.recv("Debugger.paused", main_thread)
146        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['entry_ability']
147        assert response['params']['reason'] == 'Break on start'
148        ################################################################################################################
149        # main thread: Debugger.resume
150        ################################################################################################################
151        await self.debugger_impl.send("Debugger.resume", main_thread)
152        ################################################################################################################
153        # main thread: Debugger.scriptParsed
154        ################################################################################################################
155        response = await self.debugger_impl.recv("Debugger.scriptParsed", main_thread)
156        assert response['params']['url'] == self.config['file_path']['index']
157        assert response['params']['endLine'] == 0
158        ################################################################################################################
159        # main thread: Debugger.paused
160        ################################################################################################################
161        response = await self.debugger_impl.recv("Debugger.paused", main_thread)
162        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index']
163        assert response['params']['reason'] == 'Break on start'
164        ################################################################################################################
165        # main thread: Debugger.removeBreakpointsByUrl
166        ################################################################################################################
167        params = debugger.RemoveBreakpointsUrl(self.config['file_path']['index'])
168        await self.debugger_impl.send("Debugger.removeBreakpointsByUrl", main_thread, params)
169        ################################################################################################################
170        # main thread: Debugger.getPossibleAndSetBreakpointByUrl
171        ################################################################################################################
172        locations = [debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=16),
173                     debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=84)]
174        params = debugger.SetBreakpointsLocations(locations)
175        response = await self.debugger_impl.send("Debugger.getPossibleAndSetBreakpointsByUrl",
176                                                 main_thread, params)
177        assert response['result']['locations'][0]['id'] == 'id:16:0:' + self.config['file_path']['index']
178        assert response['result']['locations'][1]['id'] == 'id:84:0:' + self.config['file_path']['index']
179        ################################################################################################################
180        # main thread: Debugger.resume
181        ################################################################################################################
182        await self.debugger_impl.send("Debugger.resume", main_thread)
183        ################################################################################################################
184        # main thread: Debugger.paused, hit breakpoint
185        ################################################################################################################
186        response = await self.debugger_impl.recv("Debugger.paused", main_thread)
187        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index']
188        assert response['params']['hitBreakpoints'] == ['id:84:1:' + self.config['file_path']['index']]
189        ################################################################################################################
190        # worker thread: connect the debugger server
191        ################################################################################################################
192        worker_thread_1 = await self.debugger_impl.connect_to_debugger_server(self.config['pid'], False)
193        logging.info(f'Connect to the debugger server of instance: {worker_thread_1.instance_id}')
194        ################################################################################################################
195        # main thread: Debugger.resume
196        ################################################################################################################
197        await self.debugger_impl.send("Debugger.resume", main_thread)
198        # main thread: Debugger.paused
199        response = await self.debugger_impl.recv("Debugger.paused", main_thread)
200        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index']
201        assert response['params']['hitBreakpoints'] == ['id:84:1:' + self.config['file_path']['index']]
202        ################################################################################################################
203        # worker thread: connect the debugger server
204        ################################################################################################################
205        worker_thread_2 = await self.debugger_impl.connect_to_debugger_server(self.config['pid'], False)
206        logging.info(f'Connect to the debugger server of instance: {worker_thread_2.instance_id}')
207        ################################################################################################################
208        # worker thread: Runtime.enable
209        ################################################################################################################
210        await self.runtime_impl.send("Runtime.enable", worker_thread_1)
211        await self.runtime_impl.send("Runtime.enable", worker_thread_2)
212        ################################################################################################################
213        # worker thread: Debugger.enable
214        ################################################################################################################
215        await self.debugger_impl.send("Debugger.enable", worker_thread_1)
216        await self.debugger_impl.send("Debugger.enable", worker_thread_2)
217        ################################################################################################################
218        # worker thread: Runtime.runIfWaitingForDebugger
219        ################################################################################################################
220        # worker thread 1: Runtime.runIfWaitingForDebugger
221        await self.runtime_impl.send("Runtime.runIfWaitingForDebugger", worker_thread_1)
222        # worker thread 1: Debugger.scriptParsed
223        response = await self.debugger_impl.recv("Debugger.scriptParsed", worker_thread_1)
224        assert response['params']['url'] == self.config['file_path']['worker']
225        assert response['params']['endLine'] == 0
226        # worker thread 1: Debugger.paused
227        response = await self.debugger_impl.recv("Debugger.paused", worker_thread_1)
228        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['worker']
229        assert response['params']['reason'] == 'Break on start'
230        # worker thread 2: Runtime.runIfWaitingForDebugger
231        await self.runtime_impl.send("Runtime.runIfWaitingForDebugger", worker_thread_2)
232        # worker thread 2: Debugger.scriptParsed
233        response = await self.debugger_impl.recv("Debugger.scriptParsed", worker_thread_2)
234        assert response['params']['url'] == self.config['file_path']['worker']
235        assert response['params']['endLine'] == 0
236        # worker thread 2: Debugger.paused
237        response = await self.debugger_impl.recv("Debugger.paused", worker_thread_2)
238        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['worker']
239        assert response['params']['reason'] == 'Break on start'
240        ################################################################################################################
241        # worker thread: Debugger.resume
242        ################################################################################################################
243        await self.debugger_impl.send("Debugger.resume", worker_thread_1)
244        await self.debugger_impl.send("Debugger.resume", worker_thread_2)
245        ################################################################################################################
246        # worker thread: Debugger.setPauseOnExceptions
247        ################################################################################################################
248        params = debugger.PauseOnExceptionsState.ALL
249        await self.debugger_impl.send("Debugger.setPauseOnExceptions", worker_thread_1, params)
250        ################################################################################################################
251        # main thread: Debugger.resume
252        ################################################################################################################
253        await self.debugger_impl.send("Debugger.resume", main_thread)
254        # main thread: Debugger.paused
255        response = await self.debugger_impl.recv("Debugger.paused", main_thread)
256        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index']
257        assert response['params']['reason'] == 'other'
258        assert response['params']['hitBreakpoints'] == ['id:16:4:' + self.config['file_path']['index']]
259        # worker thread: Debugger.paused
260        response = await self.debugger_impl.recv("Debugger.paused", worker_thread_1)
261        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['worker']
262        assert response['params']['reason'] == 'exception'
263        assert 'caught error' in response['params']['data']['description']
264        ################################################################################################################
265        # worker thread: Debugger.resume
266        ################################################################################################################
267        await self.debugger_impl.send("Debugger.resume", worker_thread_1)
268        # worker thread: Debugger.paused
269        response = await self.debugger_impl.recv("Debugger.paused", worker_thread_1)
270        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['worker']
271        assert response['params']['reason'] == 'exception'
272        assert 'uncaught error' in response['params']['data']['description']
273        ################################################################################################################
274        # worker thread: Debugger.resume
275        ################################################################################################################
276        await self.debugger_impl.send("Debugger.resume", worker_thread_1)
277        ################################################################################################################
278        # worker thread: Debugger.setPauseOnExceptions
279        ################################################################################################################
280        params = debugger.PauseOnExceptionsState.NONE
281        await self.debugger_impl.send("Debugger.setPauseOnExceptions", worker_thread_2, params)
282        ################################################################################################################
283        # main thread: Debugger.resume
284        ################################################################################################################
285        await self.debugger_impl.send("Debugger.resume", main_thread)
286        ################################################################################################################
287        # close the websocket connections
288        ################################################################################################################
289        await websocket.send_msg_to_debugger_server(worker_thread_2.instance_id, worker_thread_2.send_msg_queue,
290                                                    'close')
291        await websocket.send_msg_to_debugger_server(worker_thread_1.instance_id, worker_thread_1.send_msg_queue,
292                                                    'close')
293        await websocket.send_msg_to_debugger_server(main_thread.instance_id, main_thread.send_msg_queue, 'close')
294        await websocket.send_msg_to_connect_server('close')
295        ################################################################################################################