• 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, runtime
29from aw.api import debugger_api, runtime_api
30
31
32@pytest.mark.debug
33@pytest.mark.timeout(60)
34class TestWorkerStep:
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. 主线程 stepOut,发送消息给子线程,主线程暂停在下一断点(Debugger.stepOut)
54        17. 子线程命中断点后 getProperties(Runtime.getProperties)
55        18. 子线程 stepOut 发消息给主线程(Debugger.stepOut)
56        19. 主线程 stepInto,发送消息给另一子线程,主线程暂停在下一行(Debugger.stepInto)
57        20. 子线程命中断点后 resume,发消息给主线程(Debugger.resume)
58        21. 销毁所有子线程,对应的 debugger server 连接断开
59        22. 关闭主线程 debugger server 和 connect server 连接
60    关键代码:
61        Index.ets
62            let workerIndex = 0
63            function newWorker() {} // 创建一个子线程, workerIndex++
64            function terminateWorker() {} // 销毁一个子线程, workerIndex--
65            for (let i = 0; i < 2; i++) {
66                newWorker()
67            }
68            .onClick(() => {
69                terminateWorker()
70                newWorker()
71                for (let i = 0; i < workerIndex; i++) {
72                    workers[i].postMessage("hello world")
73                }
74                while (workerIndex) {
75                    terminateWorker()
76                }
77            })
78        Worker.ets
79            const workerPort: ThreadWorkerGlobalScope = worker.workerPort;
80            workerPort.onmessage = (e: MessageEvents) => {
81                workerPort.postMessage(e.data);
82            }
83    """
84
85    def setup_method(self):
86        logging.info('Start running TestWorkerStep: setup')
87
88        self.log_path = rf'{os.path.dirname(__file__)}\..\log'
89        self.hilog_file_name = 'test_worker_step.hilog.txt'
90        self.id_generator = Utils.message_id_generator()
91
92        # receive the hilog before the test start
93        Utils.clear_fault_log()
94        self.hilog_process, self.write_thread = Utils.save_hilog(log_path=self.log_path,
95                                                                 file_name=self.hilog_file_name,
96                                                                 debug_on=True)
97
98    def teardown_method(self):
99        Application.uninstall(self.config['bundle_name'])
100
101        # terminate the hilog receive process after the test done
102        time.sleep(3)
103        self.hilog_process.stdout.close()
104        self.hilog_process.terminate()
105        self.hilog_process.wait()
106        self.write_thread.join()
107
108        Utils.save_fault_log(log_path=self.log_path)
109        logging.info('TestWorkerStep done')
110
111    def test(self, test_suite_worker_01_debug):
112        logging.info('Start running TestWorkerStep: test')
113        self.config = test_suite_worker_01_debug
114        websocket = self.config['websocket']
115        taskpool = self.config['taskpool']
116        pid = self.config['pid']
117        self.debugger_impl = debugger_api.DebuggerImpl(self.id_generator, websocket)
118        self.runtime_impl = runtime_api.RuntimeImpl(self.id_generator, websocket)
119
120        taskpool.submit(websocket.main_task(taskpool, self.procedure, pid))
121        taskpool.await_taskpool()
122        taskpool.task_join()
123        if taskpool.task_exception:
124            raise taskpool.task_exception
125
126    async def procedure(self, websocket):
127        ################################################################################################################
128        # main thread: connect the debugger server
129        ################################################################################################################
130        main_thread = await self.debugger_impl.connect_to_debugger_server(self.config['pid'], True)
131        logging.info(f'Connect to the debugger server of instance: {main_thread.instance_id}')
132        ################################################################################################################
133        # main thread: Runtime.enable
134        ################################################################################################################
135        await self.runtime_impl.send("Runtime.enable", main_thread)
136        ################################################################################################################
137        # main thread: Debugger.enable
138        ################################################################################################################
139        await self.debugger_impl.send("Debugger.enable", main_thread)
140        ################################################################################################################
141        # main thread: Runtime.runIfWaitingForDebugger
142        ################################################################################################################
143        await self.runtime_impl.send("Runtime.runIfWaitingForDebugger", main_thread)
144        ################################################################################################################
145        # main thread: Debugger.scriptParsed
146        ################################################################################################################
147        response = await self.debugger_impl.recv("Debugger.scriptParsed", main_thread)
148        assert response['params']['url'] == self.config['file_path']['entry_ability']
149        assert response['params']['endLine'] == 0
150        ################################################################################################################
151        # main thread: Debugger.paused
152        ################################################################################################################
153        response = await self.debugger_impl.recv("Debugger.paused", main_thread)
154        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['entry_ability']
155        assert response['params']['reason'] == 'Break on start'
156        ################################################################################################################
157        # main thread: Debugger.resume
158        ################################################################################################################
159        await self.debugger_impl.send("Debugger.resume", main_thread)
160        ################################################################################################################
161        # main thread: Debugger.scriptParsed
162        ################################################################################################################
163        response = await self.debugger_impl.recv("Debugger.scriptParsed", main_thread)
164        assert response['params']['url'] == self.config['file_path']['index']
165        assert response['params']['endLine'] == 0
166        ################################################################################################################
167        # main thread: Debugger.paused
168        ################################################################################################################
169        response = await self.debugger_impl.recv("Debugger.paused", main_thread)
170        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index']
171        assert response['params']['reason'] == 'Break on start'
172        ################################################################################################################
173        # main thread: Debugger.removeBreakpointsByUrl
174        ################################################################################################################
175        params = debugger.RemoveBreakpointsUrl(self.config['file_path']['index'])
176        await self.debugger_impl.send("Debugger.removeBreakpointsByUrl", main_thread, params)
177        ################################################################################################################
178        # main thread: Debugger.getPossibleAndSetBreakpointByUrl
179        ################################################################################################################
180        locations = [debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=12),
181                     debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=53),
182                     debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=57)]
183        params = debugger.SetBreakpointsLocations(locations)
184        response = await self.debugger_impl.send("Debugger.getPossibleAndSetBreakpointsByUrl",
185                                                 main_thread, params)
186        assert response['result']['locations'][0]['id'] == 'id:12:0:' + self.config['file_path']['index']
187        assert response['result']['locations'][1]['id'] == 'id:53:0:' + self.config['file_path']['index']
188        assert response['result']['locations'][2]['id'] == 'id:57:0:' + self.config['file_path']['index']
189        ################################################################################################################
190        # main thread: Debugger.resume
191        ################################################################################################################
192        await self.debugger_impl.send("Debugger.resume", main_thread)
193        ################################################################################################################
194        # main thread: Debugger.paused, hit breakpoint
195        ################################################################################################################
196        response = await self.debugger_impl.recv("Debugger.paused", main_thread)
197        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index']
198        assert response['params']['hitBreakpoints'] == ['id:12:4:' + self.config['file_path']['index']]
199        ################################################################################################################
200        # main thread: Debugger.stepOut
201        ################################################################################################################
202        await self.debugger_impl.send("Debugger.stepOut", main_thread)
203        response = await self.debugger_impl.recv("Debugger.paused", main_thread)
204        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index']
205        assert response['params']['hitBreakpoints'] == ['id:12:4:' + self.config['file_path']['index']]
206        ################################################################################################################
207        # worker thread: connect the debugger server
208        ################################################################################################################
209        worker_thread_1 = await self.debugger_impl.connect_to_debugger_server(self.config['pid'], False)
210        logging.info(f'Connect to the debugger server of instance: {worker_thread_1.instance_id}')
211        ################################################################################################################
212        # main thread: Debugger.resume
213        ################################################################################################################
214        await self.debugger_impl.send("Debugger.resume", main_thread)
215        ################################################################################################################
216        # worker thread: connect the debugger server
217        ################################################################################################################
218        worker_thread_2 = await self.debugger_impl.connect_to_debugger_server(self.config['pid'], False)
219        logging.info(f'Connect to the debugger server of instance: {worker_thread_2.instance_id}')
220        ################################################################################################################
221        # worker thread: Runtime.enable
222        ################################################################################################################
223        await self.runtime_impl.send("Runtime.enable", worker_thread_1)
224        await self.runtime_impl.send("Runtime.enable", worker_thread_2)
225        ################################################################################################################
226        # worker thread: Debugger.enable
227        ################################################################################################################
228        await self.debugger_impl.send("Debugger.enable", worker_thread_1)
229        await self.debugger_impl.send("Debugger.enable", worker_thread_2)
230        ################################################################################################################
231        # worker thread: Runtime.runIfWaitingForDebugger
232        ################################################################################################################
233        # worker thread 1: Runtime.runIfWaitingForDebugger
234        await self.runtime_impl.send("Runtime.runIfWaitingForDebugger", worker_thread_1)
235        # worker thread 1: Debugger.scriptParsed
236        response = await self.debugger_impl.recv("Debugger.scriptParsed", worker_thread_1)
237        assert response['params']['url'] == self.config['file_path']['worker']
238        assert response['params']['endLine'] == 0
239        # worker thread 1: Debugger.paused
240        response = await self.debugger_impl.recv("Debugger.paused", worker_thread_1)
241        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['worker']
242        assert response['params']['reason'] == 'Break on start'
243        # worker thread 2: Runtime.runIfWaitingForDebugger
244        await self.runtime_impl.send("Runtime.runIfWaitingForDebugger", worker_thread_2)
245        # worker thread 2: Debugger.scriptParsed
246        response = await self.debugger_impl.recv("Debugger.scriptParsed", worker_thread_2)
247        assert response['params']['url'] == self.config['file_path']['worker']
248        assert response['params']['endLine'] == 0
249        # worker thread 2: Debugger.paused
250        response = await self.debugger_impl.recv("Debugger.paused", worker_thread_2)
251        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['worker']
252        assert response['params']['reason'] == 'Break on start'
253        ################################################################################################################
254        # worker thread: Debugger.removeBreakpointsByUrl
255        ################################################################################################################
256        params = debugger.RemoveBreakpointsUrl(self.config['file_path']['worker'])
257        await self.debugger_impl.send("Debugger.removeBreakpointsByUrl", worker_thread_1, params)
258        await self.debugger_impl.send("Debugger.removeBreakpointsByUrl", worker_thread_2, params)
259        ################################################################################################################
260        # worker thread: Debugger.getPossibleAndSetBreakpointByUrl
261        ################################################################################################################
262        locations = [debugger.BreakLocationUrl(url=self.config['file_path']['worker'], line_number=11)]
263        params = debugger.SetBreakpointsLocations(locations)
264        response = await self.debugger_impl.send("Debugger.getPossibleAndSetBreakpointsByUrl",
265                                                 worker_thread_1, params)
266        assert response['result']['locations'][0]['id'] == 'id:11:0:' + self.config['file_path']['worker']
267        response = await self.debugger_impl.send("Debugger.getPossibleAndSetBreakpointsByUrl",
268                                                 worker_thread_2, params)
269        assert response['result']['locations'][0]['id'] == 'id:11:0:' + self.config['file_path']['worker']
270        ################################################################################################################
271        # worker thread: Debugger.resume
272        ################################################################################################################
273        await self.debugger_impl.send("Debugger.resume", worker_thread_1)
274        await self.debugger_impl.send("Debugger.resume", worker_thread_2)
275        ################################################################################################################
276        # main thread: click on the screen
277        ################################################################################################################
278        Application.click_on_middle()
279        ################################################################################################################
280        # main thread: Debugger.paused, hit breakpoint
281        ################################################################################################################
282        response = await self.debugger_impl.recv("Debugger.paused", main_thread)
283        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index']
284        assert response['params']['hitBreakpoints'] == ['id:53:16:' + self.config['file_path']['index']]
285        ################################################################################################################
286        # worker thread: destroy instance
287        ################################################################################################################
288        # worker thread 2 destroyed
289        response = await self.debugger_impl.destroy_instance()
290        assert response['instanceId'] == worker_thread_2.instance_id
291        ################################################################################################################
292        # main thread: Debugger.stepInto
293        ################################################################################################################
294        await self.debugger_impl.send("Debugger.stepInto", main_thread)
295        await self.debugger_impl.recv("Debugger.paused", main_thread)
296        ################################################################################################################
297        # main thread: Runtime.getProperties
298        ################################################################################################################
299        params = runtime.GetPropertiesParams('0', True, False, True)
300        response = await self.runtime_impl.send("Runtime.getProperties", main_thread, params)
301        assert response['result']['result'][0]['name'] == 'set message'
302        assert response['result']['result'][0]['value']['type'] == 'function'
303        assert response['result']['result'][1]['name'] == 'newValue'
304        assert response['result']['result'][1]['value']['type'] == 'string'
305        ################################################################################################################
306        # main thread: Debugger.resume
307        ################################################################################################################
308        await self.debugger_impl.send("Debugger.resume", main_thread)
309        ################################################################################################################
310        # main thread: Debugger.paused, hit breakpoint
311        ################################################################################################################
312        response = await self.debugger_impl.recv("Debugger.paused", main_thread)
313        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index']
314        assert response['params']['hitBreakpoints'] == ['id:57:20:' + self.config['file_path']['index']]
315        ################################################################################################################
316        # worker thread: connect the debugger server
317        ################################################################################################################
318        worker_thread_2 = await self.debugger_impl.connect_to_debugger_server(self.config['pid'], False)
319        logging.info(f'Connect to the debugger server of instance: {worker_thread_2.instance_id}')
320        ################################################################################################################
321        # worker thread: Runtime.enable
322        ################################################################################################################
323        await self.runtime_impl.send("Runtime.enable", worker_thread_2)
324        ################################################################################################################
325        # worker thread: Debugger.enable
326        ################################################################################################################
327        await self.debugger_impl.send("Debugger.enable", worker_thread_2)
328        ################################################################################################################
329        # worker thread: Runtime.runIfWaitingForDebugger
330        ################################################################################################################
331        await self.runtime_impl.send("Runtime.runIfWaitingForDebugger", worker_thread_2)
332        # worker thread: Debugger.scriptParsed
333        response = await self.debugger_impl.recv("Debugger.scriptParsed", worker_thread_2)
334        assert response['params']['url'] == self.config['file_path']['worker']
335        assert response['params']['endLine'] == 0
336        # worker thread: Debugger.paused
337        response = await self.debugger_impl.recv("Debugger.paused", worker_thread_2)
338        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['worker']
339        assert response['params']['reason'] == 'Break on start'
340        ################################################################################################################
341        # worker thread: Debugger.removeBreakpointsByUrl
342        ################################################################################################################
343        params = debugger.RemoveBreakpointsUrl(self.config['file_path']['worker'])
344        await self.debugger_impl.send("Debugger.removeBreakpointsByUrl", worker_thread_2, params)
345        ################################################################################################################
346        # worker thread: Debugger.getPossibleAndSetBreakpointByUrl
347        ################################################################################################################
348        locations = [debugger.BreakLocationUrl(url=self.config['file_path']['worker'], line_number=11)]
349        params = debugger.SetBreakpointsLocations(locations)
350        response = await self.debugger_impl.send("Debugger.getPossibleAndSetBreakpointsByUrl",
351                                                 worker_thread_2, params)
352        assert response['result']['locations'][0]['id'] == 'id:11:0:' + self.config['file_path']['worker']
353        ################################################################################################################
354        # worker thread: Debugger.resume
355        ################################################################################################################
356        await self.debugger_impl.send("Debugger.resume", worker_thread_2)
357        ################################################################################################################
358        # main thread: Debugger.stepOut
359        ################################################################################################################
360        await self.debugger_impl.send("Debugger.stepOut", main_thread)
361        # main thread: Debugger.paused
362        response = await self.debugger_impl.recv("Debugger.paused", main_thread)
363        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index']
364        assert response['params']['reason'] == 'other'
365        assert response['params']['hitBreakpoints'] == ['id:57:20:' + self.config['file_path']['index']]
366        # worker thread: Debugger.paused
367        response = await self.debugger_impl.recv("Debugger.paused", worker_thread_1)
368        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['worker']
369        assert response['params']['reason'] == 'other'
370        assert response['params']['hitBreakpoints'] == ['id:11:4:' + self.config['file_path']['worker']]
371        ################################################################################################################
372        # worker thread: Runtime.getProperties
373        ################################################################################################################
374        params = runtime.GetPropertiesParams('0', True, False, True)
375        response = await self.runtime_impl.send("Runtime.getProperties", worker_thread_1, params)
376        assert response['result']['result'][0]['name'] == ''
377        assert response['result']['result'][0]['value']['type'] == 'function'
378        assert response['result']['result'][1]['name'] == 'e'
379        assert response['result']['result'][1]['value']['type'] == 'object'
380        ################################################################################################################
381        # worker thread: Debugger.stepOut
382        ################################################################################################################
383        await self.debugger_impl.send("Debugger.stepOut", worker_thread_1)
384        ################################################################################################################
385        # worker thread: Debugger.disable
386        ################################################################################################################
387        await self.debugger_impl.send("Debugger.disable", worker_thread_1)
388        ################################################################################################################
389        # main thread: Debugger.stepInto
390        ################################################################################################################
391        await self.debugger_impl.send("Debugger.stepInto", main_thread)
392        # main thread: Debugger.paused
393        response = await self.debugger_impl.recv("Debugger.paused", main_thread)
394        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index']
395        assert response['params']['reason'] == 'other'
396        assert response['params']['hitBreakpoints'] == []
397        # worker thread: Debugger.paused
398        response = await self.debugger_impl.recv("Debugger.paused", worker_thread_2)
399        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['worker']
400        assert response['params']['reason'] == 'other'
401        assert response['params']['hitBreakpoints'] == ['id:11:4:' + self.config['file_path']['worker']]
402        ################################################################################################################
403        # worker thread: Debugger.resume
404        ################################################################################################################
405        await self.debugger_impl.send("Debugger.resume", worker_thread_2)
406        ################################################################################################################
407        # worker thread: Debugger.disable
408        ################################################################################################################
409        await self.debugger_impl.send("Debugger.disable", worker_thread_2)
410        ################################################################################################################
411        # main thread: Debugger.resume
412        ################################################################################################################
413        await self.debugger_impl.send("Debugger.resume", main_thread)
414        ################################################################################################################
415        # worker thread: destroy instance
416        ################################################################################################################
417        response = await self.debugger_impl.destroy_instance()
418        assert response['instanceId'] != self.config['pid']
419        response = await self.debugger_impl.destroy_instance()
420        assert response['instanceId'] != self.config['pid']
421        ################################################################################################################
422        # main thread: Debugger.disable
423        ################################################################################################################
424        await self.debugger_impl.send("Debugger.disable", main_thread)
425        ################################################################################################################
426        # close the websocket connections
427        ################################################################################################################
428        await websocket.send_msg_to_debugger_server(main_thread.instance_id, main_thread.send_msg_queue, 'close')
429        await websocket.send_msg_to_connect_server('close')
430        ################################################################################################################