test_nvs.cpp 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134
  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_test_api.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("storage can find items on second page if first is not fully written and has cached search data", "[nvs]")
  267. {
  268. SpiFlashEmulator emu(3);
  269. Storage storage;
  270. CHECK(storage.init(0, 3) == ESP_OK);
  271. int bar = 0;
  272. uint8_t bigdata[100 * 32] = {0};
  273. // write one big chunk of data
  274. ESP_ERROR_CHECK(storage.writeItem(0, ItemType::BLOB, "first", bigdata, sizeof(bigdata)));
  275. // write second one; it will not fit into the first page
  276. ESP_ERROR_CHECK(storage.writeItem(0, ItemType::BLOB, "second", bigdata, sizeof(bigdata)));
  277. size_t size;
  278. ESP_ERROR_CHECK(storage.getItemDataSize(0, ItemType::BLOB, "first", size));
  279. CHECK(size == sizeof(bigdata));
  280. ESP_ERROR_CHECK(storage.getItemDataSize(0, ItemType::BLOB, "second", size));
  281. CHECK(size == sizeof(bigdata));
  282. }
  283. TEST_CASE("can write and read variable length data lots of times", "[nvs]")
  284. {
  285. SpiFlashEmulator emu(8);
  286. Storage storage;
  287. emu.setBounds(4, 8);
  288. CHECK(storage.init(4, 4) == ESP_OK);
  289. const char str[] = "foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234";
  290. char buf[sizeof(str) + 16];
  291. size_t len = strlen(str);
  292. for (size_t i = 0; i < Page::ENTRY_COUNT * 4 * 2; ++i) {
  293. CAPTURE(i);
  294. CHECK(storage.writeItem(1, ItemType::SZ, "foobaar", str, len + 1) == ESP_OK);
  295. CHECK(storage.writeItem(1, "foo", static_cast<uint32_t>(i)) == ESP_OK);
  296. uint32_t value;
  297. CHECK(storage.readItem(1, "foo", value) == ESP_OK);
  298. CHECK(value == i);
  299. fill_n(buf, sizeof(buf), 0xff);
  300. CHECK(storage.readItem(1, ItemType::SZ, "foobaar", buf, sizeof(buf)) == ESP_OK);
  301. CHECK(memcmp(buf, str, strlen(str) + 1) == 0);
  302. }
  303. 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;
  304. }
  305. TEST_CASE("can get length of variable length data", "[nvs]")
  306. {
  307. SpiFlashEmulator emu(8);
  308. emu.randomize(200);
  309. Storage storage;
  310. emu.setBounds(4, 8);
  311. CHECK(storage.init(4, 4) == ESP_OK);
  312. const char str[] = "foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234";
  313. size_t len = strlen(str);
  314. CHECK(storage.writeItem(1, ItemType::SZ, "foobaar", str, len + 1) == ESP_OK);
  315. size_t dataSize;
  316. CHECK(storage.getItemDataSize(1, ItemType::SZ, "foobaar", dataSize) == ESP_OK);
  317. CHECK(dataSize == len + 1);
  318. CHECK(storage.writeItem(2, ItemType::BLOB, "foobaar", str, len) == ESP_OK);
  319. CHECK(storage.getItemDataSize(2, ItemType::BLOB, "foobaar", dataSize) == ESP_OK);
  320. CHECK(dataSize == len);
  321. }
  322. TEST_CASE("can create namespaces", "[nvs]")
  323. {
  324. SpiFlashEmulator emu(8);
  325. Storage storage;
  326. emu.setBounds(4, 8);
  327. CHECK(storage.init(4, 4) == ESP_OK);
  328. uint8_t nsi;
  329. CHECK(storage.createOrOpenNamespace("wifi", false, nsi) == ESP_ERR_NVS_NOT_FOUND);
  330. CHECK(storage.createOrOpenNamespace("wifi", true, nsi) == ESP_OK);
  331. Page page;
  332. page.load(4);
  333. CHECK(page.findItem(Page::NS_INDEX, ItemType::U8, "wifi") == ESP_OK);
  334. }
  335. TEST_CASE("storage may become full", "[nvs]")
  336. {
  337. SpiFlashEmulator emu(8);
  338. Storage storage;
  339. emu.setBounds(4, 8);
  340. CHECK(storage.init(4, 4) == ESP_OK);
  341. for (size_t i = 0; i < Page::ENTRY_COUNT * 3; ++i) {
  342. char name[Item::MAX_KEY_LENGTH + 1];
  343. snprintf(name, sizeof(name), "key%05d", static_cast<int>(i));
  344. REQUIRE(storage.writeItem(1, name, static_cast<int>(i)) == ESP_OK);
  345. }
  346. REQUIRE(storage.writeItem(1, "foo", 10) == ESP_ERR_NVS_NOT_ENOUGH_SPACE);
  347. }
  348. TEST_CASE("can modify an item on a page which will be erased", "[nvs]")
  349. {
  350. SpiFlashEmulator emu(2);
  351. Storage storage;
  352. CHECK(storage.init(0, 2) == ESP_OK);
  353. for (size_t i = 0; i < Page::ENTRY_COUNT * 3 + 1; ++i) {
  354. REQUIRE(storage.writeItem(1, "foo", 42U) == ESP_OK);
  355. }
  356. }
  357. TEST_CASE("can erase items", "[nvs]")
  358. {
  359. SpiFlashEmulator emu(3);
  360. Storage storage;
  361. CHECK(storage.init(0, 3) == ESP_OK);
  362. for (size_t i = 0; i < Page::ENTRY_COUNT * 2 - 3; ++i) {
  363. char name[Item::MAX_KEY_LENGTH + 1];
  364. snprintf(name, sizeof(name), "key%05d", static_cast<int>(i));
  365. REQUIRE(storage.writeItem(3, name, static_cast<int>(i)) == ESP_OK);
  366. }
  367. CHECK(storage.writeItem(1, "foo", 32) == ESP_OK);
  368. CHECK(storage.writeItem(2, "foo", 64) == ESP_OK);
  369. CHECK(storage.eraseItem(2, "foo") == ESP_OK);
  370. int val;
  371. CHECK(storage.readItem(1, "foo", val) == ESP_OK);
  372. CHECK(val == 32);
  373. CHECK(storage.eraseNamespace(3) == ESP_OK);
  374. CHECK(storage.readItem(2, "foo", val) == ESP_ERR_NVS_NOT_FOUND);
  375. CHECK(storage.readItem(3, "key00222", val) == ESP_ERR_NVS_NOT_FOUND);
  376. }
  377. #define TEST_ESP_ERR(rc, res) CHECK((rc) == (res))
  378. #define TEST_ESP_OK(rc) CHECK((rc) == ESP_OK)
  379. TEST_CASE("nvs api tests", "[nvs]")
  380. {
  381. SpiFlashEmulator emu(10);
  382. emu.randomize(100);
  383. nvs_handle handle_1;
  384. const uint32_t NVS_FLASH_SECTOR = 6;
  385. const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
  386. emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
  387. TEST_ESP_ERR(nvs_open("namespace1", NVS_READWRITE, &handle_1), ESP_ERR_NVS_NOT_INITIALIZED);
  388. for (uint16_t i = NVS_FLASH_SECTOR; i <NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN; ++i) {
  389. spi_flash_erase_sector(i);
  390. }
  391. TEST_ESP_OK(nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  392. TEST_ESP_ERR(nvs_open("namespace1", NVS_READONLY, &handle_1), ESP_ERR_NVS_NOT_FOUND);
  393. // TEST_ESP_ERR(nvs_set_i32(handle_1, "foo", 0x12345678), ESP_ERR_NVS_READ_ONLY);
  394. // nvs_close(handle_1);
  395. TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle_1));
  396. TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x12345678));
  397. TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x23456789));
  398. nvs_handle handle_2;
  399. TEST_ESP_OK(nvs_open("namespace2", NVS_READWRITE, &handle_2));
  400. TEST_ESP_OK(nvs_set_i32(handle_2, "foo", 0x3456789a));
  401. const char* str = "value 0123456789abcdef0123456789abcdef";
  402. TEST_ESP_OK(nvs_set_str(handle_2, "key", str));
  403. int32_t v1;
  404. TEST_ESP_OK(nvs_get_i32(handle_1, "foo", &v1));
  405. CHECK(0x23456789 == v1);
  406. int32_t v2;
  407. TEST_ESP_OK(nvs_get_i32(handle_2, "foo", &v2));
  408. CHECK(0x3456789a == v2);
  409. char buf[strlen(str) + 1];
  410. size_t buf_len = sizeof(buf);
  411. TEST_ESP_OK(nvs_get_str(handle_2, "key", buf, &buf_len));
  412. CHECK(0 == strcmp(buf, str));
  413. }
  414. TEST_CASE("wifi test", "[nvs]")
  415. {
  416. SpiFlashEmulator emu(10);
  417. emu.randomize(10);
  418. const uint32_t NVS_FLASH_SECTOR = 5;
  419. const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
  420. emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
  421. TEST_ESP_OK(nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  422. nvs_handle misc_handle;
  423. TEST_ESP_OK(nvs_open("nvs.net80211", NVS_READWRITE, &misc_handle));
  424. char log[33];
  425. size_t log_size = sizeof(log);
  426. TEST_ESP_ERR(nvs_get_str(misc_handle, "log", log, &log_size), ESP_ERR_NVS_NOT_FOUND);
  427. strcpy(log, "foobarbazfizzz");
  428. TEST_ESP_OK(nvs_set_str(misc_handle, "log", log));
  429. nvs_handle net80211_handle;
  430. TEST_ESP_OK(nvs_open("nvs.net80211", NVS_READWRITE, &net80211_handle));
  431. uint8_t opmode = 2;
  432. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "wifi.opmode", &opmode), ESP_ERR_NVS_NOT_FOUND);
  433. TEST_ESP_OK(nvs_set_u8(net80211_handle, "wifi.opmode", opmode));
  434. uint8_t country = 0;
  435. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "wifi.country", &opmode), ESP_ERR_NVS_NOT_FOUND);
  436. TEST_ESP_OK(nvs_set_u8(net80211_handle, "wifi.country", opmode));
  437. char ssid[36];
  438. size_t size = sizeof(ssid);
  439. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.ssid", ssid, &size), ESP_ERR_NVS_NOT_FOUND);
  440. strcpy(ssid, "my android AP");
  441. TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.ssid", ssid, size));
  442. char mac[6];
  443. size = sizeof(mac);
  444. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.mac", mac, &size), ESP_ERR_NVS_NOT_FOUND);
  445. memset(mac, 0xab, 6);
  446. TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.mac", mac, size));
  447. uint8_t authmode = 1;
  448. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "sta.authmode", &authmode), ESP_ERR_NVS_NOT_FOUND);
  449. TEST_ESP_OK(nvs_set_u8(net80211_handle, "sta.authmode", authmode));
  450. char pswd[65];
  451. size = sizeof(pswd);
  452. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.pswd", pswd, &size), ESP_ERR_NVS_NOT_FOUND);
  453. strcpy(pswd, "`123456788990-=");
  454. TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.pswd", pswd, size));
  455. char pmk[32];
  456. size = sizeof(pmk);
  457. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.pmk", pmk, &size), ESP_ERR_NVS_NOT_FOUND);
  458. memset(pmk, 1, size);
  459. TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.pmk", pmk, size));
  460. uint8_t chan = 1;
  461. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "sta.chan", &chan), ESP_ERR_NVS_NOT_FOUND);
  462. TEST_ESP_OK(nvs_set_u8(net80211_handle, "sta.chan", chan));
  463. uint8_t autoconn = 1;
  464. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "auto.conn", &autoconn), ESP_ERR_NVS_NOT_FOUND);
  465. TEST_ESP_OK(nvs_set_u8(net80211_handle, "auto.conn", autoconn));
  466. uint8_t bssid_set = 1;
  467. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "bssid.set", &bssid_set), ESP_ERR_NVS_NOT_FOUND);
  468. TEST_ESP_OK(nvs_set_u8(net80211_handle, "bssid.set", bssid_set));
  469. char bssid[6];
  470. size = sizeof(bssid);
  471. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.bssid", bssid, &size), ESP_ERR_NVS_NOT_FOUND);
  472. memset(mac, 0xcd, 6);
  473. TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.bssid", bssid, size));
  474. uint8_t phym = 3;
  475. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "sta.phym", &phym), ESP_ERR_NVS_NOT_FOUND);
  476. TEST_ESP_OK(nvs_set_u8(net80211_handle, "sta.phym", phym));
  477. uint8_t phybw = 2;
  478. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "sta.phybw", &phybw), ESP_ERR_NVS_NOT_FOUND);
  479. TEST_ESP_OK(nvs_set_u8(net80211_handle, "sta.phybw", phybw));
  480. char apsw[2];
  481. size = sizeof(apsw);
  482. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.apsw", apsw, &size), ESP_ERR_NVS_NOT_FOUND);
  483. memset(apsw, 0x2, size);
  484. TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.apsw", apsw, size));
  485. char apinfo[700];
  486. size = sizeof(apinfo);
  487. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.apinfo", apinfo, &size), ESP_ERR_NVS_NOT_FOUND);
  488. memset(apinfo, 0, size);
  489. TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.apinfo", apinfo, size));
  490. size = sizeof(ssid);
  491. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "ap.ssid", ssid, &size), ESP_ERR_NVS_NOT_FOUND);
  492. strcpy(ssid, "ESP_A2F340");
  493. TEST_ESP_OK(nvs_set_blob(net80211_handle, "ap.ssid", ssid, size));
  494. size = sizeof(mac);
  495. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "ap.mac", mac, &size), ESP_ERR_NVS_NOT_FOUND);
  496. memset(mac, 0xac, 6);
  497. TEST_ESP_OK(nvs_set_blob(net80211_handle, "ap.mac", mac, size));
  498. size = sizeof(pswd);
  499. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "ap.passwd", pswd, &size), ESP_ERR_NVS_NOT_FOUND);
  500. strcpy(pswd, "");
  501. TEST_ESP_OK(nvs_set_blob(net80211_handle, "ap.passwd", pswd, size));
  502. size = sizeof(pmk);
  503. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "ap.pmk", pmk, &size), ESP_ERR_NVS_NOT_FOUND);
  504. memset(pmk, 1, size);
  505. TEST_ESP_OK(nvs_set_blob(net80211_handle, "ap.pmk", pmk, size));
  506. chan = 6;
  507. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "ap.chan", &chan), ESP_ERR_NVS_NOT_FOUND);
  508. TEST_ESP_OK(nvs_set_u8(net80211_handle, "ap.chan", chan));
  509. authmode = 0;
  510. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "ap.authmode", &authmode), ESP_ERR_NVS_NOT_FOUND);
  511. TEST_ESP_OK(nvs_set_u8(net80211_handle, "ap.authmode", authmode));
  512. uint8_t hidden = 0;
  513. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "ap.hidden", &hidden), ESP_ERR_NVS_NOT_FOUND);
  514. TEST_ESP_OK(nvs_set_u8(net80211_handle, "ap.hidden", hidden));
  515. uint8_t max_conn = 4;
  516. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "ap.max.conn", &max_conn), ESP_ERR_NVS_NOT_FOUND);
  517. TEST_ESP_OK(nvs_set_u8(net80211_handle, "ap.max.conn", max_conn));
  518. uint8_t bcn_interval = 2;
  519. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "bcn_interval", &bcn_interval), ESP_ERR_NVS_NOT_FOUND);
  520. TEST_ESP_OK(nvs_set_u8(net80211_handle, "bcn_interval", bcn_interval));
  521. 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;
  522. }
  523. TEST_CASE("can init storage from flash with random contents", "[nvs]")
  524. {
  525. SpiFlashEmulator emu(10);
  526. emu.randomize(42);
  527. nvs_handle handle;
  528. const uint32_t NVS_FLASH_SECTOR = 5;
  529. const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
  530. emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
  531. TEST_ESP_OK(nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  532. TEST_ESP_OK(nvs_open("nvs.net80211", NVS_READWRITE, &handle));
  533. uint8_t opmode = 2;
  534. if (nvs_get_u8(handle, "wifi.opmode", &opmode) != ESP_OK) {
  535. TEST_ESP_OK(nvs_set_u8(handle, "wifi.opmode", opmode));
  536. }
  537. }
  538. TEST_CASE("nvs api tests, starting with random data in flash", "[nvs][.][long]")
  539. {
  540. for (size_t count = 0; count < 10000; ++count) {
  541. SpiFlashEmulator emu(10);
  542. emu.randomize(static_cast<uint32_t>(count));
  543. const uint32_t NVS_FLASH_SECTOR = 6;
  544. const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
  545. emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
  546. TEST_ESP_OK(nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  547. nvs_handle handle_1;
  548. TEST_ESP_ERR(nvs_open("namespace1", NVS_READONLY, &handle_1), ESP_ERR_NVS_NOT_FOUND);
  549. TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle_1));
  550. TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x12345678));
  551. for (size_t i = 0; i < 500; ++i) {
  552. nvs_handle handle_2;
  553. TEST_ESP_OK(nvs_open("namespace2", NVS_READWRITE, &handle_2));
  554. TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x23456789 % (i + 1)));
  555. TEST_ESP_OK(nvs_set_i32(handle_2, "foo", static_cast<int32_t>(i)));
  556. const char* str = "value 0123456789abcdef0123456789abcdef %09d";
  557. char str_buf[128];
  558. snprintf(str_buf, sizeof(str_buf), str, i + count * 1024);
  559. TEST_ESP_OK(nvs_set_str(handle_2, "key", str_buf));
  560. int32_t v1;
  561. TEST_ESP_OK(nvs_get_i32(handle_1, "foo", &v1));
  562. CHECK(0x23456789 % (i + 1) == v1);
  563. int32_t v2;
  564. TEST_ESP_OK(nvs_get_i32(handle_2, "foo", &v2));
  565. CHECK(static_cast<int32_t>(i) == v2);
  566. char buf[128];
  567. size_t buf_len = sizeof(buf);
  568. TEST_ESP_OK(nvs_get_str(handle_2, "key", buf, &buf_len));
  569. CHECK(0 == strcmp(buf, str_buf));
  570. nvs_close(handle_2);
  571. }
  572. nvs_close(handle_1);
  573. }
  574. }
  575. extern "C" void nvs_dump();
  576. class RandomTest {
  577. static const size_t nKeys = 9;
  578. int32_t v1 = 0, v2 = 0;
  579. uint64_t v3 = 0, v4 = 0;
  580. static const size_t strBufLen = 1024;
  581. char v5[strBufLen], v6[strBufLen], v7[strBufLen], v8[strBufLen], v9[strBufLen];
  582. bool written[nKeys];
  583. public:
  584. RandomTest()
  585. {
  586. std::fill_n(written, nKeys, false);
  587. }
  588. template<typename TGen>
  589. esp_err_t doRandomThings(nvs_handle handle, TGen gen, size_t& count) {
  590. const char* keys[] = {"foo", "bar", "longkey_0123456", "another key", "param1", "param2", "param3", "param4", "param5"};
  591. const ItemType types[] = {ItemType::I32, ItemType::I32, ItemType::U64, ItemType::U64, ItemType::SZ, ItemType::SZ, ItemType::SZ, ItemType::SZ, ItemType::SZ};
  592. void* values[] = {&v1, &v2, &v3, &v4, &v5, &v6, &v7, &v8, &v9};
  593. const size_t nKeys = sizeof(keys) / sizeof(keys[0]);
  594. static_assert(nKeys == sizeof(types) / sizeof(types[0]), "");
  595. static_assert(nKeys == sizeof(values) / sizeof(values[0]), "");
  596. auto randomRead = [&](size_t index) -> esp_err_t {
  597. switch (types[index]) {
  598. case ItemType::I32:
  599. {
  600. int32_t val;
  601. auto err = nvs_get_i32(handle, keys[index], &val);
  602. if (err == ESP_ERR_FLASH_OP_FAIL) {
  603. return err;
  604. }
  605. if (!written[index]) {
  606. REQUIRE(err == ESP_ERR_NVS_NOT_FOUND);
  607. }
  608. else {
  609. REQUIRE(err == ESP_OK);
  610. REQUIRE(val == *reinterpret_cast<int32_t*>(values[index]));
  611. }
  612. break;
  613. }
  614. case ItemType::U64:
  615. {
  616. uint64_t val;
  617. auto err = nvs_get_u64(handle, keys[index], &val);
  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(val == *reinterpret_cast<uint64_t*>(values[index]));
  627. }
  628. break;
  629. }
  630. case ItemType::SZ:
  631. {
  632. char buf[strBufLen];
  633. size_t len = strBufLen;
  634. auto err = nvs_get_str(handle, keys[index], buf, &len);
  635. if (err == ESP_ERR_FLASH_OP_FAIL) {
  636. return err;
  637. }
  638. if (!written[index]) {
  639. REQUIRE(err == ESP_ERR_NVS_NOT_FOUND);
  640. }
  641. else {
  642. REQUIRE(err == ESP_OK);
  643. REQUIRE(strncmp(buf, reinterpret_cast<const char*>(values[index]), strBufLen) == 0);
  644. }
  645. break;
  646. }
  647. default:
  648. assert(0);
  649. }
  650. return ESP_OK;
  651. };
  652. auto randomWrite = [&](size_t index) -> esp_err_t {
  653. switch (types[index]) {
  654. case ItemType::I32:
  655. {
  656. int32_t val = static_cast<int32_t>(gen());
  657. auto err = nvs_set_i32(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<int32_t*>(values[index]) = val;
  664. return ESP_ERR_FLASH_OP_FAIL;
  665. }
  666. REQUIRE(err == ESP_OK);
  667. written[index] = true;
  668. *reinterpret_cast<int32_t*>(values[index]) = val;
  669. break;
  670. }
  671. case ItemType::U64:
  672. {
  673. uint64_t val = static_cast<uint64_t>(gen());
  674. auto err = nvs_set_u64(handle, keys[index], val);
  675. if (err == ESP_ERR_FLASH_OP_FAIL) {
  676. return err;
  677. }
  678. if (err == ESP_ERR_NVS_REMOVE_FAILED) {
  679. written[index] = true;
  680. *reinterpret_cast<uint64_t*>(values[index]) = val;
  681. return ESP_ERR_FLASH_OP_FAIL;
  682. }
  683. REQUIRE(err == ESP_OK);
  684. written[index] = true;
  685. *reinterpret_cast<uint64_t*>(values[index]) = val;
  686. break;
  687. }
  688. case ItemType::SZ:
  689. {
  690. char buf[strBufLen];
  691. size_t len = strBufLen;
  692. size_t strLen = gen() % (strBufLen - 1);
  693. std::generate_n(buf, strLen, [&]() -> char {
  694. const char c = static_cast<char>(gen() % 127);
  695. return (c < 32) ? 32 : c;
  696. });
  697. buf[strLen] = 0;
  698. auto err = nvs_set_str(handle, keys[index], buf);
  699. if (err == ESP_ERR_FLASH_OP_FAIL) {
  700. return err;
  701. }
  702. if (err == ESP_ERR_NVS_REMOVE_FAILED) {
  703. written[index] = true;
  704. strncpy(reinterpret_cast<char*>(values[index]), buf, strBufLen);
  705. return ESP_ERR_FLASH_OP_FAIL;
  706. }
  707. REQUIRE(err == ESP_OK);
  708. written[index] = true;
  709. strncpy(reinterpret_cast<char*>(values[index]), buf, strBufLen);
  710. break;
  711. }
  712. default:
  713. assert(0);
  714. }
  715. return ESP_OK;
  716. };
  717. for (; count != 0; --count) {
  718. size_t index = gen() % nKeys;
  719. switch (gen() % 3) {
  720. case 0: // read, 1/3
  721. if (randomRead(index) == ESP_ERR_FLASH_OP_FAIL) {
  722. return ESP_ERR_FLASH_OP_FAIL;
  723. }
  724. break;
  725. default: // write, 2/3
  726. if (randomWrite(index) == ESP_ERR_FLASH_OP_FAIL) {
  727. return ESP_ERR_FLASH_OP_FAIL;
  728. }
  729. break;
  730. }
  731. }
  732. return ESP_OK;
  733. }
  734. };
  735. TEST_CASE("monkey test", "[nvs][monkey]")
  736. {
  737. std::random_device rd;
  738. std::mt19937 gen(rd());
  739. uint32_t seed = 3;
  740. gen.seed(seed);
  741. SpiFlashEmulator emu(10);
  742. emu.randomize(seed);
  743. emu.clearStats();
  744. const uint32_t NVS_FLASH_SECTOR = 6;
  745. const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
  746. emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
  747. TEST_ESP_OK(nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  748. nvs_handle handle;
  749. TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle));
  750. RandomTest test;
  751. size_t count = 1000;
  752. CHECK(test.doRandomThings(handle, gen, count) == ESP_OK);
  753. s_perf << "Monkey test: nErase=" << emu.getEraseOps() << " nWrite=" << emu.getWriteOps() << std::endl;
  754. }
  755. TEST_CASE("test recovery from sudden poweroff", "[.][long][nvs][recovery][monkey]")
  756. {
  757. std::random_device rd;
  758. std::mt19937 gen(rd());
  759. uint32_t seed = 3;
  760. gen.seed(seed);
  761. const size_t iter_count = 2000;
  762. SpiFlashEmulator emu(10);
  763. const uint32_t NVS_FLASH_SECTOR = 6;
  764. const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
  765. emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
  766. size_t totalOps = 0;
  767. int lastPercent = -1;
  768. for (uint32_t errDelay = 0; ; ++errDelay) {
  769. INFO(errDelay);
  770. emu.randomize(seed);
  771. emu.clearStats();
  772. emu.failAfter(errDelay);
  773. RandomTest test;
  774. if (totalOps != 0) {
  775. int percent = errDelay * 100 / totalOps;
  776. if (percent > lastPercent) {
  777. printf("%d/%d (%d%%)\r\n", errDelay, static_cast<int>(totalOps), percent);
  778. lastPercent = percent;
  779. }
  780. }
  781. nvs_handle handle;
  782. size_t count = iter_count;
  783. if (nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK) {
  784. if (nvs_open("namespace1", NVS_READWRITE, &handle) == ESP_OK) {
  785. if(test.doRandomThings(handle, gen, count) != ESP_ERR_FLASH_OP_FAIL) {
  786. nvs_close(handle);
  787. break;
  788. }
  789. nvs_close(handle);
  790. }
  791. }
  792. TEST_ESP_OK(nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  793. TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle));
  794. auto res = test.doRandomThings(handle, gen, count);
  795. if (res != ESP_OK) {
  796. nvs_dump();
  797. CHECK(0);
  798. }
  799. nvs_close(handle);
  800. totalOps = emu.getEraseOps() + emu.getWriteBytes() / 4;
  801. }
  802. }
  803. TEST_CASE("test for memory leaks in open/set", "[leaks]")
  804. {
  805. SpiFlashEmulator emu(10);
  806. const uint32_t NVS_FLASH_SECTOR = 6;
  807. const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
  808. emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
  809. TEST_ESP_OK(nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  810. for (int i = 0; i < 100000; ++i) {
  811. nvs_handle light_handle = 0;
  812. char lightbulb[1024] = {12, 13, 14, 15, 16};
  813. TEST_ESP_OK(nvs_open("light", NVS_READWRITE, &light_handle));
  814. TEST_ESP_OK(nvs_set_blob(light_handle, "key", lightbulb, sizeof(lightbulb)));
  815. TEST_ESP_OK(nvs_commit(light_handle));
  816. nvs_close(light_handle);
  817. }
  818. }
  819. TEST_CASE("duplicate items are removed", "[nvs][dupes]")
  820. {
  821. SpiFlashEmulator emu(3);
  822. {
  823. // create one item
  824. nvs::Page p;
  825. p.load(0);
  826. p.writeItem<uint8_t>(1, "opmode", 3);
  827. }
  828. {
  829. // add another two without deleting the first one
  830. nvs::Item item(1, ItemType::U8, 1, "opmode");
  831. item.data[0] = 2;
  832. item.crc32 = item.calculateCrc32();
  833. emu.write(3 * 32, reinterpret_cast<const uint32_t*>(&item), sizeof(item));
  834. emu.write(4 * 32, reinterpret_cast<const uint32_t*>(&item), sizeof(item));
  835. uint32_t mask = 0xFFFFFFEA;
  836. emu.write(32, &mask, 4);
  837. }
  838. {
  839. // load page and check that second item persists
  840. nvs::Storage s;
  841. s.init(0, 3);
  842. uint8_t val;
  843. ESP_ERROR_CHECK(s.readItem(1, "opmode", val));
  844. CHECK(val == 2);
  845. }
  846. {
  847. Page p;
  848. p.load(0);
  849. CHECK(p.getErasedEntryCount() == 2);
  850. CHECK(p.getUsedEntryCount() == 1);
  851. }
  852. }
  853. TEST_CASE("recovery after failure to write data", "[nvs]")
  854. {
  855. SpiFlashEmulator emu(3);
  856. const char str[] = "value 0123456789abcdef012345678value 0123456789abcdef012345678";
  857. // make flash write fail exactly in Page::writeEntryData
  858. emu.failAfter(17);
  859. {
  860. Storage storage;
  861. TEST_ESP_OK(storage.init(0, 3));
  862. TEST_ESP_ERR(storage.writeItem(1, ItemType::SZ, "key", str, strlen(str)), ESP_ERR_FLASH_OP_FAIL);
  863. // check that repeated operations cause an error
  864. TEST_ESP_ERR(storage.writeItem(1, ItemType::SZ, "key", str, strlen(str)), ESP_ERR_NVS_INVALID_STATE);
  865. uint8_t val;
  866. TEST_ESP_ERR(storage.readItem(1, ItemType::U8, "key", &val, sizeof(val)), ESP_ERR_NVS_NOT_FOUND);
  867. }
  868. {
  869. // load page and check that data was erased
  870. Page p;
  871. p.load(0);
  872. CHECK(p.getErasedEntryCount() == 3);
  873. CHECK(p.getUsedEntryCount() == 0);
  874. // try to write again
  875. TEST_ESP_OK(p.writeItem(1, ItemType::SZ, "key", str, strlen(str)));
  876. }
  877. }
  878. TEST_CASE("crc error in variable length item is handled", "[nvs]")
  879. {
  880. SpiFlashEmulator emu(3);
  881. const uint64_t before_val = 0xbef04e;
  882. const uint64_t after_val = 0xaf7e4;
  883. // write some data
  884. {
  885. Page p;
  886. p.load(0);
  887. TEST_ESP_OK(p.writeItem<uint64_t>(0, "before", before_val));
  888. const char* str = "foobar";
  889. TEST_ESP_OK(p.writeItem(0, ItemType::SZ, "key", str, strlen(str)));
  890. TEST_ESP_OK(p.writeItem<uint64_t>(0, "after", after_val));
  891. }
  892. // corrupt some data
  893. uint32_t w;
  894. CHECK(emu.read(&w, 32 * 3 + 8, sizeof(w)));
  895. w &= 0xf000000f;
  896. CHECK(emu.write(32 * 3 + 8, &w, sizeof(w)));
  897. // load and check
  898. {
  899. Page p;
  900. p.load(0);
  901. CHECK(p.getUsedEntryCount() == 2);
  902. CHECK(p.getErasedEntryCount() == 2);
  903. uint64_t val;
  904. TEST_ESP_OK(p.readItem<uint64_t>(0, "before", val));
  905. CHECK(val == before_val);
  906. TEST_ESP_ERR(p.findItem(0, ItemType::SZ, "key"), ESP_ERR_NVS_NOT_FOUND);
  907. TEST_ESP_OK(p.readItem<uint64_t>(0, "after", val));
  908. CHECK(val == after_val);
  909. }
  910. }
  911. TEST_CASE("read/write failure (TW8406)", "[nvs]")
  912. {
  913. SpiFlashEmulator emu(3);
  914. nvs_flash_init_custom(0, 3);
  915. for (int attempts = 0; attempts < 3; ++attempts) {
  916. int i = 0;
  917. nvs_handle light_handle = 0;
  918. char key[15] = {0};
  919. char data[76] = {12, 13, 14, 15, 16};
  920. uint8_t number = 20;
  921. size_t data_len = sizeof(data);
  922. ESP_ERROR_CHECK(nvs_open("LIGHT", NVS_READWRITE, &light_handle));
  923. ESP_ERROR_CHECK(nvs_set_u8(light_handle, "RecordNum", number));
  924. for (i = 0; i < number; ++i) {
  925. sprintf(key, "light%d", i);
  926. ESP_ERROR_CHECK(nvs_set_blob(light_handle, key, data, sizeof(data)));
  927. }
  928. nvs_commit(light_handle);
  929. uint8_t get_number = 0;
  930. ESP_ERROR_CHECK(nvs_get_u8(light_handle, "RecordNum", &get_number));
  931. REQUIRE(number == get_number);
  932. for (i = 0; i < number; ++i) {
  933. char data[76] = {0};
  934. sprintf(key, "light%d", i);
  935. ESP_ERROR_CHECK(nvs_get_blob(light_handle, key, data, &data_len));
  936. }
  937. nvs_close(light_handle);
  938. }
  939. }
  940. TEST_CASE("nvs_flash_init checks for an empty page", "[nvs]")
  941. {
  942. const size_t blob_size = 2048; // big enough so that only one can fit into a page
  943. uint8_t blob[blob_size] = {0};
  944. SpiFlashEmulator emu(5);
  945. TEST_ESP_OK( nvs_flash_init_custom(0, 5) );
  946. nvs_handle handle;
  947. TEST_ESP_OK( nvs_open("test", NVS_READWRITE, &handle) );
  948. TEST_ESP_OK( nvs_set_blob(handle, "1", blob, blob_size) );
  949. TEST_ESP_OK( nvs_set_blob(handle, "2", blob, blob_size) );
  950. TEST_ESP_OK( nvs_set_blob(handle, "3", blob, blob_size) );
  951. TEST_ESP_OK( nvs_commit(handle) );
  952. nvs_close(handle);
  953. // first two pages are now full, third one is writable, last two are empty
  954. // init should fail
  955. TEST_ESP_ERR( nvs_flash_init_custom(0, 3), ESP_ERR_NVS_NO_FREE_PAGES );
  956. }
  957. TEST_CASE("dump all performance data", "[nvs]")
  958. {
  959. std::cout << "====================" << std::endl << "Dumping benchmarks" << std::endl;
  960. std::cout << s_perf.str() << std::endl;
  961. std::cout << "====================" << std::endl;
  962. }