test_nvs.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941
  1. // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
  2. //
  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. // http://www.apache.org/licenses/LICENSE-2.0
  7. //
  8. // Unless required by applicable law or agreed to in writing, software
  9. // distributed under the License is distributed on an "AS IS" BASIS,
  10. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. #include "catch.hpp"
  14. #include "nvs.hpp"
  15. #include "nvs_flash.h"
  16. #include "spi_flash_emulation.h"
  17. #include <sstream>
  18. #include <iostream>
  19. using namespace std;
  20. using namespace nvs;
  21. stringstream s_perf;
  22. void dumpBytes(const uint8_t* data, size_t count)
  23. {
  24. for (uint32_t i = 0; i < count; ++i) {
  25. if (i % 32 == 0) {
  26. printf("%08x ", i);
  27. }
  28. printf("%02x ", data[i]);
  29. if ((i + 1) % 32 == 0) {
  30. printf("\n");
  31. }
  32. }
  33. }
  34. TEST_CASE("crc32 behaves as expected", "[nvs]")
  35. {
  36. Item item1;
  37. item1.datatype = ItemType::I32;
  38. item1.nsIndex = 1;
  39. item1.crc32 = 0;
  40. item1.reserved = 0xff;
  41. fill_n(item1.key, sizeof(item1.key), 0xbb);
  42. fill_n(item1.data, sizeof(item1.data), 0xaa);
  43. auto crc32_1 = item1.calculateCrc32();
  44. Item item2 = item1;
  45. item2.crc32 = crc32_1;
  46. CHECK(crc32_1 == item2.calculateCrc32());
  47. item2 = item1;
  48. item2.nsIndex = 2;
  49. CHECK(crc32_1 != item2.calculateCrc32());
  50. item2 = item1;
  51. item2.datatype = ItemType::U32;
  52. CHECK(crc32_1 != item2.calculateCrc32());
  53. item2 = item1;
  54. strncpy(item2.key, "foo", Item::MAX_KEY_LENGTH);
  55. CHECK(crc32_1 != item2.calculateCrc32());
  56. }
  57. TEST_CASE("starting with empty flash, page is in uninitialized state", "[nvs]")
  58. {
  59. SpiFlashEmulator emu(1);
  60. Page page;
  61. CHECK(page.state() == Page::PageState::INVALID);
  62. CHECK(page.load(0) == ESP_OK);
  63. CHECK(page.state() == Page::PageState::UNINITIALIZED);
  64. }
  65. TEST_CASE("can distinguish namespaces", "[nvs]")
  66. {
  67. SpiFlashEmulator emu(1);
  68. Page page;
  69. CHECK(page.load(0) == ESP_OK);
  70. int32_t val1 = 0x12345678;
  71. CHECK(page.writeItem(1, ItemType::I32, "intval1", &val1, sizeof(val1)) == ESP_OK);
  72. int32_t val2 = 0x23456789;
  73. CHECK(page.writeItem(2, ItemType::I32, "intval1", &val2, sizeof(val2)) == ESP_OK);
  74. int32_t readVal;
  75. CHECK(page.readItem(2, ItemType::I32, "intval1", &readVal, sizeof(readVal)) == ESP_OK);
  76. CHECK(readVal == val2);
  77. }
  78. TEST_CASE("reading with different type causes type mismatch error", "[nvs]")
  79. {
  80. SpiFlashEmulator emu(1);
  81. Page page;
  82. CHECK(page.load(0) == ESP_OK);
  83. int32_t val = 0x12345678;
  84. CHECK(page.writeItem(1, ItemType::I32, "intval1", &val, sizeof(val)) == ESP_OK);
  85. CHECK(page.readItem(1, ItemType::U32, "intval1", &val, sizeof(val)) == ESP_ERR_NVS_TYPE_MISMATCH);
  86. }
  87. TEST_CASE("when page is erased, it's state becomes UNITIALIZED", "[nvs]")
  88. {
  89. SpiFlashEmulator emu(1);
  90. Page page;
  91. CHECK(page.load(0) == ESP_OK);
  92. int32_t val = 0x12345678;
  93. CHECK(page.writeItem(1, ItemType::I32, "intval1", &val, sizeof(val)) == ESP_OK);
  94. CHECK(page.erase() == ESP_OK);
  95. CHECK(page.state() == Page::PageState::UNINITIALIZED);
  96. }
  97. TEST_CASE("when writing and erasing, used/erased counts are updated correctly", "[nvs]")
  98. {
  99. SpiFlashEmulator emu(1);
  100. Page page;
  101. CHECK(page.load(0) == ESP_OK);
  102. CHECK(page.getUsedEntryCount() == 0);
  103. CHECK(page.getErasedEntryCount() == 0);
  104. uint32_t foo1 = 0;
  105. CHECK(page.writeItem(1, "foo1", foo1) == ESP_OK);
  106. CHECK(page.getUsedEntryCount() == 1);
  107. CHECK(page.writeItem(2, "foo1", foo1) == ESP_OK);
  108. CHECK(page.getUsedEntryCount() == 2);
  109. CHECK(page.eraseItem<uint32_t>(2, "foo1") == ESP_OK);
  110. CHECK(page.getUsedEntryCount() == 1);
  111. CHECK(page.getErasedEntryCount() == 1);
  112. for (size_t i = 0; i < Page::ENTRY_COUNT - 2; ++i) {
  113. char name[16];
  114. snprintf(name, sizeof(name), "i%ld", i);
  115. CHECK(page.writeItem(1, name, i) == ESP_OK);
  116. }
  117. CHECK(page.getUsedEntryCount() == Page::ENTRY_COUNT - 1);
  118. CHECK(page.getErasedEntryCount() == 1);
  119. for (size_t i = 0; i < Page::ENTRY_COUNT - 2; ++i) {
  120. char name[16];
  121. snprintf(name, sizeof(name), "i%ld", i);
  122. CHECK(page.eraseItem(1, itemTypeOf<size_t>(), name) == ESP_OK);
  123. }
  124. CHECK(page.getUsedEntryCount() == 1);
  125. CHECK(page.getErasedEntryCount() == Page::ENTRY_COUNT - 1);
  126. }
  127. TEST_CASE("when page is full, adding an element fails", "[nvs]")
  128. {
  129. SpiFlashEmulator emu(1);
  130. Page page;
  131. CHECK(page.load(0) == ESP_OK);
  132. for (size_t i = 0; i < Page::ENTRY_COUNT; ++i) {
  133. char name[16];
  134. snprintf(name, sizeof(name), "i%ld", i);
  135. CHECK(page.writeItem(1, name, i) == ESP_OK);
  136. }
  137. CHECK(page.writeItem(1, "foo", 64UL) == ESP_ERR_NVS_PAGE_FULL);
  138. }
  139. TEST_CASE("page maintains its seq number")
  140. {
  141. SpiFlashEmulator emu(1);
  142. {
  143. Page page;
  144. CHECK(page.load(0) == ESP_OK);
  145. CHECK(page.setSeqNumber(123) == ESP_OK);
  146. int32_t val = 42;
  147. CHECK(page.writeItem(1, ItemType::I32, "dummy", &val, sizeof(val)) == ESP_OK);
  148. }
  149. {
  150. Page page;
  151. CHECK(page.load(0) == ESP_OK);
  152. uint32_t seqno;
  153. CHECK(page.getSeqNumber(seqno) == ESP_OK);
  154. CHECK(seqno == 123);
  155. }
  156. }
  157. TEST_CASE("can write and read variable length data", "[nvs]")
  158. {
  159. SpiFlashEmulator emu(1);
  160. Page page;
  161. CHECK(page.load(0) == ESP_OK);
  162. const char str[] = "foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234";
  163. size_t len = strlen(str);
  164. CHECK(page.writeItem(1, "stuff1", 42) == ESP_OK);
  165. CHECK(page.writeItem(1, "stuff2", 1) == ESP_OK);
  166. CHECK(page.writeItem(1, ItemType::SZ, "foobaar", str, len + 1) == ESP_OK);
  167. CHECK(page.writeItem(1, "stuff3", 2) == ESP_OK);
  168. CHECK(page.writeItem(1, ItemType::BLOB, "baz", str, len) == ESP_OK);
  169. CHECK(page.writeItem(1, "stuff4", 0x7abbccdd) == ESP_OK);
  170. char buf[sizeof(str) + 16];
  171. int32_t value;
  172. CHECK(page.readItem(1, "stuff1", value) == ESP_OK);
  173. CHECK(value == 42);
  174. CHECK(page.readItem(1, "stuff2", value) == ESP_OK);
  175. CHECK(value == 1);
  176. CHECK(page.readItem(1, "stuff3", value) == ESP_OK);
  177. CHECK(value == 2);
  178. CHECK(page.readItem(1, "stuff4", value) == ESP_OK);
  179. CHECK(value == 0x7abbccdd);
  180. fill_n(buf, sizeof(buf), 0xff);
  181. CHECK(page.readItem(1, ItemType::SZ, "foobaar", buf, sizeof(buf)) == ESP_OK);
  182. CHECK(memcmp(buf, str, strlen(str) + 1) == 0);
  183. fill_n(buf, sizeof(buf), 0xff);
  184. CHECK(page.readItem(1, ItemType::BLOB, "baz", buf, sizeof(buf)) == ESP_OK);
  185. CHECK(memcmp(buf, str, strlen(str)) == 0);
  186. }
  187. TEST_CASE("can init PageManager in empty flash", "[nvs]")
  188. {
  189. SpiFlashEmulator emu(4);
  190. PageManager pm;
  191. CHECK(pm.load(0, 4) == ESP_OK);
  192. }
  193. TEST_CASE("PageManager adds page in the correct order", "[nvs]")
  194. {
  195. const size_t pageCount = 8;
  196. SpiFlashEmulator emu(pageCount);
  197. uint32_t pageNo[pageCount] = { -1U, 50, 11, -1U, 23, 22, 24, 49};
  198. for (uint32_t i = 0; i < pageCount; ++i) {
  199. Page p;
  200. p.load(i);
  201. if (pageNo[i] != -1U) {
  202. p.setSeqNumber(pageNo[i]);
  203. p.writeItem(1, "foo", 10U);
  204. }
  205. }
  206. PageManager pageManager;
  207. CHECK(pageManager.load(0, pageCount) == ESP_OK);
  208. uint32_t lastSeqNo = 0;
  209. for (auto it = std::begin(pageManager); it != std::end(pageManager); ++it) {
  210. uint32_t seqNo;
  211. CHECK(it->getSeqNumber(seqNo) == ESP_OK);
  212. CHECK(seqNo > lastSeqNo);
  213. }
  214. }
  215. TEST_CASE("can init storage in empty flash", "[nvs]")
  216. {
  217. SpiFlashEmulator emu(8);
  218. Storage storage;
  219. emu.setBounds(4, 8);
  220. CHECK(storage.init(4, 4) == ESP_OK);
  221. s_perf << "Time to init empty storage (4 sectors): " << emu.getTotalTime() << " us" << std::endl;
  222. }
  223. TEST_CASE("storage doesn't add duplicates within one page", "[nvs]")
  224. {
  225. SpiFlashEmulator emu(8);
  226. Storage storage;
  227. emu.setBounds(4, 8);
  228. CHECK(storage.init(4, 4) == ESP_OK);
  229. int bar = 0;
  230. CHECK(storage.writeItem(1, "bar", bar) == ESP_OK);
  231. CHECK(storage.writeItem(1, "bar", bar) == ESP_OK);
  232. Page page;
  233. page.load(4);
  234. CHECK(page.getUsedEntryCount() == 1);
  235. CHECK(page.getErasedEntryCount() == 1);
  236. }
  237. TEST_CASE("can write one item a thousand times", "[nvs]")
  238. {
  239. SpiFlashEmulator emu(8);
  240. Storage storage;
  241. emu.setBounds(4, 8);
  242. CHECK(storage.init(4, 4) == ESP_OK);
  243. for (size_t i = 0; i < Page::ENTRY_COUNT * 4 * 2; ++i) {
  244. REQUIRE(storage.writeItem(1, "i", static_cast<int>(i)) == ESP_OK);
  245. }
  246. s_perf << "Time to write one item a thousand times: " << emu.getTotalTime() << " us (" << emu.getEraseOps() << " " << emu.getWriteOps() << " " << emu.getReadOps() << " " << emu.getWriteBytes() << " " << emu.getReadBytes() << ")" << std::endl;
  247. }
  248. TEST_CASE("storage doesn't add duplicates within multiple pages", "[nvs]")
  249. {
  250. SpiFlashEmulator emu(8);
  251. Storage storage;
  252. emu.setBounds(4, 8);
  253. CHECK(storage.init(4, 4) == ESP_OK);
  254. int bar = 0;
  255. CHECK(storage.writeItem(1, "bar", bar) == ESP_OK);
  256. for (size_t i = 0; i < Page::ENTRY_COUNT; ++i) {
  257. CHECK(storage.writeItem(1, "foo", static_cast<int>(bar)) == ESP_OK);
  258. }
  259. CHECK(storage.writeItem(1, "bar", bar) == ESP_OK);
  260. Page page;
  261. page.load(4);
  262. CHECK(page.findItem(1, itemTypeOf<int>(), "bar") == ESP_ERR_NVS_NOT_FOUND);
  263. page.load(5);
  264. CHECK(page.findItem(1, itemTypeOf<int>(), "bar") == ESP_OK);
  265. }
  266. TEST_CASE("can write and read variable length data lots of times", "[nvs]")
  267. {
  268. SpiFlashEmulator emu(8);
  269. Storage storage;
  270. emu.setBounds(4, 8);
  271. CHECK(storage.init(4, 4) == ESP_OK);
  272. const char str[] = "foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234";
  273. char buf[sizeof(str) + 16];
  274. size_t len = strlen(str);
  275. for (size_t i = 0; i < Page::ENTRY_COUNT * 4 * 2; ++i) {
  276. CAPTURE(i);
  277. CHECK(storage.writeItem(1, ItemType::SZ, "foobaar", str, len + 1) == ESP_OK);
  278. CHECK(storage.writeItem(1, "foo", static_cast<uint32_t>(i)) == ESP_OK);
  279. uint32_t value;
  280. CHECK(storage.readItem(1, "foo", value) == ESP_OK);
  281. CHECK(value == i);
  282. fill_n(buf, sizeof(buf), 0xff);
  283. CHECK(storage.readItem(1, ItemType::SZ, "foobaar", buf, sizeof(buf)) == ESP_OK);
  284. CHECK(memcmp(buf, str, strlen(str) + 1) == 0);
  285. }
  286. s_perf << "Time to write one string and one integer a thousand times: " << emu.getTotalTime() << " us (" << emu.getEraseOps() << " " << emu.getWriteOps() << " " << emu.getReadOps() << " " << emu.getWriteBytes() << " " << emu.getReadBytes() << ")" << std::endl;
  287. }
  288. TEST_CASE("can get length of variable length data", "[nvs]")
  289. {
  290. SpiFlashEmulator emu(8);
  291. emu.randomize(200);
  292. Storage storage;
  293. emu.setBounds(4, 8);
  294. CHECK(storage.init(4, 4) == ESP_OK);
  295. const char str[] = "foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234";
  296. size_t len = strlen(str);
  297. CHECK(storage.writeItem(1, ItemType::SZ, "foobaar", str, len + 1) == ESP_OK);
  298. size_t dataSize;
  299. CHECK(storage.getItemDataSize(1, ItemType::SZ, "foobaar", dataSize) == ESP_OK);
  300. CHECK(dataSize == len + 1);
  301. CHECK(storage.writeItem(2, ItemType::BLOB, "foobaar", str, len) == ESP_OK);
  302. CHECK(storage.getItemDataSize(2, ItemType::BLOB, "foobaar", dataSize) == ESP_OK);
  303. CHECK(dataSize == len);
  304. }
  305. TEST_CASE("can create namespaces", "[nvs]")
  306. {
  307. SpiFlashEmulator emu(8);
  308. Storage storage;
  309. emu.setBounds(4, 8);
  310. CHECK(storage.init(4, 4) == ESP_OK);
  311. uint8_t nsi;
  312. CHECK(storage.createOrOpenNamespace("wifi", false, nsi) == ESP_ERR_NVS_NOT_FOUND);
  313. CHECK(storage.createOrOpenNamespace("wifi", true, nsi) == ESP_OK);
  314. Page page;
  315. page.load(4);
  316. CHECK(page.findItem(Page::NS_INDEX, ItemType::U8, "wifi") == ESP_OK);
  317. }
  318. TEST_CASE("storage may become full", "[nvs]")
  319. {
  320. SpiFlashEmulator emu(8);
  321. Storage storage;
  322. emu.setBounds(4, 8);
  323. CHECK(storage.init(4, 4) == ESP_OK);
  324. for (size_t i = 0; i < Page::ENTRY_COUNT * 3; ++i) {
  325. char name[Item::MAX_KEY_LENGTH + 1];
  326. snprintf(name, sizeof(name), "key%05d", static_cast<int>(i));
  327. REQUIRE(storage.writeItem(1, name, static_cast<int>(i)) == ESP_OK);
  328. }
  329. REQUIRE(storage.writeItem(1, "foo", 10) == ESP_ERR_NVS_NOT_ENOUGH_SPACE);
  330. }
  331. TEST_CASE("can modify an item on a page which will be erased", "[nvs]")
  332. {
  333. SpiFlashEmulator emu(2);
  334. Storage storage;
  335. CHECK(storage.init(0, 2) == ESP_OK);
  336. for (size_t i = 0; i < Page::ENTRY_COUNT * 3 + 1; ++i) {
  337. REQUIRE(storage.writeItem(1, "foo", 42U) == ESP_OK);
  338. }
  339. }
  340. TEST_CASE("can erase items", "[nvs]")
  341. {
  342. SpiFlashEmulator emu(3);
  343. Storage storage;
  344. CHECK(storage.init(0, 3) == ESP_OK);
  345. for (size_t i = 0; i < Page::ENTRY_COUNT * 2 - 3; ++i) {
  346. char name[Item::MAX_KEY_LENGTH + 1];
  347. snprintf(name, sizeof(name), "key%05d", static_cast<int>(i));
  348. REQUIRE(storage.writeItem(3, name, static_cast<int>(i)) == ESP_OK);
  349. }
  350. CHECK(storage.writeItem(1, "foo", 32) == ESP_OK);
  351. CHECK(storage.writeItem(2, "foo", 64) == ESP_OK);
  352. CHECK(storage.eraseItem(2, "foo") == ESP_OK);
  353. int val;
  354. CHECK(storage.readItem(1, "foo", val) == ESP_OK);
  355. CHECK(val == 32);
  356. CHECK(storage.eraseNamespace(3) == ESP_OK);
  357. CHECK(storage.readItem(2, "foo", val) == ESP_ERR_NVS_NOT_FOUND);
  358. CHECK(storage.readItem(3, "key00222", val) == ESP_ERR_NVS_NOT_FOUND);
  359. }
  360. #define TEST_ESP_ERR(rc, res) CHECK((rc) == (res))
  361. #define TEST_ESP_OK(rc) CHECK((rc) == ESP_OK)
  362. TEST_CASE("nvs api tests", "[nvs]")
  363. {
  364. SpiFlashEmulator emu(10);
  365. emu.randomize(100);
  366. nvs_handle handle_1;
  367. const uint32_t NVS_FLASH_SECTOR = 6;
  368. const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
  369. emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
  370. TEST_ESP_ERR(nvs_open("namespace1", NVS_READWRITE, &handle_1), ESP_ERR_NVS_NOT_INITIALIZED);
  371. for (uint16_t i = NVS_FLASH_SECTOR; i <NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN; ++i) {
  372. spi_flash_erase_sector(i);
  373. }
  374. TEST_ESP_OK(nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  375. TEST_ESP_ERR(nvs_open("namespace1", NVS_READONLY, &handle_1), ESP_ERR_NVS_NOT_FOUND);
  376. // TEST_ESP_ERR(nvs_set_i32(handle_1, "foo", 0x12345678), ESP_ERR_NVS_READ_ONLY);
  377. // nvs_close(handle_1);
  378. TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle_1));
  379. TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x12345678));
  380. TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x23456789));
  381. nvs_handle handle_2;
  382. TEST_ESP_OK(nvs_open("namespace2", NVS_READWRITE, &handle_2));
  383. TEST_ESP_OK(nvs_set_i32(handle_2, "foo", 0x3456789a));
  384. const char* str = "value 0123456789abcdef0123456789abcdef";
  385. TEST_ESP_OK(nvs_set_str(handle_2, "key", str));
  386. int32_t v1;
  387. TEST_ESP_OK(nvs_get_i32(handle_1, "foo", &v1));
  388. CHECK(0x23456789 == v1);
  389. int32_t v2;
  390. TEST_ESP_OK(nvs_get_i32(handle_2, "foo", &v2));
  391. CHECK(0x3456789a == v2);
  392. char buf[strlen(str) + 1];
  393. size_t buf_len = sizeof(buf);
  394. TEST_ESP_OK(nvs_get_str(handle_2, "key", buf, &buf_len));
  395. CHECK(0 == strcmp(buf, str));
  396. }
  397. TEST_CASE("wifi test", "[nvs]")
  398. {
  399. SpiFlashEmulator emu(10);
  400. emu.randomize(10);
  401. const uint32_t NVS_FLASH_SECTOR = 5;
  402. const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
  403. emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
  404. TEST_ESP_OK(nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  405. nvs_handle misc_handle;
  406. TEST_ESP_OK(nvs_open("nvs.net80211", NVS_READWRITE, &misc_handle));
  407. char log[33];
  408. size_t log_size = sizeof(log);
  409. TEST_ESP_ERR(nvs_get_str(misc_handle, "log", log, &log_size), ESP_ERR_NVS_NOT_FOUND);
  410. strcpy(log, "foobarbazfizzz");
  411. TEST_ESP_OK(nvs_set_str(misc_handle, "log", log));
  412. nvs_handle net80211_handle;
  413. TEST_ESP_OK(nvs_open("nvs.net80211", NVS_READWRITE, &net80211_handle));
  414. uint8_t opmode = 2;
  415. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "wifi.opmode", &opmode), ESP_ERR_NVS_NOT_FOUND);
  416. TEST_ESP_OK(nvs_set_u8(net80211_handle, "wifi.opmode", opmode));
  417. uint8_t country = 0;
  418. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "wifi.country", &opmode), ESP_ERR_NVS_NOT_FOUND);
  419. TEST_ESP_OK(nvs_set_u8(net80211_handle, "wifi.country", opmode));
  420. char ssid[36];
  421. size_t size = sizeof(ssid);
  422. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.ssid", ssid, &size), ESP_ERR_NVS_NOT_FOUND);
  423. strcpy(ssid, "my android AP");
  424. TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.ssid", ssid, size));
  425. char mac[6];
  426. size = sizeof(mac);
  427. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.mac", mac, &size), ESP_ERR_NVS_NOT_FOUND);
  428. memset(mac, 0xab, 6);
  429. TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.mac", mac, size));
  430. uint8_t authmode = 1;
  431. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "sta.authmode", &authmode), ESP_ERR_NVS_NOT_FOUND);
  432. TEST_ESP_OK(nvs_set_u8(net80211_handle, "sta.authmode", authmode));
  433. char pswd[65];
  434. size = sizeof(pswd);
  435. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.pswd", pswd, &size), ESP_ERR_NVS_NOT_FOUND);
  436. strcpy(pswd, "`123456788990-=");
  437. TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.pswd", pswd, size));
  438. char pmk[32];
  439. size = sizeof(pmk);
  440. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.pmk", pmk, &size), ESP_ERR_NVS_NOT_FOUND);
  441. memset(pmk, 1, size);
  442. TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.pmk", pmk, size));
  443. uint8_t chan = 1;
  444. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "sta.chan", &chan), ESP_ERR_NVS_NOT_FOUND);
  445. TEST_ESP_OK(nvs_set_u8(net80211_handle, "sta.chan", chan));
  446. uint8_t autoconn = 1;
  447. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "auto.conn", &autoconn), ESP_ERR_NVS_NOT_FOUND);
  448. TEST_ESP_OK(nvs_set_u8(net80211_handle, "auto.conn", autoconn));
  449. uint8_t bssid_set = 1;
  450. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "bssid.set", &bssid_set), ESP_ERR_NVS_NOT_FOUND);
  451. TEST_ESP_OK(nvs_set_u8(net80211_handle, "bssid.set", bssid_set));
  452. char bssid[6];
  453. size = sizeof(bssid);
  454. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.bssid", bssid, &size), ESP_ERR_NVS_NOT_FOUND);
  455. memset(mac, 0xcd, 6);
  456. TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.bssid", bssid, size));
  457. uint8_t phym = 3;
  458. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "sta.phym", &phym), ESP_ERR_NVS_NOT_FOUND);
  459. TEST_ESP_OK(nvs_set_u8(net80211_handle, "sta.phym", phym));
  460. uint8_t phybw = 2;
  461. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "sta.phybw", &phybw), ESP_ERR_NVS_NOT_FOUND);
  462. TEST_ESP_OK(nvs_set_u8(net80211_handle, "sta.phybw", phybw));
  463. char apsw[2];
  464. size = sizeof(apsw);
  465. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.apsw", apsw, &size), ESP_ERR_NVS_NOT_FOUND);
  466. memset(apsw, 0x2, size);
  467. TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.apsw", apsw, size));
  468. char apinfo[700];
  469. size = sizeof(apinfo);
  470. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.apinfo", apinfo, &size), ESP_ERR_NVS_NOT_FOUND);
  471. memset(apinfo, 0, size);
  472. TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.apinfo", apinfo, size));
  473. size = sizeof(ssid);
  474. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "ap.ssid", ssid, &size), ESP_ERR_NVS_NOT_FOUND);
  475. strcpy(ssid, "ESP_A2F340");
  476. TEST_ESP_OK(nvs_set_blob(net80211_handle, "ap.ssid", ssid, size));
  477. size = sizeof(mac);
  478. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "ap.mac", mac, &size), ESP_ERR_NVS_NOT_FOUND);
  479. memset(mac, 0xac, 6);
  480. TEST_ESP_OK(nvs_set_blob(net80211_handle, "ap.mac", mac, size));
  481. size = sizeof(pswd);
  482. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "ap.passwd", pswd, &size), ESP_ERR_NVS_NOT_FOUND);
  483. strcpy(pswd, "");
  484. TEST_ESP_OK(nvs_set_blob(net80211_handle, "ap.passwd", pswd, size));
  485. size = sizeof(pmk);
  486. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "ap.pmk", pmk, &size), ESP_ERR_NVS_NOT_FOUND);
  487. memset(pmk, 1, size);
  488. TEST_ESP_OK(nvs_set_blob(net80211_handle, "ap.pmk", pmk, size));
  489. chan = 6;
  490. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "ap.chan", &chan), ESP_ERR_NVS_NOT_FOUND);
  491. TEST_ESP_OK(nvs_set_u8(net80211_handle, "ap.chan", chan));
  492. authmode = 0;
  493. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "ap.authmode", &authmode), ESP_ERR_NVS_NOT_FOUND);
  494. TEST_ESP_OK(nvs_set_u8(net80211_handle, "ap.authmode", authmode));
  495. uint8_t hidden = 0;
  496. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "ap.hidden", &hidden), ESP_ERR_NVS_NOT_FOUND);
  497. TEST_ESP_OK(nvs_set_u8(net80211_handle, "ap.hidden", hidden));
  498. uint8_t max_conn = 4;
  499. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "ap.max.conn", &max_conn), ESP_ERR_NVS_NOT_FOUND);
  500. TEST_ESP_OK(nvs_set_u8(net80211_handle, "ap.max.conn", max_conn));
  501. uint8_t bcn_interval = 2;
  502. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "bcn_interval", &bcn_interval), ESP_ERR_NVS_NOT_FOUND);
  503. TEST_ESP_OK(nvs_set_u8(net80211_handle, "bcn_interval", bcn_interval));
  504. s_perf << "Time to simulate nvs init with wifi libs: " << emu.getTotalTime() << " us (" << emu.getEraseOps() << "E " << emu.getWriteOps() << "W " << emu.getReadOps() << "R " << emu.getWriteBytes() << "Wb " << emu.getReadBytes() << "Rb)" << std::endl;
  505. }
  506. TEST_CASE("can init storage from flash with random contents", "[nvs]")
  507. {
  508. SpiFlashEmulator emu(10);
  509. emu.randomize(42);
  510. nvs_handle handle;
  511. const uint32_t NVS_FLASH_SECTOR = 5;
  512. const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
  513. emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
  514. TEST_ESP_OK(nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  515. TEST_ESP_OK(nvs_open("nvs.net80211", NVS_READWRITE, &handle));
  516. uint8_t opmode = 2;
  517. if (nvs_get_u8(handle, "wifi.opmode", &opmode) != ESP_OK) {
  518. TEST_ESP_OK(nvs_set_u8(handle, "wifi.opmode", opmode));
  519. }
  520. }
  521. TEST_CASE("nvs api tests, starting with random data in flash", "[nvs][.][long]")
  522. {
  523. for (size_t count = 0; count < 10000; ++count) {
  524. SpiFlashEmulator emu(10);
  525. emu.randomize(static_cast<uint32_t>(count));
  526. const uint32_t NVS_FLASH_SECTOR = 6;
  527. const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
  528. emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
  529. TEST_ESP_OK(nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  530. nvs_handle handle_1;
  531. TEST_ESP_ERR(nvs_open("namespace1", NVS_READONLY, &handle_1), ESP_ERR_NVS_NOT_FOUND);
  532. TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle_1));
  533. TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x12345678));
  534. for (size_t i = 0; i < 500; ++i) {
  535. nvs_handle handle_2;
  536. TEST_ESP_OK(nvs_open("namespace2", NVS_READWRITE, &handle_2));
  537. TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x23456789 % (i + 1)));
  538. TEST_ESP_OK(nvs_set_i32(handle_2, "foo", static_cast<int32_t>(i)));
  539. const char* str = "value 0123456789abcdef0123456789abcdef %09d";
  540. char str_buf[128];
  541. snprintf(str_buf, sizeof(str_buf), str, i + count * 1024);
  542. TEST_ESP_OK(nvs_set_str(handle_2, "key", str_buf));
  543. int32_t v1;
  544. TEST_ESP_OK(nvs_get_i32(handle_1, "foo", &v1));
  545. CHECK(0x23456789 % (i + 1) == v1);
  546. int32_t v2;
  547. TEST_ESP_OK(nvs_get_i32(handle_2, "foo", &v2));
  548. CHECK(static_cast<int32_t>(i) == v2);
  549. char buf[128];
  550. size_t buf_len = sizeof(buf);
  551. TEST_ESP_OK(nvs_get_str(handle_2, "key", buf, &buf_len));
  552. CHECK(0 == strcmp(buf, str_buf));
  553. nvs_close(handle_2);
  554. }
  555. nvs_close(handle_1);
  556. }
  557. }
  558. extern "C" void nvs_dump();
  559. class RandomTest {
  560. static const size_t nKeys = 9;
  561. int32_t v1 = 0, v2 = 0;
  562. uint64_t v3 = 0, v4 = 0;
  563. static const size_t strBufLen = 1024;
  564. char v5[strBufLen], v6[strBufLen], v7[strBufLen], v8[strBufLen], v9[strBufLen];
  565. bool written[nKeys];
  566. public:
  567. RandomTest()
  568. {
  569. std::fill_n(written, nKeys, false);
  570. }
  571. template<typename TGen>
  572. esp_err_t doRandomThings(nvs_handle handle, TGen gen, size_t& count) {
  573. const char* keys[] = {"foo", "bar", "longkey_0123456", "another key", "param1", "param2", "param3", "param4", "param5"};
  574. const ItemType types[] = {ItemType::I32, ItemType::I32, ItemType::U64, ItemType::U64, ItemType::SZ, ItemType::SZ, ItemType::SZ, ItemType::SZ, ItemType::SZ};
  575. void* values[] = {&v1, &v2, &v3, &v4, &v5, &v6, &v7, &v8, &v9};
  576. const size_t nKeys = sizeof(keys) / sizeof(keys[0]);
  577. static_assert(nKeys == sizeof(types) / sizeof(types[0]), "");
  578. static_assert(nKeys == sizeof(values) / sizeof(values[0]), "");
  579. auto randomRead = [&](size_t index) -> esp_err_t {
  580. switch (types[index]) {
  581. case ItemType::I32:
  582. {
  583. int32_t val;
  584. auto err = nvs_get_i32(handle, keys[index], &val);
  585. if (err == ESP_ERR_FLASH_OP_FAIL) {
  586. return err;
  587. }
  588. if (!written[index]) {
  589. REQUIRE(err == ESP_ERR_NVS_NOT_FOUND);
  590. }
  591. else {
  592. REQUIRE(err == ESP_OK);
  593. REQUIRE(val == *reinterpret_cast<int32_t*>(values[index]));
  594. }
  595. break;
  596. }
  597. case ItemType::U64:
  598. {
  599. uint64_t val;
  600. auto err = nvs_get_u64(handle, keys[index], &val);
  601. if (err == ESP_ERR_FLASH_OP_FAIL) {
  602. return err;
  603. }
  604. if (!written[index]) {
  605. REQUIRE(err == ESP_ERR_NVS_NOT_FOUND);
  606. }
  607. else {
  608. REQUIRE(err == ESP_OK);
  609. REQUIRE(val == *reinterpret_cast<uint64_t*>(values[index]));
  610. }
  611. break;
  612. }
  613. case ItemType::SZ:
  614. {
  615. char buf[strBufLen];
  616. size_t len = strBufLen;
  617. auto err = nvs_get_str(handle, keys[index], buf, &len);
  618. if (err == ESP_ERR_FLASH_OP_FAIL) {
  619. return err;
  620. }
  621. if (!written[index]) {
  622. REQUIRE(err == ESP_ERR_NVS_NOT_FOUND);
  623. }
  624. else {
  625. REQUIRE(err == ESP_OK);
  626. REQUIRE(strncmp(buf, reinterpret_cast<const char*>(values[index]), strBufLen) == 0);
  627. }
  628. break;
  629. }
  630. default:
  631. assert(0);
  632. }
  633. return ESP_OK;
  634. };
  635. auto randomWrite = [&](size_t index) -> esp_err_t {
  636. switch (types[index]) {
  637. case ItemType::I32:
  638. {
  639. int32_t val = static_cast<int32_t>(gen());
  640. auto err = nvs_set_i32(handle, keys[index], val);
  641. if (err == ESP_ERR_FLASH_OP_FAIL) {
  642. return err;
  643. }
  644. if (err == ESP_ERR_NVS_REMOVE_FAILED) {
  645. written[index] = true;
  646. *reinterpret_cast<int32_t*>(values[index]) = val;
  647. return ESP_ERR_FLASH_OP_FAIL;
  648. }
  649. REQUIRE(err == ESP_OK);
  650. written[index] = true;
  651. *reinterpret_cast<int32_t*>(values[index]) = val;
  652. break;
  653. }
  654. case ItemType::U64:
  655. {
  656. uint64_t val = static_cast<uint64_t>(gen());
  657. auto err = nvs_set_u64(handle, keys[index], val);
  658. if (err == ESP_ERR_FLASH_OP_FAIL) {
  659. return err;
  660. }
  661. if (err == ESP_ERR_NVS_REMOVE_FAILED) {
  662. written[index] = true;
  663. *reinterpret_cast<uint64_t*>(values[index]) = val;
  664. return ESP_ERR_FLASH_OP_FAIL;
  665. }
  666. REQUIRE(err == ESP_OK);
  667. written[index] = true;
  668. *reinterpret_cast<uint64_t*>(values[index]) = val;
  669. break;
  670. }
  671. case ItemType::SZ:
  672. {
  673. char buf[strBufLen];
  674. size_t len = strBufLen;
  675. size_t strLen = gen() % (strBufLen - 1);
  676. std::generate_n(buf, strLen, [&]() -> char {
  677. const char c = static_cast<char>(gen() % 127);
  678. return (c < 32) ? 32 : c;
  679. });
  680. buf[strLen] = 0;
  681. auto err = nvs_set_str(handle, keys[index], buf);
  682. if (err == ESP_ERR_FLASH_OP_FAIL) {
  683. return err;
  684. }
  685. if (err == ESP_ERR_NVS_REMOVE_FAILED) {
  686. written[index] = true;
  687. strncpy(reinterpret_cast<char*>(values[index]), buf, strBufLen);
  688. return ESP_ERR_FLASH_OP_FAIL;
  689. }
  690. REQUIRE(err == ESP_OK);
  691. written[index] = true;
  692. strncpy(reinterpret_cast<char*>(values[index]), buf, strBufLen);
  693. break;
  694. }
  695. default:
  696. assert(0);
  697. }
  698. return ESP_OK;
  699. };
  700. for (; count != 0; --count) {
  701. size_t index = gen() % nKeys;
  702. switch (gen() % 3) {
  703. case 0: // read, 1/3
  704. if (randomRead(index) == ESP_ERR_FLASH_OP_FAIL) {
  705. return ESP_ERR_FLASH_OP_FAIL;
  706. }
  707. break;
  708. default: // write, 2/3
  709. if (randomWrite(index) == ESP_ERR_FLASH_OP_FAIL) {
  710. return ESP_ERR_FLASH_OP_FAIL;
  711. }
  712. break;
  713. }
  714. }
  715. return ESP_OK;
  716. }
  717. };
  718. TEST_CASE("monkey test", "[nvs][monkey]")
  719. {
  720. std::random_device rd;
  721. std::mt19937 gen(rd());
  722. uint32_t seed = 3;
  723. gen.seed(seed);
  724. SpiFlashEmulator emu(10);
  725. emu.randomize(seed);
  726. emu.clearStats();
  727. const uint32_t NVS_FLASH_SECTOR = 6;
  728. const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
  729. emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
  730. TEST_ESP_OK(nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  731. nvs_handle handle;
  732. TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle));
  733. RandomTest test;
  734. size_t count = 1000;
  735. CHECK(test.doRandomThings(handle, gen, count) == ESP_OK);
  736. s_perf << "Monkey test: nErase=" << emu.getEraseOps() << " nWrite=" << emu.getWriteOps() << std::endl;
  737. }
  738. TEST_CASE("test recovery from sudden poweroff", "[.][long][nvs][recovery][monkey]")
  739. {
  740. std::random_device rd;
  741. std::mt19937 gen(rd());
  742. uint32_t seed = 3;
  743. gen.seed(seed);
  744. const size_t iter_count = 2000;
  745. SpiFlashEmulator emu(10);
  746. const uint32_t NVS_FLASH_SECTOR = 6;
  747. const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
  748. emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
  749. size_t totalOps = 0;
  750. int lastPercent = -1;
  751. for (uint32_t errDelay = 4; ; ++errDelay) {
  752. INFO(errDelay);
  753. emu.randomize(seed);
  754. emu.clearStats();
  755. emu.failAfter(errDelay);
  756. RandomTest test;
  757. if (totalOps != 0) {
  758. int percent = errDelay * 100 / totalOps;
  759. if (percent != lastPercent) {
  760. printf("%d/%d (%d%%)\r\n", errDelay, static_cast<int>(totalOps), percent);
  761. lastPercent = percent;
  762. }
  763. }
  764. TEST_ESP_OK(nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  765. nvs_handle handle;
  766. TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle));
  767. size_t count = iter_count;
  768. if(test.doRandomThings(handle, gen, count) != ESP_ERR_FLASH_OP_FAIL) {
  769. nvs_close(handle);
  770. break;
  771. }
  772. nvs_close(handle);
  773. TEST_ESP_OK(nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  774. TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle));
  775. auto res = test.doRandomThings(handle, gen, count);
  776. if (res != ESP_OK) {
  777. nvs_dump();
  778. CHECK(0);
  779. }
  780. nvs_close(handle);
  781. totalOps = emu.getEraseOps() + emu.getWriteOps();
  782. }
  783. }
  784. TEST_CASE("dump all performance data", "[nvs]")
  785. {
  786. std::cout << "====================" << std::endl << "Dumping benchmarks" << std::endl;
  787. std::cout << s_perf.str() << std::endl;
  788. std::cout << "====================" << std::endl;
  789. }