• 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 TestWorkerGetProperties:
35    """
36    测试用例:多实例 getProperties 调试
37    测试步骤:
38        1.  连接 connect server 和主线程 debugger server
39        2.  主线程使能 Runtime 和 Debugger
40        3.  主线程 Index.ts 文件设置断点(Debugger.getPossibleAndSetBreakpointByUrl)
41        4.  主线程 resume,暂停在下一断点(Debugger.resume)
42        5.  创建子线程,连接子线程 debugger server
43        6.  子线程使能 Runtime 和 Debugger
44        7.  子线程 Worker.ets 文件设置断点(Debugger.getPossibleAndSetBreakpointByUrl)
45        8.  主线程 resume,发送消息给子线程,子线程暂停在断点(Debugger.resume)
46        9.  子线程 getProperties 获取 local/closure/module/global作用域变量信息(Debugger.getProperties)
47        10. 销毁子线程,对应的 debugger server 连接断开
48        11. 关闭主线程 debugger server 和 connect server 连接
49    关键代码:
50        Index.ets
51            let myWorker = new worker.ThreadWorker("entry/ets/workers/Worker.ets")
52            myWorker.postMessage("hello world")
53            .OnClick(() => {
54                myWorker.terminate()
55            })
56        Worker.ets
57            const workerPort: ThreadWorkerGlobalScope = worker.workerPort;
58            let closureBoolean = false
59            ...... // 定义不同的闭包变量
60            globalThis.globalBool = new Boolean(closureBoolean)
61            ...... // 定义不同的全局变量
62            workerPort.onmessage = (e: MessageEvents) => {
63                let localNull = null
64                ...... // 定义不同的局部变量
65                workerPort.postMessage(e.data)
66            }
67    """
68
69    def setup_method(self):
70        logging.info('Start running TestWorkerGetProperties: setup')
71
72        self.log_path = rf'{os.path.dirname(__file__)}\..\log'
73        self.hilog_file_name = 'test_worker_get_properties.hilog.txt'
74        self.id_generator = Utils.message_id_generator()
75
76        # receive the hilog before the test start
77        Utils.clear_fault_log()
78        self.hilog_process, self.write_thread = Utils.save_hilog(log_path=self.log_path,
79                                                                 file_name=self.hilog_file_name,
80                                                                 debug_on=True)
81
82    def teardown_method(self):
83        Application.uninstall(self.config['bundle_name'])
84
85        # terminate the hilog receive process after the test done
86        time.sleep(3)
87        self.hilog_process.stdout.close()
88        self.hilog_process.terminate()
89        self.hilog_process.wait()
90        self.write_thread.join()
91
92        Utils.save_fault_log(log_path=self.log_path)
93        logging.info('TestWorkerGetProperties done')
94
95    def test(self, test_suite_worker_04_debug):
96        logging.info('Start running TestWorkerGetProperties: test')
97        self.config = test_suite_worker_04_debug
98        websocket = self.config['websocket']
99        taskpool = self.config['taskpool']
100        pid = self.config['pid']
101        self.debugger_impl = debugger_api.DebuggerImpl(self.id_generator, websocket)
102        self.runtime_impl = runtime_api.RuntimeImpl(self.id_generator, websocket)
103
104        taskpool.submit(websocket.main_task(taskpool, self.procedure, pid))
105        taskpool.await_taskpool()
106        taskpool.task_join()
107        if taskpool.task_exception:
108            raise taskpool.task_exception
109
110    async def procedure(self, websocket):
111        ################################################################################################################
112        # main thread: connect the debugger server
113        ################################################################################################################
114        main_thread = await self.debugger_impl.connect_to_debugger_server(self.config['pid'], True)
115        logging.info(f'Connect to the debugger server of instance: {main_thread.instance_id}')
116        ################################################################################################################
117        # main thread: Runtime.enable
118        ################################################################################################################
119        await self.runtime_impl.send("Runtime.enable", main_thread)
120        ################################################################################################################
121        # main thread: Debugger.enable
122        ################################################################################################################
123        await self.debugger_impl.send("Debugger.enable", main_thread)
124        ################################################################################################################
125        # main thread: Runtime.runIfWaitingForDebugger
126        ################################################################################################################
127        await self.runtime_impl.send("Runtime.runIfWaitingForDebugger", main_thread)
128        ################################################################################################################
129        # main thread: Debugger.scriptParsed
130        ################################################################################################################
131        response = await self.debugger_impl.recv("Debugger.scriptParsed", main_thread)
132        assert response['params']['url'] == self.config['file_path']['entry_ability']
133        assert response['params']['endLine'] == 0
134        ################################################################################################################
135        # main thread: Debugger.paused
136        ################################################################################################################
137        response = await self.debugger_impl.recv("Debugger.paused", main_thread)
138        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['entry_ability']
139        assert response['params']['reason'] == 'Break on start'
140        ################################################################################################################
141        # main thread: Debugger.resume
142        ################################################################################################################
143        await self.debugger_impl.send("Debugger.resume", 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']['index']
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']['index']
155        assert response['params']['reason'] == 'Break on start'
156        ################################################################################################################
157        # main thread: Debugger.removeBreakpointsByUrl
158        ################################################################################################################
159        params = debugger.RemoveBreakpointsUrl(self.config['file_path']['index'])
160        await self.debugger_impl.send("Debugger.removeBreakpointsByUrl", main_thread, params)
161        ################################################################################################################
162        # main thread: Debugger.getPossibleAndSetBreakpointByUrl
163        ################################################################################################################
164        locations = [debugger.BreakLocationUrl(url=self.config['file_path']['index'], line_number=12)]
165        params = debugger.SetBreakpointsLocations(locations)
166        response = await self.debugger_impl.send("Debugger.getPossibleAndSetBreakpointsByUrl",
167                                                 main_thread, params)
168        assert response['result']['locations'][0]['id'] == 'id:12:0:' + self.config['file_path']['index']
169        ################################################################################################################
170        # main thread: Debugger.resume
171        ################################################################################################################
172        await self.debugger_impl.send("Debugger.resume", main_thread)
173        ################################################################################################################
174        # main thread: Debugger.paused, hit breakpoint
175        ################################################################################################################
176        response = await self.debugger_impl.recv("Debugger.paused", main_thread)
177        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['index']
178        assert response['params']['hitBreakpoints'] == ['id:12:0:' + self.config['file_path']['index']]
179        ################################################################################################################
180        # worker thread: connect the debugger server
181        ################################################################################################################
182        worker_thread = await self.debugger_impl.connect_to_debugger_server(self.config['pid'], False)
183        logging.info(f'Connect to the debugger server of instance: {worker_thread.instance_id}')
184        ################################################################################################################
185        # worker thread: Runtime.enable
186        ################################################################################################################
187        await self.runtime_impl.send("Runtime.enable", worker_thread)
188        ################################################################################################################
189        # worker thread: Debugger.enable
190        ################################################################################################################
191        await self.debugger_impl.send("Debugger.enable", worker_thread)
192        ################################################################################################################
193        # worker thread: Runtime.runIfWaitingForDebugger
194        ################################################################################################################
195        await self.runtime_impl.send("Runtime.runIfWaitingForDebugger", worker_thread)
196        # worker thread: Debugger.scriptParsed
197        response = await self.debugger_impl.recv("Debugger.scriptParsed", worker_thread)
198        assert response['params']['url'] == self.config['file_path']['worker']
199        assert response['params']['endLine'] == 0
200        # worker thread: Debugger.paused
201        response = await self.debugger_impl.recv("Debugger.paused", worker_thread)
202        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['worker']
203        assert response['params']['reason'] == 'Break on start'
204        ################################################################################################################
205        # worker thread: Debugger.removeBreakpointsByUrl
206        ################################################################################################################
207        params = debugger.RemoveBreakpointsUrl(self.config['file_path']['worker'])
208        await self.debugger_impl.send("Debugger.removeBreakpointsByUrl", worker_thread, params)
209        ################################################################################################################
210        # worker thread: Debugger.getPossibleAndSetBreakpointByUrl
211        ################################################################################################################
212        locations = [debugger.BreakLocationUrl(url=self.config['file_path']['worker'], line_number=116)]
213        params = debugger.SetBreakpointsLocations(locations)
214        response = await self.debugger_impl.send("Debugger.getPossibleAndSetBreakpointsByUrl",
215                                                 worker_thread, params)
216        assert response['result']['locations'][0]['id'] == 'id:116:0:' + self.config['file_path']['worker']
217        ################################################################################################################
218        # worker thread: Debugger.resume
219        ################################################################################################################
220        await self.debugger_impl.send("Debugger.resume", worker_thread)
221        ################################################################################################################
222        # main thread: Debugger.resume
223        ################################################################################################################
224        await self.debugger_impl.send("Debugger.resume", main_thread)
225        # worker thread: Debugger.paused
226        response = await self.debugger_impl.recv("Debugger.paused", worker_thread)
227        assert response['params']['callFrames'][0]['url'] == self.config['file_path']['worker']
228        assert response['params']['reason'] == 'other'
229        assert response['params']['hitBreakpoints'] == ['id:116:4:' + self.config['file_path']['worker']]
230        ################################################################################################################
231        # worker thread: Runtime.getProperties
232        ################################################################################################################
233        params = runtime.GetPropertiesParams('0')
234        response = await self.runtime_impl.send("Runtime.getProperties", worker_thread, params)
235        variables = self.get_variables_from_result(response['result']['result'], 'local')
236        assert variables == {'localArrayList': 'ArrayList', 'localBigInt64Array': 'BigInt64Array',
237                             'localBigUint64Array': 'BigUint64Array', 'localDataView': 'DataView(20)',
238                             'localDeque': 'Deque', 'localFloat32Array': 'Float32Array',
239                             'localFloat64Array': 'Float64Array', 'localHashMap': 'HashMap', 'localHashSet': 'HashSet',
240                             'localInt16Array': 'Int16Array(0)', 'localInt32Array': 'Int32Array(0)',
241                             'localInt8Array': 'Int8Array(0)', 'localLightWeightMap': 'LightWeightMap',
242                             'localLightWeightSet': 'LightWeightSet', 'localLinkedList': 'LinkedList',
243                             'localList': 'List', 'localMapIter': 'function entries( { [native code] }',
244                             'localNull': 'null', 'localPerson': 'Person', 'localPlainArray': 'PlainArray',
245                             'localPromise': 'Promise', 'localProxy': 'Proxy', 'localQueue': 'Queue',
246                             'localSendableClass': 'SendableClass[Sendable]',
247                             'localSharedArrayBuffer': 'SharedArrayBuffer(32)', 'localStack': 'Stack',
248                             'localTreeMap': 'TreeMap', 'localTreeSet': 'TreeSet', 'localUint16Array': 'Uint16Array',
249                             'localUint32Array': 'Uint32Array', 'localUint8Array': 'Uint8Array(3)',
250                             'localUint8ClampedArray': 'Uint8ClampedArray', 'localUndefined': 'undefined',
251                             'localWeakMap': 'WeakMap(0)', 'localWeakRef': 'WeakRef {}', 'localWeakSet': 'WeakSet(0)'}
252        ################################################################################################################
253        # worker thread: Runtime.getProperties
254        ################################################################################################################
255        params = runtime.GetPropertiesParams('1')
256        response = await self.runtime_impl.send("Runtime.getProperties", worker_thread, params)
257        variables = self.get_variables_from_result(response['result']['result'], 'closure')
258        assert variables == {'closureArray': 'Array(3)', 'closureArrayBuffer': 'Arraybuffer(20)',
259                             'closureMap': 'Map(0)', 'closureNum': '20', 'closureRegExp': '/^ab+c/g',
260                             'closureSet': "Set(1) {'closure'}", 'closureString': 'closure'}
261        ################################################################################################################
262        # worker thread: Runtime.getProperties
263        ################################################################################################################
264        params = runtime.GetPropertiesParams('2')
265        response = await self.runtime_impl.send("Runtime.getProperties", worker_thread, params)
266        variables = self.get_variables_from_result(response['result']['result'], '')
267        assert variables == {'ArrayList': 'function ArrayList( { [native code] }',
268                             'Deque': 'function Deque( { [native code] }',
269                             'HashMap': 'function HashMap( { [native code] }',
270                             'HashSet': 'function HashSet( { [native code] }',
271                             'LightWeightMap': 'function LightWeightMap( { [native code] }',
272                             'LightWeightSet': 'function LightWeightSet( { [native code] }',
273                             'LinkedList': 'function LinkedList( { [native code] }',
274                             'List': 'function List( { [native code] }',
275                             'PlainArray': 'function PlainArray( { [native code] }',
276                             'Queue': 'function Queue( { [native code] }', 'Stack': 'function Stack( { [native code] }',
277                             'TreeMap': 'function TreeMap( { [native code] }',
278                             'TreeSet': 'function TreeSet( { [native code] }', 'worker': 'Object'}
279        ################################################################################################################
280        # worker thread: Runtime.getProperties
281        ################################################################################################################
282        params = runtime.GetPropertiesParams('3')
283        response = await self.runtime_impl.send("Runtime.getProperties", worker_thread, params)
284        variables = self.get_variables_from_result(response['result']['result'], 'global')
285        assert variables == {'globalArray': 'Array(3)', 'globalBigInt': '9007199254740991n',
286                             'globalBool': 'Boolean{[[PrimitiveValue]]: false}',
287                             'globalDate': 'Wed Aug 28 2024 02:41:00 GMT+0800',
288                             'globalNum': 'Number{[[PrimitiveValue]]: 20}',
289                             'globalObject': 'String{[[PrimitiveValue]]: globalObject}',
290                             'globalStr': 'String{[[PrimitiveValue]]: globalStr}', 'globalThis': 'Object'}
291        ################################################################################################################
292        # worker thread: Debugger.resume
293        ################################################################################################################
294        await self.debugger_impl.send("Debugger.resume", worker_thread)
295        ################################################################################################################
296        # main thread: click on the screen
297        ################################################################################################################
298        Application.click_on_middle()
299        ################################################################################################################
300        # worker thread: destroy instance
301        ################################################################################################################
302        response = await self.debugger_impl.destroy_instance()
303        assert response['instanceId'] == worker_thread.instance_id
304        ################################################################################################################
305        # main thread: Debugger.disable
306        ################################################################################################################
307        await self.debugger_impl.send("Debugger.disable", main_thread)
308        ################################################################################################################
309        # close the websocket connections
310        ################################################################################################################
311        await websocket.send_msg_to_debugger_server(main_thread.instance_id, main_thread.send_msg_queue, 'close')
312        await websocket.send_msg_to_connect_server('close')
313        ################################################################################################################
314
315    def get_variables_from_result(self, result, prefix_name):
316        variables = {}
317        for var in result:
318            if var['name'].startswith(prefix_name):
319                name = var['name']
320                value = var['value']
321                description = value.get('description')
322                if description is not None:
323                    index_of_at = description.find('@')
324                    variables[name] = description if index_of_at == -1 else \
325                        (description[:index_of_at] + description[index_of_at + 9:].strip())
326                else:
327                    subtype = value.get('subtype')
328                    variables[name] = subtype if subtype is not None else value.get('type')
329        return variables