1/*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#ifndef ECMASCRIPT_TOOLING_TEST_TESTCASES_JS_HEAPDUMP_LOOP_TEST_H
17#define ECMASCRIPT_TOOLING_TEST_TESTCASES_JS_HEAPDUMP_LOOP_TEST_H
18
19#include "tooling/test/client_utils/test_util.h"
20
21namespace panda::ecmascript::tooling::test {
22class JsHeapdumpLoopTest : public TestActions {
23public:
24    JsHeapdumpLoopTest()
25    {
26        testAction = {
27            {SocketAction::SEND, "enable"},
28            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
29            {SocketAction::SEND, "runtime-enable"},
30            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
31            {SocketAction::SEND, "run"},
32            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
33            // load common_func.js
34            {SocketAction::RECV, "Debugger.scriptParsed", ActionRule::STRING_CONTAIN},
35
36            // break on start
37            {SocketAction::RECV, "Debugger.paused", ActionRule::STRING_CONTAIN},
38
39            {SocketAction::SEND, "heapprofiler-enable"},
40            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
41
42            // set breakpoint
43            {SocketAction::SEND, "b " DEBUGGER_JS_DIR "common_func.js 64"},
44            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
45            {SocketAction::SEND, "b " DEBUGGER_JS_DIR "common_func.js 65"},
46            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
47
48            // hit breakpoint after resume
49            {SocketAction::SEND, "resume"},
50            {SocketAction::RECV, "Debugger.resumed", ActionRule::STRING_CONTAIN},
51            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
52            {SocketAction::RECV, "Debugger.paused", ActionRule::STRING_CONTAIN},
53
54            // hit breakpoint after resume
55            {SocketAction::SEND, "resume"},
56            {SocketAction::RECV, "Debugger.resumed", ActionRule::STRING_CONTAIN},
57            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
58            {SocketAction::RECV, "Debugger.paused", ActionRule::STRING_CONTAIN},
59
60            {SocketAction::SEND, "heapdump"},
61            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE,
62                [this](auto recv, auto, auto) -> bool { return RecvReportProgress(recv); }},
63            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE,
64                [this](auto recv, auto, bool &needMoreMsg) -> bool {
65                    return RecvReportProgressFinished(recv, needMoreMsg);
66                }},
67            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE,
68                [this](auto recv, auto, bool &needMoreMsg) -> bool {
69                    return RecvReportProgressChunk(recv, needMoreMsg);
70                }},
71            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
72
73            {SocketAction::SEND, "heapprofiler-disable"},
74            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
75
76            // hit breakpoint after resume
77            {SocketAction::SEND, "resume"},
78            {SocketAction::RECV, "Debugger.resumed", ActionRule::STRING_CONTAIN},
79            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
80            {SocketAction::RECV, "Debugger.paused", ActionRule::STRING_CONTAIN},
81
82            // reply success and run
83            {SocketAction::SEND, "success"},
84            {SocketAction::SEND, "resume"},
85            {SocketAction::RECV, "Debugger.resumed", ActionRule::STRING_CONTAIN},
86            {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess},
87        };
88    }
89
90    bool RecvReportProgress(std::string recv)
91    {
92        std::unique_ptr<PtJson> json = PtJson::Parse(recv);
93        Result ret;
94        std::string method = "";
95        ret = json->GetString("method", &method);
96        if (ret != Result::SUCCESS) {
97            return false;
98        }
99
100        if (method != "HeapProfiler.reportHeapSnapshotProgress") {
101            return false;
102        }
103
104        std::unique_ptr<PtJson> params = nullptr;
105        ret = json->GetObject("params", &params);
106        if (ret != Result::SUCCESS) {
107            return false;
108        }
109
110        int done = 0;
111        ret = params->GetInt("done", &done);
112        if (ret != Result::SUCCESS) {
113            return false;
114        }
115
116        if (done != 0) {
117            return false;
118        }
119        return true;
120    }
121
122    bool RecvReportProgressFinished(std::string recv, bool &needMoreMsg)
123    {
124        needMoreMsg = false;
125        std::unique_ptr<PtJson> json = PtJson::Parse(recv);
126        Result ret;
127        std::string method = "";
128        ret = json->GetString("method", &method);
129        if (ret != Result::SUCCESS) {
130            return false;
131        }
132
133        if (method != "HeapProfiler.reportHeapSnapshotProgress") {
134            return false;
135        }
136
137        std::unique_ptr<PtJson> params = nullptr;
138        ret = json->GetObject("params", &params);
139        if (ret != Result::SUCCESS) {
140            return false;
141        }
142
143        int done = 0;
144        ret = params->GetInt("done", &done);
145        if (ret != Result::SUCCESS) {
146            return false;
147        }
148
149        bool finished = 0;
150        ret = params->GetBool("finished", &finished);
151        if (ret != Result::SUCCESS) {
152            needMoreMsg = true;
153        }
154        return true;
155    }
156
157    bool RecvReportProgressChunk(std::string recv, bool &needMoreMsg)
158    {
159        static std::string content = "";
160        needMoreMsg = false;
161        std::unique_ptr<PtJson> json = PtJson::Parse(recv);
162        Result ret;
163        std::string method = "";
164        ret = json->GetString("method", &method);
165        if (ret != Result::SUCCESS) {
166            return false;
167        }
168
169        if (method != "HeapProfiler.addHeapSnapshotChunk") {
170            return false;
171        }
172
173        std::unique_ptr<PtJson> params = nullptr;
174        ret = json->GetObject("params", &params);
175        if (ret != Result::SUCCESS) {
176            return false;
177        }
178
179        std::string chunk = "";
180        ret = params->GetString("chunk", &chunk);
181        if (ret != Result::SUCCESS) {
182            return false;
183        }
184
185        content += chunk;
186        std::unique_ptr<PtJson> contentJson = PtJson::Parse(content);
187        if (contentJson == nullptr || contentJson->Stringify().empty()) {
188            needMoreMsg = true;
189        }
190        return true;
191    }
192
193    std::pair<std::string, std::string> GetEntryPoint() override
194    {
195        return {pandaFile_, entryPoint_};
196    }
197    ~JsHeapdumpLoopTest() = default;
198
199private:
200    std::string pandaFile_ = DEBUGGER_ABC_DIR "common_func.abc";
201    std::string sourceFile_ = DEBUGGER_JS_DIR "common_func.js";
202    std::string entryPoint_ = "_GLOBAL::func_main_0";
203};
204
205std::unique_ptr<TestActions> GetJsHeapdumpLoopTest()
206{
207    return std::make_unique<JsHeapdumpLoopTest>();
208}
209}  // namespace panda::ecmascript::tooling::test
210
211#endif // ECMASCRIPT_TOOLING_TEST_TESTCASES_JS_HEAPDUMP_LOOP_TEST_H
212