1 /*
2   +----------------------------------------------------------------------+
3   | Swoole                                                               |
4   +----------------------------------------------------------------------+
5   | This source file is subject to version 2.0 of the Apache license,    |
6   | that is bundled with this package in the file LICENSE, and is        |
7   | available through the world-wide-web at the following url:           |
8   | http://www.apache.org/licenses/LICENSE-2.0.html                      |
9   | If you did not receive a copy of the Apache2.0 license and are unable|
10   | to obtain it through the world-wide-web, please send a note to       |
11   | license@swoole.com so we can mail you a copy immediately.            |
12   +----------------------------------------------------------------------+
13   | @link     https://www.swoole.com/                                    |
14   | @contact  team@swoole.com                                            |
15   | @license  https://github.com/swoole/swoole-src/blob/master/LICENSE   |
16   | @author   Tianfeng Han  <mikan.tenny@gmail.com>                      |
17   +----------------------------------------------------------------------+
18 */
19 
20 #include "test_coroutine.h"
21 #include "swoole_file.h"
22 #include "swoole_util.h"
23 
24 using swoole::Coroutine;
25 using swoole::String;
26 using swoole::coroutine::System;
27 using swoole::test::coroutine;
28 
29 const char *host_1 = "www.baidu.com";
30 const char *host_2 = "www.xxxxxxxxxxxxxxxxxxxxx00000xxxxxxxxx----not_found.com";
31 static const char *test_file = "/tmp/swoole-core-test";
32 
TEST(coroutine_hook,file)33 TEST(coroutine_hook, file) {
34     coroutine::run([](void *arg) {
35         char buf[8192];
36         size_t n_buf = sizeof(buf);
37         ASSERT_EQ(swoole_random_bytes(buf, n_buf), n_buf);
38 
39         int fd = swoole_coroutine_open(test_file, O_WRONLY | O_TRUNC | O_CREAT, 0666);
40         ASSERT_EQ(swoole_coroutine_write(fd, buf, n_buf), n_buf);
41         swoole_coroutine_close(fd);
42 
43         fd = swoole_coroutine_open(test_file, O_RDONLY, 0);
44         char data[8192];
45         ASSERT_EQ(swoole_coroutine_read(fd, data, n_buf), n_buf);
46         ASSERT_EQ(std::string(buf, n_buf), std::string(data, n_buf));
47         swoole_coroutine_close(fd);
48 
49         ASSERT_EQ(swoole_coroutine_unlink(test_file), 0);
50     });
51 }
52 
TEST(coroutine_hook,gethostbyname)53 TEST(coroutine_hook, gethostbyname) {
54     coroutine::run([](void *arg) {
55         auto result1 = swoole_coroutine_gethostbyname(host_1);
56         ASSERT_NE(result1, nullptr);
57 
58         auto result2 = swoole_coroutine_gethostbyname(host_2);
59         ASSERT_EQ(result2, nullptr);
60         ASSERT_EQ(h_errno, HOST_NOT_FOUND);
61     });
62 }
63 
TEST(coroutine_hook,getaddrinfo)64 TEST(coroutine_hook, getaddrinfo) {
65     coroutine::run([](void *arg) {
66         struct addrinfo hints;
67         sw_memset_zero(&hints, sizeof(struct addrinfo));
68         hints.ai_family = AF_INET;
69         hints.ai_socktype = SOCK_STREAM;
70         hints.ai_flags = AI_PASSIVE;
71 
72         struct addrinfo *result, *curr;
73         int count;
74 
75         result = nullptr;
76         auto result1 = swoole_coroutine_getaddrinfo(host_1, "http", &hints, &result);
77         ASSERT_EQ(result1, 0);
78 
79         curr = result;
80         count = 0;
81         while (curr && curr->ai_addr) {
82             curr = curr->ai_next;
83             count++;
84         }
85         ASSERT_GE(count, 1);
86         freeaddrinfo(result);
87 
88         result = nullptr;
89         auto result2 = swoole_coroutine_getaddrinfo(host_2, nullptr, &hints, &result);
90         ASSERT_EQ(result2, EAI_NONAME);
91         ASSERT_EQ(result, nullptr);
92         freeaddrinfo(result);
93     });
94 }
95 
TEST(coroutine_hook,fstat)96 TEST(coroutine_hook, fstat) {
97     coroutine::run([](void *arg) {
98         int fd = swoole_coroutine_open(TEST_TMP_FILE, O_RDONLY, 0);
99         struct stat statbuf_1;
100         swoole_coroutine_fstat(fd, &statbuf_1);
101 
102         struct stat statbuf_2;
103         fstat(fd, &statbuf_2);
104 
105         ASSERT_EQ(memcmp(&statbuf_1, &statbuf_2, sizeof(statbuf_2)), 0);
106 
107         swoole_coroutine_close(fd);
108     });
109 }
110 
TEST(coroutine_hook,statvfs)111 TEST(coroutine_hook, statvfs) {
112     coroutine::run([](void *arg) {
113         struct statvfs statbuf_1;
114         swoole_coroutine_statvfs("/tmp", &statbuf_1);
115 
116         struct statvfs statbuf_2;
117         statvfs("/tmp", &statbuf_2);
118 
119         ASSERT_EQ(memcmp(&statbuf_1, &statbuf_2, sizeof(statbuf_2)), 0);
120     });
121 }
122 
TEST(coroutine_hook,dir)123 TEST(coroutine_hook, dir) {
124     coroutine::run([](void *arg) {
125         ASSERT_EQ(swoole_coroutine_mkdir(TEST_TMP_DIR, 0666), 0);
126         ASSERT_EQ(swoole_coroutine_access(TEST_TMP_DIR, R_OK), 0);
127         ASSERT_EQ(swoole_coroutine_rmdir(TEST_TMP_DIR), 0);
128         ASSERT_EQ(access(TEST_TMP_DIR, R_OK), -1);
129     });
130 }
131 
TEST(coroutine_hook,socket)132 TEST(coroutine_hook, socket) {
133     coroutine::run([](void *arg) {
134         int sock = swoole_coroutine_socket(AF_INET, SOCK_STREAM, 0);
135         ASSERT_GT(sock, 0);
136         swoole::network::Address sa;
137         std::string ip = System::gethostbyname("www.baidu.com", AF_INET, 10);
138         sa.assign(SW_SOCK_TCP, ip, 80);
139         ASSERT_EQ(swoole_coroutine_connect(sock, &sa.addr.ss, sa.len), 0);
140         ASSERT_EQ(swoole_coroutine_socket_wait_event(sock, SW_EVENT_WRITE, 5), SW_OK);
141 
142         const char req[] = "GET / HTTP/1.1\r\nHost: www.baidu.com\r\nConnection: close\r\nKeepAlive: off\r\n\r\n";
143         ASSERT_EQ(swoole_coroutine_send(sock, req, strlen(req), 0), strlen(req));
144 
145         swoole::String resp(1024);
146 
147         while (1) {
148             ssize_t n = swoole_coroutine_recv(sock, resp.value() + resp.length, resp.size - resp.length, 0);
149             if (n <= 0) {
150                 break;
151             }
152             resp.length += n;
153             if (resp.length == resp.size) {
154                 resp.reserve(resp.size * 2);
155             }
156         }
157 
158         ASSERT_GT(resp.length, 100);
159         ASSERT_TRUE(resp.contains("baidu.com"));
160         swoole_coroutine_close(sock);
161     });
162 }
163 
TEST(coroutine_hook,rename)164 TEST(coroutine_hook, rename) {
165     coroutine::run([](void *arg) {
166         char buf[8192];
167         size_t n_buf = sizeof(buf);
168         ASSERT_EQ(swoole_random_bytes(buf, n_buf), n_buf);
169 
170         int fd = swoole_coroutine_open(test_file, O_WRONLY | O_TRUNC | O_CREAT, 0666);
171         ASSERT_EQ(swoole_coroutine_write(fd, buf, n_buf), n_buf);
172         swoole_coroutine_close(fd);
173 
174         std::string to_file_name = std::string(test_file, ".bak");
175         ASSERT_EQ(swoole_coroutine_rename(test_file, to_file_name.c_str()), 0);
176         ASSERT_EQ(access(TEST_TMP_DIR, F_OK), -1);
177         ASSERT_EQ(access(to_file_name.c_str(), F_OK), 0);
178 
179         swoole_coroutine_unlink(to_file_name.c_str());
180     });
181 }
182 
TEST(coroutine_hook,flock)183 TEST(coroutine_hook, flock) {
184     long start_time = swoole::time<std::chrono::milliseconds>();
185     coroutine::run([&](void *arg) {
186         swoole::Coroutine::create([&](void *arg) {
187             int fd = swoole_coroutine_open(TEST_TMP_FILE, O_WRONLY, 0);
188             ASSERT_EQ(swoole_coroutine_flock(fd, LOCK_EX), 0);
189             System::sleep(0.1);
190             ASSERT_EQ(swoole_coroutine_flock(fd, LOCK_UN), 0);
191 
192             ASSERT_EQ(swoole_coroutine_flock(fd, LOCK_SH), 0);
193             ASSERT_EQ(swoole_coroutine_flock(fd, LOCK_UN), 0);
194             ASSERT_LE(swoole::time<std::chrono::milliseconds>() - start_time, 1000);
195             swoole_coroutine_close(fd);
196         });
197         swoole::Coroutine::create([&](void *arg) {
198             int fd = swoole_coroutine_open(TEST_TMP_FILE, O_WRONLY, 0);
199             ASSERT_EQ(swoole_coroutine_flock(fd, LOCK_SH), 0);
200             System::sleep(2);
201             ASSERT_EQ(swoole_coroutine_flock(fd, LOCK_UN), 0);
202             swoole_coroutine_close(fd);
203         });
204     });
205     // LOCK_NB
206     coroutine::run([](void *arg) {
207         int fd1 = swoole_coroutine_open(TEST_TMP_FILE, O_WRONLY, 0);
208         ASSERT_EQ(swoole_coroutine_flock(fd1, LOCK_EX), 0);
209         int fd2 = swoole_coroutine_open(TEST_TMP_FILE, O_WRONLY, 0);
210         ASSERT_EQ(swoole_coroutine_flock(fd2, LOCK_EX | LOCK_NB), -1);
211         ASSERT_EQ(swoole_coroutine_flock(fd1, LOCK_UN), 0);
212         swoole_coroutine_close(fd1);
213         swoole_coroutine_close(fd2);
214     });
215 }
216 
TEST(coroutine_hook,read_dir)217 TEST(coroutine_hook, read_dir) {
218     auto fp = opendir("/tmp");
219     std::string dir1(readdir(fp)->d_name);
220     std::string dir2(readdir(fp)->d_name);
221     closedir(fp);
222 
223     auto fn = [&]() {
224         auto fp = swoole_coroutine_opendir("/tmp");
225         ASSERT_NE(fp, nullptr);
226         struct dirent *entry;
227 
228         entry = swoole_coroutine_readdir(fp);
229         ASSERT_NE(entry, nullptr);
230         ASSERT_STREQ(entry->d_name, dir1.c_str());
231 
232         entry = swoole_coroutine_readdir(fp);
233         ASSERT_NE(entry, nullptr);
234         ASSERT_STREQ(entry->d_name, dir2.c_str());
235 
236         swoole_coroutine_closedir(fp);
237     };
238 
239     coroutine::run([&](void *arg) {
240         fn();
241     });
242     fn();
243 }
244 
TEST(coroutine_hook,readlink)245 TEST(coroutine_hook, readlink) {
246     auto fn = []() {
247         char buf1[1024] = {};
248         char buf2[1024] = {};
249 
250         auto retval = swoole_coroutine_readlink("/proc/self/cwd", buf1, sizeof(buf1));
251         ASSERT_NE(retval, -1);
252 
253         getcwd(buf2, sizeof(buf2));
254         ASSERT_STREQ(buf1, buf2);
255     };
256 
257     coroutine::run([&](void *arg) {
258         fn();
259     });
260     fn();
261 }
262 
TEST(coroutine_hook,stdio_1)263 TEST(coroutine_hook, stdio_1) {
264     auto fn = []() {
265         FILE *fp1 = swoole_coroutine_fopen(test_file, "w+");
266         const char *str = "hello world";
267         int n = swoole_coroutine_fputs(str, fp1);
268         ASSERT_TRUE(n);
269         swoole_coroutine_fclose(fp1);
270 
271         FILE *fp2 = swoole_coroutine_fopen(test_file, "r+");
272         char buf[1024];
273         char *str2 = swoole_coroutine_fgets(buf, sizeof(buf), fp2);
274 
275         ASSERT_STREQ(str2, str);
276         swoole_coroutine_fclose(fp2);
277 
278         unlink(test_file);
279     };
280 
281     coroutine::run([&](void *arg) {
282         fn();
283     });
284     fn();
285 }
286 
TEST(coroutine_hook,stdio_2)287 TEST(coroutine_hook, stdio_2) {
288     auto fn = []() {
289         size_t size = 1024;
290 
291         FILE *fp1 = swoole_coroutine_fopen(test_file, "w+");
292         String str(size);
293         str.append_random_bytes(size);
294         size_t n = swoole_coroutine_fwrite(str.str, 1, size, fp1);
295         ASSERT_EQ(n, size);
296         swoole_coroutine_fclose(fp1);
297 
298         FILE *fp2 = swoole_coroutine_fopen(test_file, "r+");
299         char buf[size];
300         size_t len = swoole_coroutine_fread(buf, 1, size, fp2);
301         ASSERT_EQ(len, size);
302 
303         len = swoole_coroutine_fread(buf, 1, size, fp2);
304         ASSERT_EQ(len, 0);
305 
306         ASSERT_TRUE(swoole_coroutine_feof(fp2));
307 
308         ASSERT_MEMEQ(buf, str.str, size);
309         swoole_coroutine_fclose(fp2);
310 
311         unlink(test_file);
312     };
313 
314     coroutine::run([&](void *arg) {
315         fn();
316     });
317     fn();
318 }
319