test_nvs.cpp 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117
  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("dump all performance data", "[nvs]")
  941. {
  942. std::cout << "====================" << std::endl << "Dumping benchmarks" << std::endl;
  943. std::cout << s_perf.str() << std::endl;
  944. std::cout << "====================" << std::endl;
  945. }