tc_posix_api.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. /*
  2. * Copyright (c) 2006-2024, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2024-09-03 Rbb666 the first version for DFS POSIX API utest
  9. */
  10. #include <rtthread.h>
  11. #include "utest.h"
  12. #include <dfs_file.h>
  13. #include <dfs.h>
  14. #include <sys/stat.h>
  15. #include <dirent.h>
  16. #include <fcntl.h>
  17. #include <unistd.h>
  18. #include <sys/types.h>
  19. #include <stdio.h>
  20. #include <errno.h>
  21. int fd = -1;
  22. static const char write_buf[] = "Hello RT-Thread POSIX!";
  23. #define TEST_MNT_PATH RT_UTEST_DFS_MNT_PATH
  24. #define TEST_BLOCK_DEV RT_UTEST_DFS_BLOCK_DEV
  25. #define TEST_FS RT_UTEST_DFS_FS_TYPE
  26. #define TEST_FILE TEST_MNT_PATH "/RTT.txt"
  27. #define TEST_DIR TEST_MNT_PATH "/posix"
  28. #define TEST_DIR_FILE TEST_MNT_PATH "/posix/RTT.txt"
  29. #define TEST_RENAME_FILE TEST_MNT_PATH "/RTT-renamed.txt"
  30. #define TEST_LINK_FILE TEST_MNT_PATH "/RTT-link.txt"
  31. #define TEST_CHDIR_DIR TEST_MNT_PATH "/chdir_test"
  32. #define WRITE_BUF_LEN (sizeof(write_buf) - 1)
  33. static void test_mkfs(void)
  34. {
  35. rt_err_t rst = dfs_mkfs(TEST_FS, TEST_BLOCK_DEV);
  36. uassert_true(rst == 0);
  37. }
  38. static void test_mount(void)
  39. {
  40. rt_err_t rst;
  41. struct stat stat_buf;
  42. /* First check if the mount point already has a filesystem */
  43. if (stat("/", &stat_buf) == 0)
  44. {
  45. uassert_true(RT_TRUE);
  46. return;
  47. }
  48. /* Try to unmount first, ignore errors as filesystem might not be mounted */
  49. rst = dfs_unmount(TEST_MNT_PATH);
  50. if (rst != 0)
  51. {
  52. rt_kprintf("[ERROR] unmount failed with result = %d\n", rst);
  53. }
  54. /* Now try to mount */
  55. rst = dfs_mount(TEST_BLOCK_DEV, TEST_MNT_PATH, TEST_FS, 0, 0);
  56. if (rst != 0)
  57. {
  58. rt_kprintf("[ERROR] Mount failed with result = %d\n", rst);
  59. /* If mount fails but filesystem already exists, consider it a pass */
  60. if (stat("/", &stat_buf) == 0)
  61. {
  62. uassert_true(RT_TRUE);
  63. return;
  64. }
  65. }
  66. uassert_true(rst == 0);
  67. }
  68. static void test_posix_open(void)
  69. {
  70. rt_kprintf("TEST_FILE:%s\n", TEST_FILE);
  71. fd = open(TEST_FILE, O_CREAT | O_RDWR, 0644);
  72. if (fd < 0)
  73. {
  74. rt_kprintf("[ERROR] Open failed, fd = %d, errno = %d\n", fd, errno);
  75. }
  76. uassert_true(fd >= 0);
  77. }
  78. static void test_posix_write(void)
  79. {
  80. ssize_t rst;
  81. rst = lseek(fd, 0, SEEK_SET);
  82. if (rst != 0)
  83. {
  84. rt_kprintf("[ERROR] lseek failed with result = %d\n", rst);
  85. }
  86. uassert_true(rst == 0);
  87. rt_kprintf("[WRITE] Writing data: \"%s\" (length: %d)\n", write_buf, WRITE_BUF_LEN);
  88. rst = write(fd, write_buf, WRITE_BUF_LEN);
  89. if (rst != WRITE_BUF_LEN)
  90. {
  91. rt_kprintf("[ERROR] Write failed, result = %d, expected = %d\n", rst, WRITE_BUF_LEN);
  92. }
  93. else
  94. {
  95. rt_kprintf("[WRITE] Write successful, %d bytes written\n", rst);
  96. }
  97. uassert_true(rst == WRITE_BUF_LEN);
  98. }
  99. static void test_posix_read(void)
  100. {
  101. ssize_t rst;
  102. char read_buf[32];
  103. rst = lseek(fd, 0, SEEK_SET);
  104. if (rst != 0)
  105. {
  106. rt_kprintf("[ERROR] lseek failed with result = %d\n", rst);
  107. }
  108. uassert_true(rst == 0);
  109. rt_kprintf("[READ] Reading %d bytes from file\n", WRITE_BUF_LEN);
  110. rst = read(fd, read_buf, WRITE_BUF_LEN);
  111. if (rst != WRITE_BUF_LEN)
  112. {
  113. rt_kprintf("[ERROR] Read failed, result = %d, expected = %d\n", rst, WRITE_BUF_LEN);
  114. }
  115. else
  116. {
  117. read_buf[rst] = '\0';
  118. rt_kprintf("[READ] Read successful, %d bytes read: \"%s\"\n", rst, read_buf);
  119. }
  120. uassert_true(rst == WRITE_BUF_LEN);
  121. read_buf[rst] = '\0';
  122. uassert_str_equal(write_buf, read_buf);
  123. }
  124. static void test_posix_close(void)
  125. {
  126. int rst = close(fd);
  127. if (rst != 0)
  128. {
  129. rt_kprintf("[ERROR] Close failed with result = %d\n", rst);
  130. }
  131. uassert_true(rst == 0);
  132. fd = -1;
  133. }
  134. static void test_posix_stat(void)
  135. {
  136. struct stat stat_buf;
  137. int rst = stat(TEST_FILE, &stat_buf);
  138. if (rst != 0)
  139. {
  140. rt_kprintf("[ERROR] stat failed with result = %d\n", rst);
  141. }
  142. uassert_true(rst == 0);
  143. uassert_true(S_ISREG(stat_buf.st_mode));
  144. }
  145. static void test_posix_unlink(void)
  146. {
  147. int rst = unlink(TEST_FILE);
  148. if (rst != 0)
  149. {
  150. rt_kprintf("[ERROR] unlink failed with result = %d\n", rst);
  151. }
  152. uassert_true(rst == 0);
  153. }
  154. static void test_posix_mkdir(void)
  155. {
  156. int rst = mkdir(TEST_DIR, 0755);
  157. if (rst != 0)
  158. {
  159. rt_kprintf("[ERROR] mkdir failed with result = %d\n", rst);
  160. }
  161. uassert_true(rst == 0);
  162. }
  163. static void test_posix_rmdir(void)
  164. {
  165. int rst = rmdir(TEST_DIR);
  166. if (rst != 0)
  167. {
  168. rt_kprintf("[ERROR] rmdir failed with result = %d\n", rst);
  169. }
  170. uassert_true(rst == 0);
  171. }
  172. static void test_posix_rename(void)
  173. {
  174. /* Create a file first */
  175. fd = open(TEST_FILE, O_CREAT | O_RDWR, 0644);
  176. if (fd < 0)
  177. {
  178. rt_kprintf("[ERROR] Failed to create file for rename test\n");
  179. uassert_true(fd >= 0);
  180. return;
  181. }
  182. close(fd);
  183. fd = -1;
  184. /* Rename it */
  185. int rst = rename(TEST_FILE, TEST_RENAME_FILE);
  186. if (rst != 0)
  187. {
  188. rt_kprintf("[ERROR] rename failed with result = %d\n", rst);
  189. /* Clean up the original file if rename failed */
  190. unlink(TEST_FILE);
  191. uassert_true(rst == 0);
  192. return;
  193. }
  194. /* Check old file doesn't exist */
  195. struct stat stat_buf;
  196. rst = stat(TEST_FILE, &stat_buf);
  197. if (rst == 0)
  198. {
  199. rt_kprintf("[ERROR] Old file still exists after rename\n");
  200. /* Clean up both files */
  201. unlink(TEST_FILE);
  202. unlink(TEST_RENAME_FILE);
  203. uassert_true(rst != 0);
  204. return;
  205. }
  206. /* Check new file exists */
  207. rst = stat(TEST_RENAME_FILE, &stat_buf);
  208. if (rst != 0)
  209. {
  210. rt_kprintf("[ERROR] New file does not exist after rename\n");
  211. uassert_true(rst == 0);
  212. return;
  213. }
  214. /* Clean up */
  215. unlink(TEST_RENAME_FILE);
  216. }
  217. static void test_posix_opendir_readdir(void)
  218. {
  219. DIR *dir = NULL;
  220. struct dirent *entry;
  221. /* Create directory and file */
  222. mkdir(TEST_DIR, 0755);
  223. fd = open(TEST_DIR_FILE, O_CREAT | O_RDWR, 0644);
  224. if (fd >= 0)
  225. {
  226. close(fd);
  227. fd = -1;
  228. }
  229. dir = opendir(TEST_DIR);
  230. if (dir == NULL)
  231. {
  232. rt_kprintf("[ERROR] opendir failed\n");
  233. /* Clean up on error */
  234. unlink(TEST_DIR_FILE);
  235. rmdir(TEST_DIR);
  236. uassert_not_null(dir);
  237. return;
  238. }
  239. entry = readdir(dir);
  240. if (entry == NULL)
  241. {
  242. rt_kprintf("[ERROR] readdir failed\n");
  243. closedir(dir);
  244. /* Clean up on error */
  245. unlink(TEST_DIR_FILE);
  246. rmdir(TEST_DIR);
  247. uassert_not_null(entry);
  248. return;
  249. }
  250. /* The filename should match what we created - just the basename, not the full path */
  251. uassert_str_equal(entry->d_name, "RTT.txt"); /* Just the basename */
  252. closedir(dir);
  253. dir = NULL;
  254. /* Clean up */
  255. unlink(TEST_DIR_FILE);
  256. rmdir(TEST_DIR);
  257. }
  258. static void test_posix_lseek(void)
  259. {
  260. /* Create and write to file */
  261. fd = open(TEST_FILE, O_CREAT | O_RDWR, 0644);
  262. if (fd < 0)
  263. {
  264. rt_kprintf("[ERROR] Open failed for lseek test\n");
  265. uassert_true(fd >= 0);
  266. return;
  267. }
  268. ssize_t rst = write(fd, write_buf, WRITE_BUF_LEN);
  269. if (rst != WRITE_BUF_LEN)
  270. {
  271. rt_kprintf("[ERROR] Write failed in lseek test\n");
  272. close(fd);
  273. unlink(TEST_FILE);
  274. uassert_true(rst == WRITE_BUF_LEN);
  275. return;
  276. }
  277. /* Seek to beginning */
  278. off_t pos = lseek(fd, 0, SEEK_SET);
  279. if (pos != 0)
  280. {
  281. rt_kprintf("[ERROR] lseek to SET failed, pos = %ld\n", pos);
  282. }
  283. uassert_true(pos == 0);
  284. /* Seek to end */
  285. pos = lseek(fd, 0, SEEK_END);
  286. if (pos != WRITE_BUF_LEN)
  287. {
  288. rt_kprintf("[ERROR] lseek to END failed, pos = %ld, expected = %d\n", pos, WRITE_BUF_LEN);
  289. }
  290. uassert_true(pos == WRITE_BUF_LEN);
  291. /* Seek from current (back 5 bytes) */
  292. pos = lseek(fd, -5, SEEK_CUR);
  293. if (pos != (WRITE_BUF_LEN - 5))
  294. {
  295. rt_kprintf("[ERROR] lseek CUR failed, pos = %ld\n", pos);
  296. }
  297. uassert_true(pos == (WRITE_BUF_LEN - 5));
  298. close(fd);
  299. fd = -1;
  300. unlink(TEST_FILE);
  301. }
  302. static void test_posix_fstat(void)
  303. {
  304. /* Create and open file */
  305. fd = open(TEST_FILE, O_CREAT | O_RDWR, 0644);
  306. if (fd < 0)
  307. {
  308. rt_kprintf("[ERROR] Open failed for fstat test\n");
  309. uassert_true(fd >= 0);
  310. return;
  311. }
  312. struct stat stat_buf;
  313. int rst = fstat(fd, &stat_buf);
  314. if (rst != 0)
  315. {
  316. rt_kprintf("[ERROR] fstat failed with result = %d\n", rst);
  317. }
  318. uassert_true(rst == 0);
  319. uassert_true(S_ISREG(stat_buf.st_mode));
  320. uassert_true(stat_buf.st_size == 0); /* Initially empty */
  321. close(fd);
  322. fd = -1;
  323. unlink(TEST_FILE);
  324. }
  325. static void test_posix_access(void)
  326. {
  327. /* Create file */
  328. fd = open(TEST_FILE, O_CREAT | O_RDWR, 0644);
  329. if (fd < 0)
  330. {
  331. rt_kprintf("[ERROR] Open failed for access test\n");
  332. uassert_true(fd >= 0);
  333. return;
  334. }
  335. close(fd);
  336. fd = -1;
  337. /* Check existence */
  338. int rst = access(TEST_FILE, F_OK);
  339. if (rst != 0)
  340. {
  341. rt_kprintf("[ERROR] access F_OK failed\n");
  342. }
  343. uassert_true(rst == 0);
  344. /* Check read permission */
  345. rst = access(TEST_FILE, R_OK);
  346. if (rst != 0)
  347. {
  348. rt_kprintf("[ERROR] access R_OK failed\n");
  349. }
  350. uassert_true(rst == 0);
  351. /* Check write permission */
  352. rst = access(TEST_FILE, W_OK);
  353. if (rst != 0)
  354. {
  355. rt_kprintf("[ERROR] access W_OK failed\n");
  356. }
  357. uassert_true(rst == 0);
  358. /* Check execute permission (may not be set) */
  359. rst = access(TEST_FILE, X_OK);
  360. if (rst == 0)
  361. {
  362. rt_kprintf("[WARN] access X_OK succeeded, but file is not executable\n");
  363. }
  364. /* No assert here as it depends on mode */
  365. unlink(TEST_FILE);
  366. }
  367. static void test_posix_chdir_getcwd(void)
  368. {
  369. char cwd[256];
  370. /* Get current working directory */
  371. if (getcwd(cwd, sizeof(cwd)) == NULL)
  372. {
  373. rt_kprintf("[ERROR] getcwd failed initially\n");
  374. uassert_not_null(getcwd(cwd, sizeof(cwd)));
  375. return;
  376. }
  377. rt_kprintf("[CWD] Initial: %s\n", cwd);
  378. /* Create directory */
  379. int rst = mkdir(TEST_CHDIR_DIR, 0755);
  380. if (rst != 0)
  381. {
  382. rt_kprintf("[ERROR] mkdir failed for chdir test\n");
  383. uassert_true(rst == 0);
  384. return;
  385. }
  386. /* Change directory */
  387. rst = chdir(TEST_CHDIR_DIR);
  388. if (rst != 0)
  389. {
  390. rt_kprintf("[ERROR] chdir failed\n");
  391. rmdir(TEST_CHDIR_DIR);
  392. uassert_true(rst == 0);
  393. return;
  394. }
  395. /* Get new cwd */
  396. if (getcwd(cwd, sizeof(cwd)) == NULL)
  397. {
  398. rt_kprintf("[ERROR] getcwd failed after chdir\n");
  399. chdir("..");
  400. rmdir(TEST_CHDIR_DIR);
  401. uassert_not_null(getcwd(cwd, sizeof(cwd)));
  402. return;
  403. }
  404. rt_kprintf("[CWD] After chdir: %s\n", cwd);
  405. uassert_str_equal(cwd, TEST_CHDIR_DIR);
  406. /* Change back */
  407. rst = chdir("..");
  408. if (rst != 0)
  409. {
  410. rt_kprintf("[ERROR] chdir back failed\n");
  411. }
  412. uassert_true(rst == 0);
  413. /* Clean up */
  414. rmdir(TEST_CHDIR_DIR);
  415. }
  416. static rt_err_t utest_tc_init(void)
  417. {
  418. /* Clean up any leftover files from previous runs */
  419. unlink(TEST_FILE);
  420. unlink(TEST_RENAME_FILE);
  421. unlink(TEST_DIR_FILE);
  422. unlink(TEST_LINK_FILE);
  423. rmdir(TEST_DIR);
  424. rmdir(TEST_CHDIR_DIR);
  425. return RT_EOK;
  426. }
  427. static rt_err_t utest_tc_cleanup(void)
  428. {
  429. /* Ensure all resources are cleaned up */
  430. if (fd >= 0)
  431. {
  432. close(fd);
  433. fd = -1;
  434. }
  435. /* Clean up all test files and directories */
  436. unlink(TEST_FILE);
  437. unlink(TEST_RENAME_FILE);
  438. unlink(TEST_DIR_FILE);
  439. unlink(TEST_LINK_FILE);
  440. rmdir(TEST_DIR);
  441. rmdir(TEST_CHDIR_DIR);
  442. return RT_EOK;
  443. }
  444. static void testcase(void)
  445. {
  446. UTEST_UNIT_RUN(test_mkfs);
  447. UTEST_UNIT_RUN(test_mount);
  448. UTEST_UNIT_RUN(test_posix_open);
  449. UTEST_UNIT_RUN(test_posix_write);
  450. UTEST_UNIT_RUN(test_posix_read);
  451. UTEST_UNIT_RUN(test_posix_close);
  452. UTEST_UNIT_RUN(test_posix_stat);
  453. UTEST_UNIT_RUN(test_posix_unlink);
  454. UTEST_UNIT_RUN(test_posix_mkdir);
  455. UTEST_UNIT_RUN(test_posix_rmdir);
  456. UTEST_UNIT_RUN(test_posix_rename);
  457. UTEST_UNIT_RUN(test_posix_opendir_readdir);
  458. UTEST_UNIT_RUN(test_posix_lseek);
  459. UTEST_UNIT_RUN(test_posix_fstat);
  460. UTEST_UNIT_RUN(test_posix_access);
  461. UTEST_UNIT_RUN(test_posix_chdir_getcwd);
  462. }
  463. UTEST_TC_EXPORT(testcase, "components.dfs.fs_posix_api_tc", utest_tc_init, utest_tc_cleanup, 10);