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 TestDebug03:
35    """
36    测试用例:多 task 实例 debug 调试
37    测试步骤:
38        1.  连接 connect server 和主线程 debugger server
39        2.  主线程使能 Runtime 和 Debugger
40        3.  连接子线程 debugger server,用于执行 task 任务
41        4.  子线程使能 Runtime 和 Debugger
42        5.  主线程 Index.ts 文件设置断点(Debugger.getPossibleAndSetBreakpointByUrl)
43        6.  触发点击事件,主线程命中断点
44        7.  子线程 Index.ts 文件设置断点(Debugger.getPossibleAndSetBreakpointByUrl)
45        8.  子线程 resume,命中断点(Debugger.resume)
46        9.  子线程 getProperties,返回给定对象的属性(Runtime.getProperties)
47        10. 子线程 stepOut,主线程命中断点(Debugger.stepOut)
48        11. 主线程 getProperties(Runtime.getProperties)
49        12. 主线程 resume(Debugger.resume)
50        13. 子线程命中断点后 resume(Debugger.resume)
51        14. 关闭所有线程 debugger server 和 connect server 连接
52    """
53
54    def setup_method(self):
55        logging.info('Start running TestDebug03: setup')
56
57        self.log_path = rf'{os.path.dirname(__file__)}\..\log'
58        self.hilog_file_name = 'test_debug_03.hilog.txt'
59        self.id_generator = Utils.message_id_generator()
60
61        # receive the hilog before the test start
62        Utils.clear_fault_log()
63        self.hilog_process, self.write_thread = Utils.save_hilog(log_path=self.log_path,
64                                                                 file_name=self.hilog_file_name,
65                                                                 debug_on=True)
66
67    def teardown_method(self):
68        Application.uninstall(self.config['bundle_name'])
69
70        # terminate the hilog receive process after the test done
71        time.sleep(3)
72        self.hilog_process.stdout.close()
73        self.hilog_process.terminate()
74        self.hilog_process.wait()
75        self.write_thread.join()
76
77        Utils.save_fault_log(log_path=self.log_path)
78        logging.info('TestDebug03 done')
79
80    def test(self, test_suite_taskpool_01_debug):
81        logging.info('Start running TestDebug03: test')
82        self.config = test_suite_taskpool_01_debug
83        websocket = self.config['websocket']
84        taskpool = self.config['taskpool']
85        pid = self.config['pid']
86        self.debugger_impl = debugger_api.DebuggerImpl(self.id_generator, websocket)
87        self.runtime_impl = runtime_api.RuntimeImpl(self.id_generator, websocket)
88
89        taskpool.submit(websocket.main_task(taskpool, self.procedure, pid))
90        taskpool.await_taskpool()
91        taskpool.task_join()
92        if taskpool.task_exception:
93            raise taskpool.task_exception
94
95    async def procedure(self, websocket):
96        ################################################################################################################
97        # main thread: connect the debugger server
98        ################################################################################################################
99        main_thread = await self.debugger_impl.connect_to_debugger_server(self.config['pid'], True)
100        logging.info(f'Connect to the debugger server of instance: {main_thread.instance_id}')
101        ################################################################################################################
102        # main thread: Runtime.enable
103        ################################################################################################################
104        await self.runtime_impl.send("Runtime.enable", main_thread)
105        ################################################################################################################
106        # main thread: Debugger.enable
107        ################################################################################################################
108        await self.debugger_impl.send("Debugger.enable", main_thread)
109        ################################################################################################################
110        # main thread: Runtime.runIfWaitingForDebugger
111        ################################################################################################################
112        await self.runtime_impl.send("Runtime.runIfWaitingForDebugger", main_thread)
113        ################################################################################################################
114        # main thread: Debugger.scriptParsed
115        ################################################################################################################
116        response = await self.debugger_impl.recv("Debugger.scriptParsed", main_thread)
117        assert response['params']['url'] == self.config['file_path']['entry_ability']
118        assert response['params']['endLine'] == 0
119        ################################################################################################################
120        # main thread: Debugger.paused
121        ################################################################################################################
122        response = await self.debugger_impl.recv("Debugger.paused", main_thread)
123        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['entry_ability']
124        assert response['params']['reason'] == 'Break on start'
125        ################################################################################################################
126        # main thread: Debugger.resume
127        ################################################################################################################
128        await self.debugger_impl.send("Debugger.resume", main_thread)
129        ################################################################################################################
130        # main thread: Debugger.scriptParsed
131        ################################################################################################################
132        response = await self.debugger_impl.recv("Debugger.scriptParsed", main_thread)
133        assert response['params']['url'] == self.config['file_path']['index']
134        assert response['params']['endLine'] == 0
135        ################################################################################################################
136        # main thread: Debugger.paused
137        ################################################################################################################
138        response = await self.debugger_impl.recv("Debugger.paused", main_thread)
139        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index']
140        assert response['params']['reason'] == 'Break on start'
141        ################################################################################################################
142        # main thread: Debugger.resume
143        ################################################################################################################
144        await self.debugger_impl.send("Debugger.resume", main_thread)
145        ################################################################################################################
146        # worker thread: connect the debugger server
147        ################################################################################################################
148        worker_thread = await self.debugger_impl.connect_to_debugger_server(self.config['pid'], False)
149        logging.info(f'Connect to the debugger server of instance: {worker_thread.instance_id}')
150        ################################################################################################################
151        # worker thread: Runtime.enable
152        ################################################################################################################
153        await self.runtime_impl.send("Runtime.enable", worker_thread)
154        ################################################################################################################
155        # worker thread: Debugger.enable
156        ################################################################################################################
157        await self.debugger_impl.send("Debugger.enable", worker_thread)
158        ################################################################################################################
159        # worker thread: Runtime.runIfWaitingForDebugger
160        ################################################################################################################
161        await self.runtime_impl.send("Runtime.runIfWaitingForDebugger", worker_thread)
162        ################################################################################################################
163        # main thread: Debugger.removeBreakpointsByUrl
164        ################################################################################################################
165        params = debugger.RemoveBreakpointsUrl(self.config['file_path']['index'])
166        await self.debugger_impl.send("Debugger.removeBreakpointsByUrl", main_thread, params)
167        ################################################################################################################
168        # main thread: Debugger.getPossibleAndSetBreakpointByUrl
169        ################################################################################################################
170        locations = [debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=10),
171                     debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=17),
172                     debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=25)]
173        params = debugger.SetBreakpointsLocations(locations)
174        response = await self.debugger_impl.send("Debugger.getPossibleAndSetBreakpointsByUrl",
175                                                 main_thread, params)
176        assert response['result']['locations'][0]['id'] == 'id:10:0:' + self.config['file_path']['index']
177        assert response['result']['locations'][1]['id'] == 'id:17:0:' + self.config['file_path']['index']
178        assert response['result']['locations'][2]['id'] == 'id:25:0:' + self.config['file_path']['index']
179        ################################################################################################################
180        # main thread: click on the screen
181        ################################################################################################################
182        Application.click_on_middle()
183        ################################################################################################################
184        # worker thread: Debugger.scriptParsed
185        ################################################################################################################
186        response = await self.debugger_impl.recv("Debugger.scriptParsed", worker_thread)
187        assert response['params']['url'] == self.config['file_path']['index']
188        assert response['params']['endLine'] == 0
189        # worker thread: Debugger.paused
190        response = await self.debugger_impl.recv("Debugger.paused", worker_thread)
191        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index']
192        assert response['params']['reason'] == 'Break on start'
193        ################################################################################################################
194        # worker thread: Debugger.removeBreakpointsByUrl
195        ################################################################################################################
196        params = debugger.RemoveBreakpointsUrl(self.config['file_path']['index'])
197        await self.debugger_impl.send("Debugger.removeBreakpointsByUrl", worker_thread, params)
198        ################################################################################################################
199        # worker thread: Debugger.getPossibleAndSetBreakpointByUrl
200        ################################################################################################################
201        locations = [debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=10),
202                     debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=17),
203                     debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=25)]
204        params = debugger.SetBreakpointsLocations(locations)
205        response = await self.debugger_impl.send("Debugger.getPossibleAndSetBreakpointsByUrl",
206                                                 worker_thread, params)
207        assert response['result']['locations'][0]['id'] == 'id:10:0:' + self.config['file_path']['index']
208        assert response['result']['locations'][1]['id'] == 'id:17:0:' + self.config['file_path']['index']
209        assert response['result']['locations'][2]['id'] == 'id:25:0:' + self.config['file_path']['index']
210        ################################################################################################################
211        # worker thread: Debugger.resume
212        ################################################################################################################
213        await self.debugger_impl.send("Debugger.resume", worker_thread)
214        # worker thread: Debugger.paused
215        response = await self.debugger_impl.recv("Debugger.paused", worker_thread)
216        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index']
217        assert response['params']['reason'] == 'other'
218        assert response['params']['hitBreakpoints'] == ['id:10:14:' + self.config['file_path']['index']]
219        ################################################################################################################
220        # worker thread: Runtime.getProperties
221        ################################################################################################################
222        params = runtime.GetPropertiesParams('0')
223        response = await self.runtime_impl.send("Runtime.getProperties", worker_thread, params)
224        assert response['result']['result'][0]['name'] == 'add'
225        assert response['result']['result'][0]['value']['type'] == 'function'
226        ################################################################################################################
227        # worker thread: Debugger.stepOut
228        ################################################################################################################
229        await self.debugger_impl.send("Debugger.stepOut", worker_thread)
230        ################################################################################################################
231        # main thread: Debugger.paused, hit breakpoint
232        ################################################################################################################
233        response = await self.debugger_impl.recv("Debugger.paused", main_thread)
234        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index']
235        assert response['params']['hitBreakpoints'] == ['id:25:4:' + self.config['file_path']['index']]
236        ################################################################################################################
237        # main thread: Runtime.getProperties
238        ################################################################################################################
239        params = runtime.GetPropertiesParams('0')
240        response = await self.runtime_impl.send("Runtime.getProperties", main_thread, params)
241        assert response['result']['result'][0]['name'] == 'taskpoolTest'
242        assert response['result']['result'][0]['value']['type'] == 'function'
243        assert response['result']['result'][1]['name'] == 'valueSub'
244        assert response['result']['result'][1]['value']['type'] == 'undefined'
245        assert response['result']['result'][2]['name'] == 'valueAdd'
246        assert response['result']['result'][2]['value']['type'] == 'number'
247        assert response['result']['result'][2]['value']['description'] == '300'
248        ################################################################################################################
249        # main thread: Debugger.resume
250        ################################################################################################################
251        await self.debugger_impl.send("Debugger.resume", main_thread)
252        ################################################################################################################
253        # worker thread: Debugger.paused
254        ################################################################################################################
255        response = await self.debugger_impl.recv("Debugger.paused", worker_thread)
256        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index']
257        assert response['params']['hitBreakpoints'] == ['id:17:14:' + self.config['file_path']['index']]
258        ################################################################################################################
259        # worker thread: Debugger.resume
260        ################################################################################################################
261        await self.debugger_impl.send("Debugger.resume", worker_thread)
262        ################################################################################################################
263        # worker thread: Debugger.disable
264        ################################################################################################################
265        await self.debugger_impl.send("Debugger.disable", worker_thread)
266        ################################################################################################################
267        # main thread: Debugger.disable
268        ################################################################################################################
269        await self.debugger_impl.send("Debugger.disable", main_thread)
270        ################################################################################################################
271        # close the websocket connections
272        ################################################################################################################
273        await websocket.send_msg_to_debugger_server(worker_thread.instance_id, worker_thread.send_msg_queue, 'close')
274        await websocket.send_msg_to_debugger_server(main_thread.instance_id, main_thread.send_msg_queue, 'close')
275        await websocket.send_msg_to_connect_server('close')
276        ################################################################################################################