1 /*
2 * Copyright (C) 2021 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 #include "ut_mod.h"
16 #include <openssl/evp.h>
17 #include <openssl/md5.h>
18 using namespace Hdc;
19
20 namespace HdcTest {
TestBaseCommand(void * runtimePtr)21 bool TestBaseCommand(void *runtimePtr)
22 {
23 Runtime *rt = (Runtime *)runtimePtr;
24 uint8_t *bufPtr = nullptr;
25 int bytesIO = 0;
26 bool ret = false;
27 // test 'discover'
28 rt->InnerCall(UT_DISCOVER);
29 if ((bytesIO = Base::ReadBinFile((UT_TMP_PATH + "/base-discover.result").c_str(),
30 reinterpret_cast<void **>(&bufPtr), 0)) < 0) {
31 return false;
32 }
33 if (!strcmp("0", reinterpret_cast<char *>(bufPtr))) {
34 delete[] bufPtr;
35 bufPtr = nullptr;
36 return false;
37 }
38 delete[] bufPtr;
39 bufPtr = nullptr;
40 // test 'targets'
41 rt->InnerCall(UT_LIST_TARGETS);
42 constexpr int expert = 5;
43 if ((bytesIO = Base::ReadBinFile((UT_TMP_PATH + "/base-list.result").c_str(),
44 reinterpret_cast<void **>(&bufPtr), 0)) < expert) {
45 goto Finish;
46 }
47 if (strcmp(MESSAGE_SUCCESS.c_str(), reinterpret_cast<char *>(bufPtr))) {
48 goto Finish;
49 }
50 delete[] bufPtr;
51 bufPtr = nullptr;
52 // test 'any'
53 rt->InnerCall(UT_CONNECT_ANY);
54 if ((bytesIO = Base::ReadBinFile((UT_TMP_PATH + "/base-any.result").c_str(),
55 reinterpret_cast<void **>(&bufPtr), 0)) < 0) {
56 goto Finish;
57 }
58 if (strcmp(MESSAGE_SUCCESS.c_str(), reinterpret_cast<char *>(bufPtr))) {
59 goto Finish;
60 }
61 // all pass
62 ret = true;
63
64 Finish:
65 if (bufPtr) {
66 delete[] bufPtr;
67 bufPtr = nullptr;
68 }
69 return ret;
70 }
71
TestShellExecute(void * runtimePtr)72 bool TestShellExecute(void *runtimePtr)
73 {
74 Runtime *rt = (Runtime *)runtimePtr;
75 uint8_t *bufPtr = nullptr;
76 int bytesIO = 0;
77 bool ret = false;
78 char bufString[BUF_SIZE_DEFAULT4] = "";
79 string resultFile = "execute.result";
80 while (true) {
81 // test1
82 rt->InnerCall(UT_SHELL_BASIC);
83 constexpr int expert = 10;
84 if ((bytesIO = Base::ReadBinFile((UT_TMP_PATH + "/" + resultFile).c_str(),
85 reinterpret_cast<void **>(&bufPtr), 0)) < expert) {
86 break;
87 }
88 Base::RunPipeComand(const_cast<const char *>("id"), bufString, sizeof(bufString), false);
89 if (strcmp(bufString, reinterpret_cast<char *>(bufPtr))) {
90 break;
91 }
92 delete[] bufPtr;
93 bufPtr = nullptr;
94
95 // test 2
96 rt->ResetUtTmpFile(resultFile);
97 rt->InnerCall(UT_SHELL_LIGHT);
98 if ((bytesIO = Base::ReadBinFile((UT_TMP_PATH + "/" + resultFile).c_str(),
99 reinterpret_cast<void **>(&bufPtr), 0)) < expert) {
100 break;
101 }
102 Base::RunPipeComand(const_cast<const char *>("cat /etc/passwd"), bufString, sizeof(bufString), false);
103 if (strcmp(bufString, reinterpret_cast<char *>(bufPtr))) {
104 break;
105 }
106 delete[] bufPtr;
107 bufPtr = nullptr;
108
109 // all pass
110 ret = true;
111 break;
112 }
113 if (bufPtr) {
114 delete[] bufPtr;
115 }
116 return ret;
117 }
118
Md5Sum(uint8_t * buf,int size)119 vector<uint8_t> Md5Sum(uint8_t *buf, int size)
120 {
121 vector<uint8_t> ret;
122 uint8_t md5Hash[MD5_DIGEST_LENGTH] = { 0 };
123 if (EVP_Digest(buf, size, md5Hash, NULL, EVP_md5(), NULL)) {
124 ret.insert(ret.begin(), md5Hash, md5Hash + sizeof(md5Hash));
125 }
126 return ret;
127 }
128
129 // file send like recv in our code, so just test send is enough
TestFileCommand(void * runtimePtr)130 bool TestFileCommand(void *runtimePtr)
131 {
132 Runtime *rt = (Runtime *)runtimePtr;
133 bool ret = false;
134 char bufString[BUF_SIZE_DEFAULT] = "";
135 uint8_t *bufLocal = nullptr;
136 uint8_t *bufRemote = nullptr;
137 int sizeLocal = 0;
138 int sizeRemote = 0;
139 string localFile = Base::StringFormat("%s/file.local", UT_TMP_PATH.c_str());
140 string remoteFile = Base::StringFormat("%s/file.remote", UT_TMP_PATH.c_str());
141 do {
142 // to be use random buf, not bash result
143 string cmd = Base::StringFormat("find /usr > %s", localFile.c_str());
144 Base::RunPipeComand(cmd.c_str(), bufString, sizeof(bufString), false);
145 rt->InnerCall(UT_FILE_SEND);
146 if ((sizeLocal = Base::ReadBinFile(localFile.c_str(), reinterpret_cast<void **>(&bufLocal), 0)) < 0) {
147 break;
148 };
149 if ((sizeRemote = Base::ReadBinFile(remoteFile.c_str(), reinterpret_cast<void **>(&bufRemote), 0)) < 0) {
150 break;
151 };
152 auto localHash = Md5Sum(bufLocal, sizeLocal);
153 auto remoteHash = Md5Sum(bufRemote, sizeRemote);
154 if (memcmp(localHash.data(), remoteHash.data(), localHash.size())) {
155 break;
156 }
157 ret = true;
158 } while (false);
159
160 if (bufLocal) {
161 delete[] bufLocal;
162 }
163 if (bufRemote) {
164 delete[] bufRemote;
165 }
166 return ret;
167 }
168
UtForwardWaiter(uv_loop_t * loop,uv_tcp_t * server)169 void UtForwardWaiter(uv_loop_t *loop, uv_tcp_t *server)
170 {
171 auto funcOnNewConn = [](uv_stream_t *server, int status) -> void {
172 auto funcOnRead = [](uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) -> void {
173 if (nread > 0 && !strcmp(buf->base, MESSAGE_SUCCESS.c_str())) {
174 Base::WriteBinFile((UT_TMP_PATH + "/forward.result").c_str(),
175 reinterpret_cast<uint8_t *>(MESSAGE_SUCCESS.c_str()),
176 MESSAGE_SUCCESS.size(), true);
177 }
178 uv_close((uv_handle_t *)client, [](uv_handle_t *handle) { free(handle); });
179 free(buf->base);
180 };
181 if (status < 0) {
182 return;
183 }
184 uv_tcp_t *client = new uv_tcp_t();
185 uv_tcp_init(server->loop, client);
186 if (uv_accept(server, (uv_stream_t *)client) == 0) {
187 uv_read_start((uv_stream_t *)client,
188 [](uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {
189 buf->base = new char[suggested_size]();
190 buf->len = suggested_size;
191 },
192 funcOnRead);
193 } else {
194 uv_close((uv_handle_t *)client, [](uv_handle_t *handle) { free(handle); });
195 }
196 };
197 const int utForwardTargetPort = 8082;
198 struct sockaddr_in addr;
199 if (uv_tcp_init(loop, server) || uv_ip4_addr("127.0.0.1", utForwardTargetPort, &addr)) {
200 return;
201 }
202 if (uv_tcp_bind(server, (const struct sockaddr *)&addr, 0) || uv_listen((uv_stream_t *)server, 5, funcOnNewConn)) {
203 return;
204 }
205 WRITE_LOG(LOG_DEBUG, "UtForwardWaiter listen on port:%d", utForwardTargetPort);
206 }
207
UtForwardConnect(uv_loop_t * loop,uv_tcp_t * client,uv_tcp_t * server)208 bool UtForwardConnect(uv_loop_t *loop, uv_tcp_t *client, uv_tcp_t *server)
209 {
210 auto funcConn = [](uv_connect_t *req, int status) -> void {
211 uv_tcp_t *server = (uv_tcp_t *)req->data;
212 delete req;
213 if (status < 0) {
214 return;
215 }
216 Base::SendToStream((uv_stream_t *)req->handle, (uint8_t *)MESSAGE_SUCCESS.c_str(), MESSAGE_SUCCESS.size());
217 Base::DelayDoSimple(req->handle->loop, 3000, [=](const uint8_t flag, string &msg, const void *p) {
218 uv_close((uv_handle_t *)server, nullptr); // notify UtForwardWaiter stop
219 });
220 };
221
222 const int utForwardListenPort = 8081;
223 struct sockaddr_in addr;
224 bool ret = false;
225 uv_connect_t *connReq = new uv_connect_t();
226 connReq->data = server;
227 do {
228 if (uv_tcp_init(loop, client)) {
229 break;
230 }
231 uv_ip4_addr("127.0.0.1", utForwardListenPort, &addr);
232 if (uv_tcp_connect(connReq, client, (const struct sockaddr *)&addr, funcConn)) {
233 break;
234 }
235
236 ret = true;
237 } while (false);
238 return ret;
239 }
240
TestForwardExternThread(void * arg)241 void TestForwardExternThread(void *arg)
242 {
243 uv_loop_t loop;
244 uv_tcp_t server;
245 uv_tcp_t client;
246 const int clientForwardTimeout = 1000;
247 bool *clientOK = (bool *)arg;
248 auto funcDelayCallUtForwardConnect = [&](const uint8_t flag, string &msg, const void *p) -> void {
249 if (!*clientOK) {
250 // client create forward timeout
251 WRITE_LOG(LOG_WARN, "Client forward timeout");
252 uv_stop(&loop);
253 }
254 UtForwardConnect(&loop, &client, &server);
255 };
256
257 uv_loop_init(&loop);
258 UtForwardWaiter(&loop, &server);
259 Base::DelayDoSimple(&loop, clientForwardTimeout, funcDelayCallUtForwardConnect);
260 uv_run(&loop, UV_RUN_DEFAULT);
261 uv_loop_close(&loop);
262 };
263
TestForwardCommand(void * runtimePtr)264 bool TestForwardCommand(void *runtimePtr)
265 {
266 Runtime *rt = (Runtime *)runtimePtr;
267 uv_thread_t td;
268 char buf[BUF_SIZE_TINY] = "";
269 bool clientOK = false;
270 int sizeResult = 0;
271 uv_thread_create(&td, TestForwardExternThread, &clientOK);
272 rt->InnerCall(UT_FORWARD_TCP2TCP);
273 clientOK = true;
274 uv_thread_join(&td);
275 // all done, we will check result ok
276 string localFile = Base::StringFormat("%s/forward.result", UT_TMP_PATH.c_str());
277 if ((sizeResult = Base::ReadBinFile(localFile.c_str(), reinterpret_cast<void **>(buf), sizeof(buf))) < 0) {
278 return false;
279 };
280 if (strcmp(buf, MESSAGE_SUCCESS.c_str())) {
281 return false;
282 }
283 return true;
284 }
285
TestAppCommand(void * runtimePtr)286 bool TestAppCommand(void *runtimePtr)
287 {
288 Runtime *rt = (Runtime *)runtimePtr;
289 char bufString[BUF_SIZE_DEFAULT] = "";
290 string localFile = Base::StringFormat("%s/app.hap", UT_TMP_PATH.c_str());
291 string cmd = Base::StringFormat("id --help > %s", localFile.c_str()); // I know it is a invalid hap file
292 Base::RunPipeComand(cmd.c_str(), bufString, sizeof(bufString), false);
293 rt->InnerCall(UT_APP_INSTALL);
294
295 constexpr int expert = 5;
296 if (Base::ReadBinFile((UT_TMP_PATH + "/appinstall.result").c_str(), reinterpret_cast<void **>(&bufString),
297 sizeof(bufString)) < expert) {
298 return false;
299 }
300 if (strcmp(MESSAGE_SUCCESS.c_str(), reinterpret_cast<char *>(bufString))) {
301 return false;
302 }
303 return true;
304 }
305 } // namespace HdcTest