host_test_spiffs.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /*
  2. * SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include <stdint.h>
  9. #include <stdlib.h>
  10. #include <sys/mman.h>
  11. #include <sys/stat.h>
  12. #include <sys/types.h>
  13. #include <dirent.h>
  14. #include <limits.h>
  15. #include <unistd.h>
  16. #include "Mockqueue.h"
  17. #include "esp_partition.h"
  18. #include "spiffs.h"
  19. #include "spiffs_nucleus.h"
  20. #include "spiffs_api.h"
  21. #include "unity.h"
  22. #include "unity_fixture.h"
  23. TEST_GROUP(spiffs);
  24. TEST_SETUP(spiffs)
  25. {
  26. // CMock init for spiffs xSemaphore* use
  27. xQueueSemaphoreTake_IgnoreAndReturn(0);
  28. xQueueGenericSend_IgnoreAndReturn(0);
  29. }
  30. TEST_TEAR_DOWN(spiffs)
  31. {
  32. }
  33. static void init_spiffs(spiffs *fs, uint32_t max_files)
  34. {
  35. spiffs_config cfg = {};
  36. s32_t spiffs_res;
  37. u32_t flash_sector_size;
  38. const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_SPIFFS, "storage");
  39. TEST_ASSERT_NOT_NULL(partition);
  40. // Configure objects needed by SPIFFS
  41. esp_spiffs_t *user_data = (esp_spiffs_t *) calloc(1, sizeof(*user_data));
  42. user_data->partition = partition;
  43. fs->user_data = (void *)user_data;
  44. flash_sector_size = 4096;
  45. cfg.hal_erase_f = spiffs_api_erase;
  46. cfg.hal_read_f = spiffs_api_read;
  47. cfg.hal_write_f = spiffs_api_write;
  48. cfg.log_block_size = flash_sector_size;
  49. cfg.log_page_size = CONFIG_SPIFFS_PAGE_SIZE;
  50. cfg.phys_addr = 0;
  51. cfg.phys_erase_block = flash_sector_size;
  52. cfg.phys_size = partition->size;
  53. uint32_t work_sz = cfg.log_page_size * 2;
  54. uint8_t *work = (uint8_t *) malloc(work_sz);
  55. uint32_t fds_sz = max_files * sizeof(spiffs_fd);
  56. uint8_t *fds = (uint8_t *) malloc(fds_sz);
  57. #if CONFIG_SPIFFS_CACHE
  58. uint32_t cache_sz = sizeof(spiffs_cache) + max_files * (sizeof(spiffs_cache_page)
  59. + cfg.log_page_size);
  60. uint8_t *cache = (uint8_t *) malloc(cache_sz);
  61. #else
  62. uint32_t cache_sz = 0;
  63. uint8_t cache = NULL;
  64. #endif
  65. // Special mounting procedure: mount, format, mount as per
  66. // https://github.com/pellepl/spiffs/wiki/Using-spiffs
  67. spiffs_res = SPIFFS_mount(fs, &cfg, work, fds, fds_sz,
  68. cache, cache_sz, spiffs_api_check);
  69. if (spiffs_res == SPIFFS_ERR_NOT_A_FS) {
  70. spiffs_res = SPIFFS_format(fs);
  71. TEST_ASSERT_TRUE(spiffs_res >= SPIFFS_OK);
  72. spiffs_res = SPIFFS_mount(fs, &cfg, work, fds, fds_sz,
  73. cache, cache_sz, spiffs_api_check);
  74. }
  75. TEST_ASSERT_TRUE(spiffs_res >= SPIFFS_OK);
  76. }
  77. static void deinit_spiffs(spiffs *fs)
  78. {
  79. SPIFFS_unmount(fs);
  80. free(fs->work);
  81. free(fs->user_data);
  82. free(fs->fd_space);
  83. #if CONFIG_SPIFFS_CACHE
  84. free(fs->cache);
  85. #endif
  86. }
  87. static void check_spiffs_files(spiffs *fs, const char *base_path, char *cur_path)
  88. {
  89. DIR *dir;
  90. struct dirent *entry;
  91. size_t len = strlen(cur_path);
  92. if (len == 0) {
  93. strcpy(cur_path, base_path);
  94. len = strlen(base_path);
  95. }
  96. dir = opendir(cur_path);
  97. TEST_ASSERT_TRUE(dir != 0);
  98. while ((entry = readdir(dir)) != NULL) {
  99. char *name = entry->d_name;
  100. char path[PATH_MAX] = { 0 };
  101. // Read the file from host FS
  102. strcpy(path, cur_path);
  103. strcat(path, "/");
  104. strcat(path, name);
  105. struct stat sb;
  106. stat(path, &sb);
  107. if (S_ISDIR(sb.st_mode)) {
  108. if (!strcmp(name, ".") || !strcmp(name, "..")) {
  109. continue;
  110. }
  111. cur_path[len] = '/';
  112. strcpy(cur_path + len + 1, name);
  113. check_spiffs_files(fs, base_path, cur_path);
  114. cur_path[len] = '\0';
  115. } else {
  116. FILE *f = fopen(path, "r");
  117. TEST_ASSERT_NOT_NULL(f);
  118. fseek(f, 0, SEEK_END);
  119. long sz = ftell(f);
  120. fseek(f, 0, SEEK_SET);
  121. char *f_contents = (char *) malloc(sz);
  122. TEST_ASSERT(fread(f_contents, 1, sz, f) == sz);
  123. fclose(f);
  124. s32_t spiffs_res;
  125. // Read the file from SPIFFS
  126. char *spiffs_path = path + strlen(base_path);
  127. spiffs_res = SPIFFS_open(fs, spiffs_path, SPIFFS_RDONLY, 0);
  128. TEST_ASSERT_TRUE(spiffs_res > SPIFFS_OK);
  129. spiffs_file fd = spiffs_res;
  130. spiffs_stat stat;
  131. spiffs_res = SPIFFS_stat(fs, spiffs_path, &stat);
  132. char *spiffs_f_contents = (char *) malloc(stat.size);
  133. spiffs_res = SPIFFS_read(fs, fd, spiffs_f_contents, stat.size);
  134. TEST_ASSERT_TRUE(spiffs_res == stat.size);
  135. // Compare the contents
  136. TEST_ASSERT_TRUE(sz == stat.size);
  137. bool same = memcmp(f_contents, spiffs_f_contents, sz) == 0;
  138. TEST_ASSERT_TRUE(same);
  139. free(f_contents);
  140. free(spiffs_f_contents);
  141. }
  142. }
  143. closedir(dir);
  144. }
  145. TEST(spiffs, format_disk_open_file_write_and_read_file)
  146. {
  147. spiffs fs;
  148. s32_t spiffs_res;
  149. init_spiffs(&fs, 5);
  150. // Open test file
  151. spiffs_res = SPIFFS_open(&fs, "test.txt", SPIFFS_O_CREAT | SPIFFS_O_RDWR, 0);
  152. TEST_ASSERT_TRUE(spiffs_res >= SPIFFS_OK);
  153. // Generate data
  154. spiffs_file file = spiffs_res;
  155. uint32_t data_count = 5000;
  156. uint32_t data_size = data_count * sizeof(uint32_t);
  157. char *data = (char *) malloc(data_size);
  158. char *read = (char *) malloc(data_size);
  159. for (uint32_t i = 0; i < data_size; i += sizeof(i)) {
  160. *((uint32_t *)(data + i)) = i;
  161. }
  162. // Write data to file
  163. spiffs_res = SPIFFS_write(&fs, file, (void *)data, data_size);
  164. TEST_ASSERT_TRUE(spiffs_res >= SPIFFS_OK);
  165. TEST_ASSERT_TRUE(spiffs_res == data_size);
  166. // Set the file object pointer to the beginning
  167. spiffs_res = SPIFFS_lseek(&fs, file, 0, SPIFFS_SEEK_SET);
  168. TEST_ASSERT_TRUE(spiffs_res >= SPIFFS_OK);
  169. // Read the file
  170. spiffs_res = SPIFFS_read(&fs, file, (void *)read, data_size);
  171. TEST_ASSERT_TRUE(spiffs_res >= SPIFFS_OK);
  172. TEST_ASSERT_TRUE(spiffs_res == data_size);
  173. // Close the test file
  174. spiffs_res = SPIFFS_close(&fs, file);
  175. TEST_ASSERT_TRUE(spiffs_res >= SPIFFS_OK);
  176. TEST_ASSERT_TRUE(memcmp(data, read, data_size) == 0);
  177. deinit_spiffs(&fs);
  178. free(read);
  179. free(data);
  180. }
  181. TEST(spiffs, can_read_spiffs_image)
  182. {
  183. spiffs fs;
  184. s32_t spiffs_res;
  185. const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_SPIFFS, "storage");
  186. TEST_ASSERT_NOT_NULL(partition);
  187. // Write the contents of the image file to partition
  188. FILE *img_file = fopen(BUILD_DIR "/image.bin", "r");
  189. TEST_ASSERT_NOT_NULL(img_file);
  190. fseek(img_file, 0, SEEK_END);
  191. long img_size = ftell(img_file);
  192. fseek(img_file, 0, SEEK_SET);
  193. char *img = (char *) malloc(img_size);
  194. TEST_ASSERT(fread(img, 1, img_size, img_file) == img_size);
  195. fclose(img_file);
  196. TEST_ASSERT_EQUAL(partition->size, img_size);
  197. esp_partition_erase_range(partition, 0, partition->size);
  198. esp_partition_write(partition, 0, img, img_size);
  199. free(img);
  200. // Mount the spiffs partition and init filesystem, using the contents of
  201. // the image file
  202. init_spiffs(&fs, 1024);
  203. // Check spiffs consistency
  204. spiffs_res = SPIFFS_check(&fs);
  205. TEST_ASSERT_TRUE(spiffs_res == SPIFFS_OK);
  206. char path_buf[PATH_MAX] = {0};
  207. // The image is created from the spiffs source directory. Compare the files in that
  208. // directory to the files read from the SPIFFS image.
  209. check_spiffs_files(&fs, BUILD_DIR "/../../spiffs", path_buf);
  210. deinit_spiffs(&fs);
  211. }
  212. TEST_GROUP_RUNNER(spiffs)
  213. {
  214. RUN_TEST_CASE(spiffs, format_disk_open_file_write_and_read_file);
  215. RUN_TEST_CASE(spiffs, can_read_spiffs_image);
  216. }
  217. static void run_all_tests(void)
  218. {
  219. RUN_TEST_GROUP(spiffs);
  220. }
  221. int main(int argc, char **argv)
  222. {
  223. UNITY_MAIN_FUNC(run_all_tests);
  224. return 0;
  225. }