test_nvs.cpp 75 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076
  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. #include <fstream>
  20. #include <unistd.h>
  21. #include <sys/wait.h>
  22. #define TEST_ESP_ERR(rc, res) CHECK((rc) == (res))
  23. #define TEST_ESP_OK(rc) CHECK((rc) == ESP_OK)
  24. using namespace std;
  25. using namespace nvs;
  26. stringstream s_perf;
  27. void dumpBytes(const uint8_t* data, size_t count)
  28. {
  29. for (uint32_t i = 0; i < count; ++i) {
  30. if (i % 32 == 0) {
  31. printf("%08x ", i);
  32. }
  33. printf("%02x ", data[i]);
  34. if ((i + 1) % 32 == 0) {
  35. printf("\n");
  36. }
  37. }
  38. }
  39. TEST_CASE("crc32 behaves as expected", "[nvs]")
  40. {
  41. Item item1;
  42. item1.datatype = ItemType::I32;
  43. item1.nsIndex = 1;
  44. item1.crc32 = 0;
  45. item1.chunkIndex = 0xff;
  46. fill_n(item1.key, sizeof(item1.key), 0xbb);
  47. fill_n(item1.data, sizeof(item1.data), 0xaa);
  48. auto crc32_1 = item1.calculateCrc32();
  49. Item item2 = item1;
  50. item2.crc32 = crc32_1;
  51. CHECK(crc32_1 == item2.calculateCrc32());
  52. item2 = item1;
  53. item2.nsIndex = 2;
  54. CHECK(crc32_1 != item2.calculateCrc32());
  55. item2 = item1;
  56. item2.datatype = ItemType::U32;
  57. CHECK(crc32_1 != item2.calculateCrc32());
  58. item2 = item1;
  59. strncpy(item2.key, "foo", Item::MAX_KEY_LENGTH);
  60. CHECK(crc32_1 != item2.calculateCrc32());
  61. }
  62. TEST_CASE("starting with empty flash, page is in uninitialized state", "[nvs]")
  63. {
  64. SpiFlashEmulator emu(1);
  65. Page page;
  66. CHECK(page.state() == Page::PageState::INVALID);
  67. CHECK(page.load(0) == ESP_OK);
  68. CHECK(page.state() == Page::PageState::UNINITIALIZED);
  69. }
  70. TEST_CASE("can distinguish namespaces", "[nvs]")
  71. {
  72. SpiFlashEmulator emu(1);
  73. Page page;
  74. CHECK(page.load(0) == ESP_OK);
  75. int32_t val1 = 0x12345678;
  76. CHECK(page.writeItem(1, ItemType::I32, "intval1", &val1, sizeof(val1)) == ESP_OK);
  77. int32_t val2 = 0x23456789;
  78. CHECK(page.writeItem(2, ItemType::I32, "intval1", &val2, sizeof(val2)) == ESP_OK);
  79. int32_t readVal;
  80. CHECK(page.readItem(2, ItemType::I32, "intval1", &readVal, sizeof(readVal)) == ESP_OK);
  81. CHECK(readVal == val2);
  82. }
  83. TEST_CASE("reading with different type causes type mismatch error", "[nvs]")
  84. {
  85. SpiFlashEmulator emu(1);
  86. Page page;
  87. CHECK(page.load(0) == ESP_OK);
  88. int32_t val = 0x12345678;
  89. CHECK(page.writeItem(1, ItemType::I32, "intval1", &val, sizeof(val)) == ESP_OK);
  90. CHECK(page.readItem(1, ItemType::U32, "intval1", &val, sizeof(val)) == ESP_ERR_NVS_TYPE_MISMATCH);
  91. }
  92. TEST_CASE("when page is erased, it's state becomes UNITIALIZED", "[nvs]")
  93. {
  94. SpiFlashEmulator emu(1);
  95. Page page;
  96. CHECK(page.load(0) == ESP_OK);
  97. int32_t val = 0x12345678;
  98. CHECK(page.writeItem(1, ItemType::I32, "intval1", &val, sizeof(val)) == ESP_OK);
  99. CHECK(page.erase() == ESP_OK);
  100. CHECK(page.state() == Page::PageState::UNINITIALIZED);
  101. }
  102. TEST_CASE("when writing and erasing, used/erased counts are updated correctly", "[nvs]")
  103. {
  104. SpiFlashEmulator emu(1);
  105. Page page;
  106. CHECK(page.load(0) == ESP_OK);
  107. CHECK(page.getUsedEntryCount() == 0);
  108. CHECK(page.getErasedEntryCount() == 0);
  109. uint32_t foo1 = 0;
  110. CHECK(page.writeItem(1, "foo1", foo1) == ESP_OK);
  111. CHECK(page.getUsedEntryCount() == 1);
  112. CHECK(page.writeItem(2, "foo1", foo1) == ESP_OK);
  113. CHECK(page.getUsedEntryCount() == 2);
  114. CHECK(page.eraseItem<uint32_t>(2, "foo1") == ESP_OK);
  115. CHECK(page.getUsedEntryCount() == 1);
  116. CHECK(page.getErasedEntryCount() == 1);
  117. for (size_t i = 0; i < Page::ENTRY_COUNT - 2; ++i) {
  118. char name[16];
  119. snprintf(name, sizeof(name), "i%ld", (long int)i);
  120. CHECK(page.writeItem(1, name, i) == ESP_OK);
  121. }
  122. CHECK(page.getUsedEntryCount() == Page::ENTRY_COUNT - 1);
  123. CHECK(page.getErasedEntryCount() == 1);
  124. for (size_t i = 0; i < Page::ENTRY_COUNT - 2; ++i) {
  125. char name[16];
  126. snprintf(name, sizeof(name), "i%ld", (long int)i);
  127. CHECK(page.eraseItem(1, itemTypeOf<size_t>(), name) == ESP_OK);
  128. }
  129. CHECK(page.getUsedEntryCount() == 1);
  130. CHECK(page.getErasedEntryCount() == Page::ENTRY_COUNT - 1);
  131. }
  132. TEST_CASE("when page is full, adding an element fails", "[nvs]")
  133. {
  134. SpiFlashEmulator emu(1);
  135. Page page;
  136. CHECK(page.load(0) == ESP_OK);
  137. for (size_t i = 0; i < Page::ENTRY_COUNT; ++i) {
  138. char name[16];
  139. snprintf(name, sizeof(name), "i%ld", (long int)i);
  140. CHECK(page.writeItem(1, name, i) == ESP_OK);
  141. }
  142. CHECK(page.writeItem(1, "foo", 64UL) == ESP_ERR_NVS_PAGE_FULL);
  143. }
  144. TEST_CASE("page maintains its seq number")
  145. {
  146. SpiFlashEmulator emu(1);
  147. {
  148. Page page;
  149. CHECK(page.load(0) == ESP_OK);
  150. CHECK(page.setSeqNumber(123) == ESP_OK);
  151. int32_t val = 42;
  152. CHECK(page.writeItem(1, ItemType::I32, "dummy", &val, sizeof(val)) == ESP_OK);
  153. }
  154. {
  155. Page page;
  156. CHECK(page.load(0) == ESP_OK);
  157. uint32_t seqno;
  158. CHECK(page.getSeqNumber(seqno) == ESP_OK);
  159. CHECK(seqno == 123);
  160. }
  161. }
  162. TEST_CASE("can write and read variable length data", "[nvs]")
  163. {
  164. SpiFlashEmulator emu(1);
  165. Page page;
  166. CHECK(page.load(0) == ESP_OK);
  167. const char str[] = "foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234";
  168. size_t len = strlen(str);
  169. CHECK(page.writeItem(1, "stuff1", 42) == ESP_OK);
  170. CHECK(page.writeItem(1, "stuff2", 1) == ESP_OK);
  171. CHECK(page.writeItem(1, ItemType::SZ, "foobaar", str, len + 1) == ESP_OK);
  172. CHECK(page.writeItem(1, "stuff3", 2) == ESP_OK);
  173. CHECK(page.writeItem(1, ItemType::BLOB, "baz", str, len) == ESP_OK);
  174. CHECK(page.writeItem(1, "stuff4", 0x7abbccdd) == ESP_OK);
  175. char buf[sizeof(str) + 16];
  176. int32_t value;
  177. CHECK(page.readItem(1, "stuff1", value) == ESP_OK);
  178. CHECK(value == 42);
  179. CHECK(page.readItem(1, "stuff2", value) == ESP_OK);
  180. CHECK(value == 1);
  181. CHECK(page.readItem(1, "stuff3", value) == ESP_OK);
  182. CHECK(value == 2);
  183. CHECK(page.readItem(1, "stuff4", value) == ESP_OK);
  184. CHECK(value == 0x7abbccdd);
  185. fill_n(buf, sizeof(buf), 0xff);
  186. CHECK(page.readItem(1, ItemType::SZ, "foobaar", buf, sizeof(buf)) == ESP_OK);
  187. CHECK(memcmp(buf, str, strlen(str) + 1) == 0);
  188. fill_n(buf, sizeof(buf), 0xff);
  189. CHECK(page.readItem(1, ItemType::BLOB, "baz", buf, sizeof(buf)) == ESP_OK);
  190. CHECK(memcmp(buf, str, strlen(str)) == 0);
  191. }
  192. TEST_CASE("different key names are distinguished even if the pointer is the same", "[nvs]")
  193. {
  194. SpiFlashEmulator emu(1);
  195. Page page;
  196. TEST_ESP_OK(page.load(0));
  197. TEST_ESP_OK(page.writeItem(1, "i1", 1));
  198. TEST_ESP_OK(page.writeItem(1, "i2", 2));
  199. int32_t value;
  200. char keyname[10] = {0};
  201. for (int i = 0; i < 2; ++i) {
  202. strncpy(keyname, "i1", sizeof(keyname) - 1);
  203. TEST_ESP_OK(page.readItem(1, keyname, value));
  204. CHECK(value == 1);
  205. strncpy(keyname, "i2", sizeof(keyname) - 1);
  206. TEST_ESP_OK(page.readItem(1, keyname, value));
  207. CHECK(value == 2);
  208. }
  209. }
  210. TEST_CASE("Page validates key size", "[nvs]")
  211. {
  212. SpiFlashEmulator emu(4);
  213. Page page;
  214. TEST_ESP_OK(page.load(0));
  215. // 16-character key fails
  216. TEST_ESP_ERR(page.writeItem(1, "0123456789123456", 1), ESP_ERR_NVS_KEY_TOO_LONG);
  217. // 15-character key is okay
  218. TEST_ESP_OK(page.writeItem(1, "012345678912345", 1));
  219. }
  220. TEST_CASE("Page validates blob size", "[nvs]")
  221. {
  222. SpiFlashEmulator emu(4);
  223. Page page;
  224. TEST_ESP_OK(page.load(0));
  225. char buf[2048] = { 0 };
  226. // There are two potential errors here:
  227. // - not enough space in the page (because one value has been written already)
  228. // - value is too long
  229. // Check that the second one is actually returned.
  230. TEST_ESP_ERR(page.writeItem(1, ItemType::BLOB, "2", buf, Page::ENTRY_COUNT * Page::ENTRY_SIZE), ESP_ERR_NVS_VALUE_TOO_LONG);
  231. // Should fail as well
  232. TEST_ESP_ERR(page.writeItem(1, ItemType::BLOB, "2", buf, Page::CHUNK_MAX_SIZE + 1), ESP_ERR_NVS_VALUE_TOO_LONG);
  233. TEST_ESP_OK(page.writeItem(1, ItemType::BLOB, "2", buf, Page::CHUNK_MAX_SIZE));
  234. }
  235. TEST_CASE("Page handles invalid CRC of variable length items", "[nvs][cur]")
  236. {
  237. SpiFlashEmulator emu(4);
  238. {
  239. Page page;
  240. TEST_ESP_OK(page.load(0));
  241. char buf[128] = {0};
  242. TEST_ESP_OK(page.writeItem(1, ItemType::BLOB, "1", buf, sizeof(buf)));
  243. }
  244. // corrupt header of the item (64 is the offset of the first item in page)
  245. uint32_t overwrite_buf = 0;
  246. emu.write(64, &overwrite_buf, 4);
  247. // load page again
  248. {
  249. Page page;
  250. TEST_ESP_OK(page.load(0));
  251. }
  252. }
  253. TEST_CASE("can init PageManager in empty flash", "[nvs]")
  254. {
  255. SpiFlashEmulator emu(4);
  256. PageManager pm;
  257. CHECK(pm.load(0, 4) == ESP_OK);
  258. }
  259. TEST_CASE("PageManager adds page in the correct order", "[nvs]")
  260. {
  261. const size_t pageCount = 8;
  262. SpiFlashEmulator emu(pageCount);
  263. uint32_t pageNo[pageCount] = { -1U, 50, 11, -1U, 23, 22, 24, 49};
  264. for (uint32_t i = 0; i < pageCount; ++i) {
  265. Page p;
  266. p.load(i);
  267. if (pageNo[i] != -1U) {
  268. p.setSeqNumber(pageNo[i]);
  269. p.writeItem(1, "foo", 10U);
  270. }
  271. }
  272. PageManager pageManager;
  273. CHECK(pageManager.load(0, pageCount) == ESP_OK);
  274. uint32_t lastSeqNo = 0;
  275. for (auto it = std::begin(pageManager); it != std::end(pageManager); ++it) {
  276. uint32_t seqNo;
  277. CHECK(it->getSeqNumber(seqNo) == ESP_OK);
  278. CHECK(seqNo > lastSeqNo);
  279. }
  280. }
  281. TEST_CASE("can init storage in empty flash", "[nvs]")
  282. {
  283. SpiFlashEmulator emu(8);
  284. Storage storage;
  285. emu.setBounds(4, 8);
  286. CHECK(storage.init(4, 4) == ESP_OK);
  287. s_perf << "Time to init empty storage (4 sectors): " << emu.getTotalTime() << " us" << std::endl;
  288. }
  289. TEST_CASE("storage doesn't add duplicates within one page", "[nvs]")
  290. {
  291. SpiFlashEmulator emu(8);
  292. Storage storage;
  293. emu.setBounds(4, 8);
  294. CHECK(storage.init(4, 4) == ESP_OK);
  295. int bar = 0;
  296. CHECK(storage.writeItem(1, "bar", bar) == ESP_OK);
  297. CHECK(storage.writeItem(1, "bar", bar) == ESP_OK);
  298. Page page;
  299. page.load(4);
  300. CHECK(page.getUsedEntryCount() == 1);
  301. CHECK(page.getErasedEntryCount() == 1);
  302. }
  303. TEST_CASE("can write one item a thousand times", "[nvs]")
  304. {
  305. SpiFlashEmulator emu(8);
  306. Storage storage;
  307. emu.setBounds(4, 8);
  308. CHECK(storage.init(4, 4) == ESP_OK);
  309. for (size_t i = 0; i < Page::ENTRY_COUNT * 4 * 2; ++i) {
  310. REQUIRE(storage.writeItem(1, "i", static_cast<int>(i)) == ESP_OK);
  311. }
  312. 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;
  313. }
  314. TEST_CASE("storage doesn't add duplicates within multiple pages", "[nvs]")
  315. {
  316. SpiFlashEmulator emu(8);
  317. Storage storage;
  318. emu.setBounds(4, 8);
  319. CHECK(storage.init(4, 4) == ESP_OK);
  320. int bar = 0;
  321. CHECK(storage.writeItem(1, "bar", bar) == ESP_OK);
  322. for (size_t i = 0; i < Page::ENTRY_COUNT; ++i) {
  323. CHECK(storage.writeItem(1, "foo", static_cast<int>(bar)) == ESP_OK);
  324. }
  325. CHECK(storage.writeItem(1, "bar", bar) == ESP_OK);
  326. Page page;
  327. page.load(4);
  328. CHECK(page.findItem(1, itemTypeOf<int>(), "bar") == ESP_ERR_NVS_NOT_FOUND);
  329. page.load(5);
  330. CHECK(page.findItem(1, itemTypeOf<int>(), "bar") == ESP_OK);
  331. }
  332. TEST_CASE("storage can find items on second page if first is not fully written and has cached search data", "[nvs]")
  333. {
  334. SpiFlashEmulator emu(3);
  335. Storage storage;
  336. CHECK(storage.init(0, 3) == ESP_OK);
  337. int bar = 0;
  338. uint8_t bigdata[(Page::CHUNK_MAX_SIZE - Page::ENTRY_SIZE)/2] = {0};
  339. // write one big chunk of data
  340. ESP_ERROR_CHECK(storage.writeItem(0, ItemType::BLOB, "1", bigdata, sizeof(bigdata)));
  341. // write another big chunk of data
  342. ESP_ERROR_CHECK(storage.writeItem(0, ItemType::BLOB, "2", bigdata, sizeof(bigdata)));
  343. // write third one; it will not fit into the first page
  344. ESP_ERROR_CHECK(storage.writeItem(0, ItemType::BLOB, "3", bigdata, sizeof(bigdata)));
  345. size_t size;
  346. ESP_ERROR_CHECK(storage.getItemDataSize(0, ItemType::BLOB, "1", size));
  347. CHECK(size == sizeof(bigdata));
  348. ESP_ERROR_CHECK(storage.getItemDataSize(0, ItemType::BLOB, "3", size));
  349. CHECK(size == sizeof(bigdata));
  350. }
  351. TEST_CASE("can write and read variable length data lots of times", "[nvs]")
  352. {
  353. SpiFlashEmulator emu(8);
  354. Storage storage;
  355. emu.setBounds(4, 8);
  356. CHECK(storage.init(4, 4) == ESP_OK);
  357. const char str[] = "foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234";
  358. char buf[sizeof(str) + 16];
  359. size_t len = strlen(str);
  360. for (size_t i = 0; i < Page::ENTRY_COUNT * 4 * 2; ++i) {
  361. CAPTURE(i);
  362. CHECK(storage.writeItem(1, ItemType::SZ, "foobaar", str, len + 1) == ESP_OK);
  363. CHECK(storage.writeItem(1, "foo", static_cast<uint32_t>(i)) == ESP_OK);
  364. uint32_t value;
  365. CHECK(storage.readItem(1, "foo", value) == ESP_OK);
  366. CHECK(value == i);
  367. fill_n(buf, sizeof(buf), 0xff);
  368. CHECK(storage.readItem(1, ItemType::SZ, "foobaar", buf, sizeof(buf)) == ESP_OK);
  369. CHECK(memcmp(buf, str, strlen(str) + 1) == 0);
  370. }
  371. 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;
  372. }
  373. TEST_CASE("can get length of variable length data", "[nvs]")
  374. {
  375. SpiFlashEmulator emu(8);
  376. emu.randomize(200);
  377. Storage storage;
  378. emu.setBounds(4, 8);
  379. CHECK(storage.init(4, 4) == ESP_OK);
  380. const char str[] = "foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234";
  381. size_t len = strlen(str);
  382. CHECK(storage.writeItem(1, ItemType::SZ, "foobaar", str, len + 1) == ESP_OK);
  383. size_t dataSize;
  384. CHECK(storage.getItemDataSize(1, ItemType::SZ, "foobaar", dataSize) == ESP_OK);
  385. CHECK(dataSize == len + 1);
  386. CHECK(storage.writeItem(2, ItemType::BLOB, "foobaar", str, len) == ESP_OK);
  387. CHECK(storage.getItemDataSize(2, ItemType::BLOB, "foobaar", dataSize) == ESP_OK);
  388. CHECK(dataSize == len);
  389. }
  390. TEST_CASE("can create namespaces", "[nvs]")
  391. {
  392. SpiFlashEmulator emu(8);
  393. Storage storage;
  394. emu.setBounds(4, 8);
  395. CHECK(storage.init(4, 4) == ESP_OK);
  396. uint8_t nsi;
  397. CHECK(storage.createOrOpenNamespace("wifi", false, nsi) == ESP_ERR_NVS_NOT_FOUND);
  398. CHECK(storage.createOrOpenNamespace("wifi", true, nsi) == ESP_OK);
  399. Page page;
  400. page.load(4);
  401. CHECK(page.findItem(Page::NS_INDEX, ItemType::U8, "wifi") == ESP_OK);
  402. }
  403. TEST_CASE("storage may become full", "[nvs]")
  404. {
  405. SpiFlashEmulator emu(8);
  406. Storage storage;
  407. emu.setBounds(4, 8);
  408. CHECK(storage.init(4, 4) == ESP_OK);
  409. for (size_t i = 0; i < Page::ENTRY_COUNT * 3; ++i) {
  410. char name[Item::MAX_KEY_LENGTH + 1];
  411. snprintf(name, sizeof(name), "key%05d", static_cast<int>(i));
  412. REQUIRE(storage.writeItem(1, name, static_cast<int>(i)) == ESP_OK);
  413. }
  414. REQUIRE(storage.writeItem(1, "foo", 10) == ESP_ERR_NVS_NOT_ENOUGH_SPACE);
  415. }
  416. TEST_CASE("can modify an item on a page which will be erased", "[nvs]")
  417. {
  418. SpiFlashEmulator emu(2);
  419. Storage storage;
  420. CHECK(storage.init(0, 2) == ESP_OK);
  421. for (size_t i = 0; i < Page::ENTRY_COUNT * 3 + 1; ++i) {
  422. REQUIRE(storage.writeItem(1, "foo", 42U) == ESP_OK);
  423. }
  424. }
  425. TEST_CASE("can erase items", "[nvs]")
  426. {
  427. SpiFlashEmulator emu(3);
  428. Storage storage;
  429. CHECK(storage.init(0, 3) == ESP_OK);
  430. for (size_t i = 0; i < Page::ENTRY_COUNT * 2 - 3; ++i) {
  431. char name[Item::MAX_KEY_LENGTH + 1];
  432. snprintf(name, sizeof(name), "key%05d", static_cast<int>(i));
  433. REQUIRE(storage.writeItem(3, name, static_cast<int>(i)) == ESP_OK);
  434. }
  435. CHECK(storage.writeItem(1, "foo", 32) == ESP_OK);
  436. CHECK(storage.writeItem(2, "foo", 64) == ESP_OK);
  437. CHECK(storage.eraseItem(2, "foo") == ESP_OK);
  438. int val;
  439. CHECK(storage.readItem(1, "foo", val) == ESP_OK);
  440. CHECK(val == 32);
  441. CHECK(storage.eraseNamespace(3) == ESP_OK);
  442. CHECK(storage.readItem(2, "foo", val) == ESP_ERR_NVS_NOT_FOUND);
  443. CHECK(storage.readItem(3, "key00222", val) == ESP_ERR_NVS_NOT_FOUND);
  444. }
  445. TEST_CASE("nvs api tests", "[nvs]")
  446. {
  447. SpiFlashEmulator emu(10);
  448. emu.randomize(100);
  449. nvs_handle handle_1;
  450. const uint32_t NVS_FLASH_SECTOR = 6;
  451. const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
  452. emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
  453. TEST_ESP_ERR(nvs_open("namespace1", NVS_READWRITE, &handle_1), ESP_ERR_NVS_NOT_INITIALIZED);
  454. for (uint16_t i = NVS_FLASH_SECTOR; i <NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN; ++i) {
  455. spi_flash_erase_sector(i);
  456. }
  457. TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  458. TEST_ESP_ERR(nvs_open("namespace1", NVS_READONLY, &handle_1), ESP_ERR_NVS_NOT_FOUND);
  459. // TEST_ESP_ERR(nvs_set_i32(handle_1, "foo", 0x12345678), ESP_ERR_NVS_READ_ONLY);
  460. // nvs_close(handle_1);
  461. TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle_1));
  462. TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x12345678));
  463. TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x23456789));
  464. nvs_handle handle_2;
  465. TEST_ESP_OK(nvs_open("namespace2", NVS_READWRITE, &handle_2));
  466. TEST_ESP_OK(nvs_set_i32(handle_2, "foo", 0x3456789a));
  467. const char* str = "value 0123456789abcdef0123456789abcdef";
  468. TEST_ESP_OK(nvs_set_str(handle_2, "key", str));
  469. int32_t v1;
  470. TEST_ESP_OK(nvs_get_i32(handle_1, "foo", &v1));
  471. CHECK(0x23456789 == v1);
  472. int32_t v2;
  473. TEST_ESP_OK(nvs_get_i32(handle_2, "foo", &v2));
  474. CHECK(0x3456789a == v2);
  475. char buf[strlen(str) + 1];
  476. size_t buf_len = sizeof(buf);
  477. size_t buf_len_needed;
  478. TEST_ESP_OK(nvs_get_str(handle_2, "key", NULL, &buf_len_needed));
  479. CHECK(buf_len_needed == buf_len);
  480. size_t buf_len_short = buf_len - 1;
  481. TEST_ESP_ERR(ESP_ERR_NVS_INVALID_LENGTH, nvs_get_str(handle_2, "key", buf, &buf_len_short));
  482. CHECK(buf_len_short == buf_len);
  483. size_t buf_len_long = buf_len + 1;
  484. TEST_ESP_OK(nvs_get_str(handle_2, "key", buf, &buf_len_long));
  485. CHECK(buf_len_long == buf_len);
  486. TEST_ESP_OK(nvs_get_str(handle_2, "key", buf, &buf_len));
  487. CHECK(0 == strcmp(buf, str));
  488. }
  489. TEST_CASE("wifi test", "[nvs]")
  490. {
  491. SpiFlashEmulator emu(10);
  492. emu.randomize(10);
  493. const uint32_t NVS_FLASH_SECTOR = 5;
  494. const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
  495. emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
  496. TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  497. nvs_handle misc_handle;
  498. TEST_ESP_OK(nvs_open("nvs.net80211", NVS_READWRITE, &misc_handle));
  499. char log[33];
  500. size_t log_size = sizeof(log);
  501. TEST_ESP_ERR(nvs_get_str(misc_handle, "log", log, &log_size), ESP_ERR_NVS_NOT_FOUND);
  502. strcpy(log, "foobarbazfizzz");
  503. TEST_ESP_OK(nvs_set_str(misc_handle, "log", log));
  504. nvs_handle net80211_handle;
  505. TEST_ESP_OK(nvs_open("nvs.net80211", NVS_READWRITE, &net80211_handle));
  506. uint8_t opmode = 2;
  507. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "wifi.opmode", &opmode), ESP_ERR_NVS_NOT_FOUND);
  508. TEST_ESP_OK(nvs_set_u8(net80211_handle, "wifi.opmode", opmode));
  509. uint8_t country = 0;
  510. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "wifi.country", &opmode), ESP_ERR_NVS_NOT_FOUND);
  511. TEST_ESP_OK(nvs_set_u8(net80211_handle, "wifi.country", opmode));
  512. char ssid[36];
  513. size_t size = sizeof(ssid);
  514. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.ssid", ssid, &size), ESP_ERR_NVS_NOT_FOUND);
  515. strcpy(ssid, "my android AP");
  516. TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.ssid", ssid, size));
  517. char mac[6];
  518. size = sizeof(mac);
  519. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.mac", mac, &size), ESP_ERR_NVS_NOT_FOUND);
  520. memset(mac, 0xab, 6);
  521. TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.mac", mac, size));
  522. uint8_t authmode = 1;
  523. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "sta.authmode", &authmode), ESP_ERR_NVS_NOT_FOUND);
  524. TEST_ESP_OK(nvs_set_u8(net80211_handle, "sta.authmode", authmode));
  525. char pswd[65];
  526. size = sizeof(pswd);
  527. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.pswd", pswd, &size), ESP_ERR_NVS_NOT_FOUND);
  528. strcpy(pswd, "`123456788990-=");
  529. TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.pswd", pswd, size));
  530. char pmk[32];
  531. size = sizeof(pmk);
  532. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.pmk", pmk, &size), ESP_ERR_NVS_NOT_FOUND);
  533. memset(pmk, 1, size);
  534. TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.pmk", pmk, size));
  535. uint8_t chan = 1;
  536. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "sta.chan", &chan), ESP_ERR_NVS_NOT_FOUND);
  537. TEST_ESP_OK(nvs_set_u8(net80211_handle, "sta.chan", chan));
  538. uint8_t autoconn = 1;
  539. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "auto.conn", &autoconn), ESP_ERR_NVS_NOT_FOUND);
  540. TEST_ESP_OK(nvs_set_u8(net80211_handle, "auto.conn", autoconn));
  541. uint8_t bssid_set = 1;
  542. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "bssid.set", &bssid_set), ESP_ERR_NVS_NOT_FOUND);
  543. TEST_ESP_OK(nvs_set_u8(net80211_handle, "bssid.set", bssid_set));
  544. char bssid[6];
  545. size = sizeof(bssid);
  546. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.bssid", bssid, &size), ESP_ERR_NVS_NOT_FOUND);
  547. memset(mac, 0xcd, 6);
  548. TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.bssid", bssid, size));
  549. uint8_t phym = 3;
  550. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "sta.phym", &phym), ESP_ERR_NVS_NOT_FOUND);
  551. TEST_ESP_OK(nvs_set_u8(net80211_handle, "sta.phym", phym));
  552. uint8_t phybw = 2;
  553. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "sta.phybw", &phybw), ESP_ERR_NVS_NOT_FOUND);
  554. TEST_ESP_OK(nvs_set_u8(net80211_handle, "sta.phybw", phybw));
  555. char apsw[2];
  556. size = sizeof(apsw);
  557. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.apsw", apsw, &size), ESP_ERR_NVS_NOT_FOUND);
  558. memset(apsw, 0x2, size);
  559. TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.apsw", apsw, size));
  560. char apinfo[700];
  561. size = sizeof(apinfo);
  562. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.apinfo", apinfo, &size), ESP_ERR_NVS_NOT_FOUND);
  563. memset(apinfo, 0, size);
  564. TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.apinfo", apinfo, size));
  565. size = sizeof(ssid);
  566. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "ap.ssid", ssid, &size), ESP_ERR_NVS_NOT_FOUND);
  567. strcpy(ssid, "ESP_A2F340");
  568. TEST_ESP_OK(nvs_set_blob(net80211_handle, "ap.ssid", ssid, size));
  569. size = sizeof(mac);
  570. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "ap.mac", mac, &size), ESP_ERR_NVS_NOT_FOUND);
  571. memset(mac, 0xac, 6);
  572. TEST_ESP_OK(nvs_set_blob(net80211_handle, "ap.mac", mac, size));
  573. size = sizeof(pswd);
  574. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "ap.passwd", pswd, &size), ESP_ERR_NVS_NOT_FOUND);
  575. strcpy(pswd, "");
  576. TEST_ESP_OK(nvs_set_blob(net80211_handle, "ap.passwd", pswd, size));
  577. size = sizeof(pmk);
  578. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "ap.pmk", pmk, &size), ESP_ERR_NVS_NOT_FOUND);
  579. memset(pmk, 1, size);
  580. TEST_ESP_OK(nvs_set_blob(net80211_handle, "ap.pmk", pmk, size));
  581. chan = 6;
  582. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "ap.chan", &chan), ESP_ERR_NVS_NOT_FOUND);
  583. TEST_ESP_OK(nvs_set_u8(net80211_handle, "ap.chan", chan));
  584. authmode = 0;
  585. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "ap.authmode", &authmode), ESP_ERR_NVS_NOT_FOUND);
  586. TEST_ESP_OK(nvs_set_u8(net80211_handle, "ap.authmode", authmode));
  587. uint8_t hidden = 0;
  588. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "ap.hidden", &hidden), ESP_ERR_NVS_NOT_FOUND);
  589. TEST_ESP_OK(nvs_set_u8(net80211_handle, "ap.hidden", hidden));
  590. uint8_t max_conn = 4;
  591. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "ap.max.conn", &max_conn), ESP_ERR_NVS_NOT_FOUND);
  592. TEST_ESP_OK(nvs_set_u8(net80211_handle, "ap.max.conn", max_conn));
  593. uint8_t bcn_interval = 2;
  594. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "bcn_interval", &bcn_interval), ESP_ERR_NVS_NOT_FOUND);
  595. TEST_ESP_OK(nvs_set_u8(net80211_handle, "bcn_interval", bcn_interval));
  596. 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;
  597. }
  598. TEST_CASE("can init storage from flash with random contents", "[nvs]")
  599. {
  600. SpiFlashEmulator emu(10);
  601. emu.randomize(42);
  602. nvs_handle handle;
  603. const uint32_t NVS_FLASH_SECTOR = 5;
  604. const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
  605. emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
  606. TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  607. TEST_ESP_OK(nvs_open("nvs.net80211", NVS_READWRITE, &handle));
  608. uint8_t opmode = 2;
  609. if (nvs_get_u8(handle, "wifi.opmode", &opmode) != ESP_OK) {
  610. TEST_ESP_OK(nvs_set_u8(handle, "wifi.opmode", opmode));
  611. }
  612. }
  613. TEST_CASE("nvs api tests, starting with random data in flash", "[nvs][long]")
  614. {
  615. const size_t testIters = 3000;
  616. int lastPercent = -1;
  617. for (size_t count = 0; count < testIters; ++count) {
  618. int percentDone = (int) (count * 100 / testIters);
  619. if (percentDone != lastPercent) {
  620. lastPercent = percentDone;
  621. printf("%d%%\n", percentDone);
  622. }
  623. SpiFlashEmulator emu(10);
  624. emu.randomize(static_cast<uint32_t>(count));
  625. const uint32_t NVS_FLASH_SECTOR = 6;
  626. const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
  627. emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
  628. TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  629. nvs_handle handle_1;
  630. TEST_ESP_ERR(nvs_open("namespace1", NVS_READONLY, &handle_1), ESP_ERR_NVS_NOT_FOUND);
  631. TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle_1));
  632. TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x12345678));
  633. for (size_t i = 0; i < 500; ++i) {
  634. nvs_handle handle_2;
  635. TEST_ESP_OK(nvs_open("namespace2", NVS_READWRITE, &handle_2));
  636. TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x23456789 % (i + 1)));
  637. TEST_ESP_OK(nvs_set_i32(handle_2, "foo", static_cast<int32_t>(i)));
  638. const char* str = "value 0123456789abcdef0123456789abcdef %09d";
  639. char str_buf[128];
  640. snprintf(str_buf, sizeof(str_buf), str, i + count * 1024);
  641. TEST_ESP_OK(nvs_set_str(handle_2, "key", str_buf));
  642. int32_t v1;
  643. TEST_ESP_OK(nvs_get_i32(handle_1, "foo", &v1));
  644. CHECK(0x23456789 % (i + 1) == v1);
  645. int32_t v2;
  646. TEST_ESP_OK(nvs_get_i32(handle_2, "foo", &v2));
  647. CHECK(static_cast<int32_t>(i) == v2);
  648. char buf[128];
  649. size_t buf_len = sizeof(buf);
  650. TEST_ESP_OK(nvs_get_str(handle_2, "key", buf, &buf_len));
  651. CHECK(0 == strcmp(buf, str_buf));
  652. nvs_close(handle_2);
  653. }
  654. nvs_close(handle_1);
  655. }
  656. }
  657. extern "C" void nvs_dump(const char *partName);
  658. class RandomTest {
  659. static const size_t nKeys = 11;
  660. int32_t v1 = 0, v2 = 0;
  661. uint64_t v3 = 0, v4 = 0;
  662. static const size_t strBufLen = 1024;
  663. static const size_t smallBlobLen = Page::CHUNK_MAX_SIZE / 3;
  664. static const size_t largeBlobLen = Page::CHUNK_MAX_SIZE * 3;
  665. char v5[strBufLen], v6[strBufLen], v7[strBufLen], v8[strBufLen], v9[strBufLen];
  666. uint8_t v10[smallBlobLen], v11[largeBlobLen];
  667. bool written[nKeys];
  668. public:
  669. RandomTest()
  670. {
  671. std::fill_n(written, nKeys, false);
  672. }
  673. template<typename TGen>
  674. esp_err_t doRandomThings(nvs_handle handle, TGen gen, size_t& count) {
  675. const char* keys[] = {"foo", "bar", "longkey_0123456", "another key", "param1", "param2", "param3", "param4", "param5", "singlepage", "multipage"};
  676. const ItemType types[] = {ItemType::I32, ItemType::I32, ItemType::U64, ItemType::U64, ItemType::SZ, ItemType::SZ, ItemType::SZ, ItemType::SZ, ItemType::SZ, ItemType::BLOB, ItemType::BLOB};
  677. void* values[] = {&v1, &v2, &v3, &v4, &v5, &v6, &v7, &v8, &v9, &v10, &v11};
  678. const size_t nKeys = sizeof(keys) / sizeof(keys[0]);
  679. static_assert(nKeys == sizeof(types) / sizeof(types[0]), "");
  680. static_assert(nKeys == sizeof(values) / sizeof(values[0]), "");
  681. auto randomRead = [&](size_t index) -> esp_err_t {
  682. switch (types[index]) {
  683. case ItemType::I32:
  684. {
  685. int32_t val;
  686. auto err = nvs_get_i32(handle, keys[index], &val);
  687. if (err == ESP_ERR_FLASH_OP_FAIL) {
  688. return err;
  689. }
  690. if (!written[index]) {
  691. REQUIRE(err == ESP_ERR_NVS_NOT_FOUND);
  692. }
  693. else {
  694. REQUIRE(err == ESP_OK);
  695. REQUIRE(val == *reinterpret_cast<int32_t*>(values[index]));
  696. }
  697. break;
  698. }
  699. case ItemType::U64:
  700. {
  701. uint64_t val;
  702. auto err = nvs_get_u64(handle, keys[index], &val);
  703. if (err == ESP_ERR_FLASH_OP_FAIL) {
  704. return err;
  705. }
  706. if (!written[index]) {
  707. REQUIRE(err == ESP_ERR_NVS_NOT_FOUND);
  708. }
  709. else {
  710. REQUIRE(err == ESP_OK);
  711. REQUIRE(val == *reinterpret_cast<uint64_t*>(values[index]));
  712. }
  713. break;
  714. }
  715. case ItemType::SZ:
  716. {
  717. char buf[strBufLen];
  718. size_t len = strBufLen;
  719. auto err = nvs_get_str(handle, keys[index], buf, &len);
  720. if (err == ESP_ERR_FLASH_OP_FAIL) {
  721. return err;
  722. }
  723. if (!written[index]) {
  724. REQUIRE(err == ESP_ERR_NVS_NOT_FOUND);
  725. }
  726. else {
  727. REQUIRE(err == ESP_OK);
  728. REQUIRE(strncmp(buf, reinterpret_cast<const char*>(values[index]), strBufLen) == 0);
  729. }
  730. break;
  731. }
  732. case ItemType::BLOB:
  733. {
  734. uint32_t blobBufLen = 0;
  735. if(strncmp(keys[index],"singlepage", sizeof("singlepage")) == 0) {
  736. blobBufLen = smallBlobLen ;
  737. } else {
  738. blobBufLen = largeBlobLen ;
  739. }
  740. uint8_t buf[blobBufLen];
  741. memset(buf, 0, blobBufLen);
  742. size_t len = blobBufLen;
  743. auto err = nvs_get_blob(handle, keys[index], buf, &len);
  744. if (err == ESP_ERR_FLASH_OP_FAIL) {
  745. return err;
  746. }
  747. if (!written[index]) {
  748. REQUIRE(err == ESP_ERR_NVS_NOT_FOUND);
  749. }
  750. else {
  751. REQUIRE(err == ESP_OK);
  752. REQUIRE(memcmp(buf, reinterpret_cast<const uint8_t*>(values[index]), blobBufLen) == 0);
  753. }
  754. break;
  755. }
  756. default:
  757. assert(0);
  758. }
  759. return ESP_OK;
  760. };
  761. auto randomWrite = [&](size_t index) -> esp_err_t {
  762. switch (types[index]) {
  763. case ItemType::I32:
  764. {
  765. int32_t val = static_cast<int32_t>(gen());
  766. auto err = nvs_set_i32(handle, keys[index], val);
  767. if (err == ESP_ERR_FLASH_OP_FAIL) {
  768. return err;
  769. }
  770. if (err == ESP_ERR_NVS_REMOVE_FAILED) {
  771. written[index] = true;
  772. *reinterpret_cast<int32_t*>(values[index]) = val;
  773. return ESP_ERR_FLASH_OP_FAIL;
  774. }
  775. REQUIRE(err == ESP_OK);
  776. written[index] = true;
  777. *reinterpret_cast<int32_t*>(values[index]) = val;
  778. break;
  779. }
  780. case ItemType::U64:
  781. {
  782. uint64_t val = static_cast<uint64_t>(gen());
  783. auto err = nvs_set_u64(handle, keys[index], val);
  784. if (err == ESP_ERR_FLASH_OP_FAIL) {
  785. return err;
  786. }
  787. if (err == ESP_ERR_NVS_REMOVE_FAILED) {
  788. written[index] = true;
  789. *reinterpret_cast<uint64_t*>(values[index]) = val;
  790. return ESP_ERR_FLASH_OP_FAIL;
  791. }
  792. REQUIRE(err == ESP_OK);
  793. written[index] = true;
  794. *reinterpret_cast<uint64_t*>(values[index]) = val;
  795. break;
  796. }
  797. case ItemType::SZ:
  798. {
  799. char buf[strBufLen];
  800. size_t len = strBufLen;
  801. size_t strLen = gen() % (strBufLen - 1);
  802. std::generate_n(buf, strLen, [&]() -> char {
  803. const char c = static_cast<char>(gen() % 127);
  804. return (c < 32) ? 32 : c;
  805. });
  806. buf[strLen] = 0;
  807. auto err = nvs_set_str(handle, keys[index], buf);
  808. if (err == ESP_ERR_FLASH_OP_FAIL) {
  809. return err;
  810. }
  811. if (err == ESP_ERR_NVS_REMOVE_FAILED) {
  812. written[index] = true;
  813. strncpy(reinterpret_cast<char*>(values[index]), buf, strBufLen);
  814. return ESP_ERR_FLASH_OP_FAIL;
  815. }
  816. REQUIRE(err == ESP_OK);
  817. written[index] = true;
  818. strncpy(reinterpret_cast<char*>(values[index]), buf, strBufLen);
  819. break;
  820. }
  821. case ItemType::BLOB:
  822. {
  823. uint32_t blobBufLen = 0;
  824. if(strncmp(keys[index],"singlepage", sizeof("singlepage")) == 0) {
  825. blobBufLen = smallBlobLen ;
  826. } else {
  827. blobBufLen = largeBlobLen ;
  828. }
  829. uint8_t buf[blobBufLen];
  830. memset(buf, 0, blobBufLen);
  831. size_t blobLen = gen() % blobBufLen;
  832. std::generate_n(buf, blobLen, [&]() -> uint8_t {
  833. return static_cast<uint8_t>(gen() % 256);
  834. });
  835. auto err = nvs_set_blob(handle, keys[index], buf, blobLen);
  836. if (err == ESP_ERR_FLASH_OP_FAIL) {
  837. return err;
  838. }
  839. if (err == ESP_ERR_NVS_REMOVE_FAILED) {
  840. written[index] = true;
  841. memcpy(reinterpret_cast<uint8_t*>(values[index]), buf, blobBufLen);
  842. return ESP_ERR_FLASH_OP_FAIL;
  843. }
  844. REQUIRE(err == ESP_OK);
  845. written[index] = true;
  846. memcpy(reinterpret_cast<char*>(values[index]), buf, blobBufLen);
  847. break;
  848. }
  849. default:
  850. assert(0);
  851. }
  852. return ESP_OK;
  853. };
  854. for (; count != 0; --count) {
  855. size_t index = gen() % (nKeys);
  856. switch (gen() % 3) {
  857. case 0: // read, 1/3
  858. if (randomRead(index) == ESP_ERR_FLASH_OP_FAIL) {
  859. return ESP_ERR_FLASH_OP_FAIL;
  860. }
  861. break;
  862. default: // write, 2/3
  863. if (randomWrite(index) == ESP_ERR_FLASH_OP_FAIL) {
  864. return ESP_ERR_FLASH_OP_FAIL;
  865. }
  866. break;
  867. }
  868. }
  869. return ESP_OK;
  870. }
  871. esp_err_t handleExternalWriteAtIndex(uint8_t index, const void* value, const size_t len ) {
  872. if(index == 9) { /* This is only done for small-page blobs for now*/
  873. if(len > smallBlobLen) {
  874. return ESP_FAIL;
  875. }
  876. memcpy(v10, value, len);
  877. written[index] = true;
  878. return ESP_OK;
  879. } else {
  880. return ESP_FAIL;
  881. }
  882. }
  883. };
  884. TEST_CASE("monkey test", "[nvs][monkey]")
  885. {
  886. std::random_device rd;
  887. std::mt19937 gen(rd());
  888. uint32_t seed = 3;
  889. gen.seed(seed);
  890. SpiFlashEmulator emu(10);
  891. emu.randomize(seed);
  892. emu.clearStats();
  893. const uint32_t NVS_FLASH_SECTOR = 2;
  894. const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 8;
  895. emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
  896. TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  897. nvs_handle handle;
  898. TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle));
  899. RandomTest test;
  900. size_t count = 1000;
  901. CHECK(test.doRandomThings(handle, gen, count) == ESP_OK);
  902. s_perf << "Monkey test: nErase=" << emu.getEraseOps() << " nWrite=" << emu.getWriteOps() << std::endl;
  903. }
  904. TEST_CASE("test recovery from sudden poweroff", "[long][nvs][recovery][monkey]")
  905. {
  906. std::random_device rd;
  907. std::mt19937 gen(rd());
  908. uint32_t seed = 3;
  909. gen.seed(seed);
  910. const size_t iter_count = 2000;
  911. SpiFlashEmulator emu(10);
  912. const uint32_t NVS_FLASH_SECTOR = 2;
  913. const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 8;
  914. emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
  915. size_t totalOps = 0;
  916. int lastPercent = -1;
  917. for (uint32_t errDelay = 0; ; ++errDelay) {
  918. INFO(errDelay);
  919. emu.randomize(seed);
  920. emu.clearStats();
  921. emu.failAfter(errDelay);
  922. RandomTest test;
  923. if (totalOps != 0) {
  924. int percent = errDelay * 100 / totalOps;
  925. if (percent > lastPercent) {
  926. printf("%d/%d (%d%%)\r\n", errDelay, static_cast<int>(totalOps), percent);
  927. lastPercent = percent;
  928. }
  929. }
  930. nvs_handle handle;
  931. size_t count = iter_count;
  932. if (nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK) {
  933. if (nvs_open("namespace1", NVS_READWRITE, &handle) == ESP_OK) {
  934. if(test.doRandomThings(handle, gen, count) != ESP_ERR_FLASH_OP_FAIL) {
  935. nvs_close(handle);
  936. break;
  937. }
  938. nvs_close(handle);
  939. }
  940. }
  941. TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  942. TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle));
  943. auto res = test.doRandomThings(handle, gen, count);
  944. if (res != ESP_OK) {
  945. nvs_dump(NVS_DEFAULT_PART_NAME);
  946. CHECK(0);
  947. }
  948. nvs_close(handle);
  949. totalOps = emu.getEraseOps() + emu.getWriteBytes() / 4;
  950. }
  951. }
  952. TEST_CASE("test for memory leaks in open/set", "[leaks]")
  953. {
  954. SpiFlashEmulator emu(10);
  955. const uint32_t NVS_FLASH_SECTOR = 6;
  956. const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
  957. emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
  958. TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  959. for (int i = 0; i < 100000; ++i) {
  960. nvs_handle light_handle = 0;
  961. char lightbulb[1024] = {12, 13, 14, 15, 16};
  962. TEST_ESP_OK(nvs_open("light", NVS_READWRITE, &light_handle));
  963. TEST_ESP_OK(nvs_set_blob(light_handle, "key", lightbulb, sizeof(lightbulb)));
  964. TEST_ESP_OK(nvs_commit(light_handle));
  965. nvs_close(light_handle);
  966. }
  967. }
  968. TEST_CASE("duplicate items are removed", "[nvs][dupes]")
  969. {
  970. SpiFlashEmulator emu(3);
  971. {
  972. // create one item
  973. nvs::Page p;
  974. p.load(0);
  975. p.writeItem<uint8_t>(1, "opmode", 3);
  976. }
  977. {
  978. // add another two without deleting the first one
  979. nvs::Item item(1, ItemType::U8, 1, "opmode");
  980. item.data[0] = 2;
  981. item.crc32 = item.calculateCrc32();
  982. emu.write(3 * 32, reinterpret_cast<const uint32_t*>(&item), sizeof(item));
  983. emu.write(4 * 32, reinterpret_cast<const uint32_t*>(&item), sizeof(item));
  984. uint32_t mask = 0xFFFFFFEA;
  985. emu.write(32, &mask, 4);
  986. }
  987. {
  988. // load page and check that second item persists
  989. nvs::Storage s;
  990. s.init(0, 3);
  991. uint8_t val;
  992. ESP_ERROR_CHECK(s.readItem(1, "opmode", val));
  993. CHECK(val == 2);
  994. }
  995. {
  996. Page p;
  997. p.load(0);
  998. CHECK(p.getErasedEntryCount() == 2);
  999. CHECK(p.getUsedEntryCount() == 1);
  1000. }
  1001. }
  1002. TEST_CASE("recovery after failure to write data", "[nvs]")
  1003. {
  1004. SpiFlashEmulator emu(3);
  1005. const char str[] = "value 0123456789abcdef012345678value 0123456789abcdef012345678";
  1006. // make flash write fail exactly in Page::writeEntryData
  1007. emu.failAfter(17);
  1008. {
  1009. Storage storage;
  1010. TEST_ESP_OK(storage.init(0, 3));
  1011. TEST_ESP_ERR(storage.writeItem(1, ItemType::SZ, "key", str, strlen(str)), ESP_ERR_FLASH_OP_FAIL);
  1012. // check that repeated operations cause an error
  1013. TEST_ESP_ERR(storage.writeItem(1, ItemType::SZ, "key", str, strlen(str)), ESP_ERR_NVS_INVALID_STATE);
  1014. uint8_t val;
  1015. TEST_ESP_ERR(storage.readItem(1, ItemType::U8, "key", &val, sizeof(val)), ESP_ERR_NVS_NOT_FOUND);
  1016. }
  1017. {
  1018. // load page and check that data was erased
  1019. Page p;
  1020. p.load(0);
  1021. CHECK(p.getErasedEntryCount() == 3);
  1022. CHECK(p.getUsedEntryCount() == 0);
  1023. // try to write again
  1024. TEST_ESP_OK(p.writeItem(1, ItemType::SZ, "key", str, strlen(str)));
  1025. }
  1026. }
  1027. TEST_CASE("crc errors in item header are handled", "[nvs]")
  1028. {
  1029. SpiFlashEmulator emu(3);
  1030. Storage storage;
  1031. // prepare some data
  1032. TEST_ESP_OK(storage.init(0, 3));
  1033. TEST_ESP_OK(storage.writeItem(0, "ns1", static_cast<uint8_t>(1)));
  1034. TEST_ESP_OK(storage.writeItem(1, "value1", static_cast<uint32_t>(1)));
  1035. TEST_ESP_OK(storage.writeItem(1, "value2", static_cast<uint32_t>(2)));
  1036. // corrupt item header
  1037. uint32_t val = 0;
  1038. emu.write(32 * 3, &val, 4);
  1039. // check that storage can recover
  1040. TEST_ESP_OK(storage.init(0, 3));
  1041. TEST_ESP_OK(storage.readItem(1, "value2", val));
  1042. CHECK(val == 2);
  1043. // check that the corrupted item is no longer present
  1044. TEST_ESP_ERR(ESP_ERR_NVS_NOT_FOUND, storage.readItem(1, "value1", val));
  1045. // add more items to make the page full
  1046. for (size_t i = 0; i < Page::ENTRY_COUNT; ++i) {
  1047. char item_name[Item::MAX_KEY_LENGTH + 1];
  1048. snprintf(item_name, sizeof(item_name), "item_%ld", (long int)i);
  1049. TEST_ESP_OK(storage.writeItem(1, item_name, static_cast<uint32_t>(i)));
  1050. }
  1051. // corrupt another item on the full page
  1052. val = 0;
  1053. emu.write(32 * 4, &val, 4);
  1054. // check that storage can recover
  1055. TEST_ESP_OK(storage.init(0, 3));
  1056. // check that the corrupted item is no longer present
  1057. TEST_ESP_ERR(ESP_ERR_NVS_NOT_FOUND, storage.readItem(1, "value2", val));
  1058. }
  1059. TEST_CASE("crc error in variable length item is handled", "[nvs]")
  1060. {
  1061. SpiFlashEmulator emu(3);
  1062. const uint64_t before_val = 0xbef04e;
  1063. const uint64_t after_val = 0xaf7e4;
  1064. // write some data
  1065. {
  1066. Page p;
  1067. p.load(0);
  1068. TEST_ESP_OK(p.writeItem<uint64_t>(0, "before", before_val));
  1069. const char* str = "foobar";
  1070. TEST_ESP_OK(p.writeItem(0, ItemType::SZ, "key", str, strlen(str)));
  1071. TEST_ESP_OK(p.writeItem<uint64_t>(0, "after", after_val));
  1072. }
  1073. // corrupt some data
  1074. uint32_t w;
  1075. CHECK(emu.read(&w, 32 * 3 + 8, sizeof(w)));
  1076. w &= 0xf000000f;
  1077. CHECK(emu.write(32 * 3 + 8, &w, sizeof(w)));
  1078. // load and check
  1079. {
  1080. Page p;
  1081. p.load(0);
  1082. CHECK(p.getUsedEntryCount() == 2);
  1083. CHECK(p.getErasedEntryCount() == 2);
  1084. uint64_t val;
  1085. TEST_ESP_OK(p.readItem<uint64_t>(0, "before", val));
  1086. CHECK(val == before_val);
  1087. TEST_ESP_ERR(p.findItem(0, ItemType::SZ, "key"), ESP_ERR_NVS_NOT_FOUND);
  1088. TEST_ESP_OK(p.readItem<uint64_t>(0, "after", val));
  1089. CHECK(val == after_val);
  1090. }
  1091. }
  1092. TEST_CASE("read/write failure (TW8406)", "[nvs]")
  1093. {
  1094. SpiFlashEmulator emu(3);
  1095. nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 3);
  1096. for (int attempts = 0; attempts < 3; ++attempts) {
  1097. int i = 0;
  1098. nvs_handle light_handle = 0;
  1099. char key[15] = {0};
  1100. char data[76] = {12, 13, 14, 15, 16};
  1101. uint8_t number = 20;
  1102. size_t data_len = sizeof(data);
  1103. ESP_ERROR_CHECK(nvs_open("LIGHT", NVS_READWRITE, &light_handle));
  1104. ESP_ERROR_CHECK(nvs_set_u8(light_handle, "RecordNum", number));
  1105. for (i = 0; i < number; ++i) {
  1106. sprintf(key, "light%d", i);
  1107. ESP_ERROR_CHECK(nvs_set_blob(light_handle, key, data, sizeof(data)));
  1108. }
  1109. nvs_commit(light_handle);
  1110. uint8_t get_number = 0;
  1111. ESP_ERROR_CHECK(nvs_get_u8(light_handle, "RecordNum", &get_number));
  1112. REQUIRE(number == get_number);
  1113. for (i = 0; i < number; ++i) {
  1114. char data[76] = {0};
  1115. sprintf(key, "light%d", i);
  1116. ESP_ERROR_CHECK(nvs_get_blob(light_handle, key, data, &data_len));
  1117. }
  1118. nvs_close(light_handle);
  1119. }
  1120. }
  1121. TEST_CASE("nvs_flash_init checks for an empty page", "[nvs]")
  1122. {
  1123. const size_t blob_size = Page::CHUNK_MAX_SIZE;
  1124. uint8_t blob[blob_size] = {0};
  1125. SpiFlashEmulator emu(5);
  1126. TEST_ESP_OK( nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 5) );
  1127. nvs_handle handle;
  1128. TEST_ESP_OK( nvs_open("test", NVS_READWRITE, &handle) );
  1129. // Fill first page
  1130. TEST_ESP_OK( nvs_set_blob(handle, "1a", blob, blob_size) );
  1131. // Fill second page
  1132. TEST_ESP_OK( nvs_set_blob(handle, "2a", blob, blob_size) );
  1133. // Fill third page
  1134. TEST_ESP_OK( nvs_set_blob(handle, "3a", blob, blob_size) );
  1135. TEST_ESP_OK( nvs_commit(handle) );
  1136. nvs_close(handle);
  1137. // first two pages are now full, third one is writable, last two are empty
  1138. // init should fail
  1139. TEST_ESP_ERR( nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 3), ESP_ERR_NVS_NO_FREE_PAGES );
  1140. }
  1141. TEST_CASE("multiple partitions access check", "[nvs]")
  1142. {
  1143. SpiFlashEmulator emu(10);
  1144. TEST_ESP_OK( nvs_flash_init_custom("nvs1", 0, 5) );
  1145. TEST_ESP_OK( nvs_flash_init_custom("nvs2", 5, 5) );
  1146. nvs_handle handle1, handle2;
  1147. TEST_ESP_OK( nvs_open_from_partition("nvs1", "test", NVS_READWRITE, &handle1) );
  1148. TEST_ESP_OK( nvs_open_from_partition("nvs2", "test", NVS_READWRITE, &handle2) );
  1149. TEST_ESP_OK( nvs_set_i32(handle1, "foo", 0xdeadbeef));
  1150. TEST_ESP_OK( nvs_set_i32(handle2, "foo", 0xcafebabe));
  1151. int32_t v1, v2;
  1152. TEST_ESP_OK( nvs_get_i32(handle1, "foo", &v1));
  1153. TEST_ESP_OK( nvs_get_i32(handle2, "foo", &v2));
  1154. CHECK(v1 == 0xdeadbeef);
  1155. CHECK(v2 == 0xcafebabe);
  1156. }
  1157. TEST_CASE("nvs page selection takes into account free entries also not just erased entries", "[nvs]")
  1158. {
  1159. const size_t blob_size = Page::CHUNK_MAX_SIZE/2;
  1160. uint8_t blob[blob_size] = {0};
  1161. SpiFlashEmulator emu(3);
  1162. TEST_ESP_OK( nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 3) );
  1163. nvs_handle handle;
  1164. TEST_ESP_OK( nvs_open("test", NVS_READWRITE, &handle) );
  1165. // Fill first page
  1166. TEST_ESP_OK( nvs_set_blob(handle, "1a", blob, blob_size/3) );
  1167. TEST_ESP_OK( nvs_set_blob(handle, "1b", blob, blob_size) );
  1168. // Fill second page
  1169. TEST_ESP_OK( nvs_set_blob(handle, "2a", blob, blob_size) );
  1170. TEST_ESP_OK( nvs_set_blob(handle, "2b", blob, blob_size) );
  1171. // The item below should be able to fit the first page.
  1172. TEST_ESP_OK( nvs_set_blob(handle, "3a", blob, 4) );
  1173. TEST_ESP_OK( nvs_commit(handle) );
  1174. nvs_close(handle);
  1175. }
  1176. TEST_CASE("calculate used and free space", "[nvs]")
  1177. {
  1178. SpiFlashEmulator emu(6);
  1179. nvs_flash_deinit();
  1180. TEST_ESP_ERR(nvs_get_stats(NULL, NULL), ESP_ERR_INVALID_ARG);
  1181. nvs_stats_t stat1;
  1182. nvs_stats_t stat2;
  1183. TEST_ESP_ERR(nvs_get_stats(NULL, &stat1), ESP_ERR_NVS_NOT_INITIALIZED);
  1184. CHECK(stat1.free_entries == 0);
  1185. CHECK(stat1.namespace_count == 0);
  1186. CHECK(stat1.total_entries == 0);
  1187. CHECK(stat1.used_entries == 0);
  1188. nvs_handle handle = 0;
  1189. size_t h_count_entries;
  1190. TEST_ESP_ERR(nvs_get_used_entry_count(handle, &h_count_entries), ESP_ERR_NVS_INVALID_HANDLE);
  1191. CHECK(h_count_entries == 0);
  1192. // init nvs
  1193. TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 6));
  1194. TEST_ESP_ERR(nvs_get_used_entry_count(handle, &h_count_entries), ESP_ERR_NVS_INVALID_HANDLE);
  1195. CHECK(h_count_entries == 0);
  1196. Page p;
  1197. // after erase. empty partition
  1198. TEST_ESP_OK(nvs_get_stats(NULL, &stat1));
  1199. CHECK(stat1.free_entries != 0);
  1200. CHECK(stat1.namespace_count == 0);
  1201. CHECK(stat1.total_entries == 6 * p.ENTRY_COUNT);
  1202. CHECK(stat1.used_entries == 0);
  1203. // create namespace test_k1
  1204. nvs_handle handle_1;
  1205. TEST_ESP_OK(nvs_open("test_k1", NVS_READWRITE, &handle_1));
  1206. TEST_ESP_OK(nvs_get_stats(NULL, &stat2));
  1207. CHECK(stat2.free_entries + 1 == stat1.free_entries);
  1208. CHECK(stat2.namespace_count == 1);
  1209. CHECK(stat2.total_entries == stat1.total_entries);
  1210. CHECK(stat2.used_entries == 1);
  1211. // create pair key-value com
  1212. TEST_ESP_OK(nvs_set_i32(handle_1, "com", 0x12345678));
  1213. TEST_ESP_OK(nvs_get_stats(NULL, &stat1));
  1214. CHECK(stat1.free_entries + 1 == stat2.free_entries);
  1215. CHECK(stat1.namespace_count == 1);
  1216. CHECK(stat1.total_entries == stat2.total_entries);
  1217. CHECK(stat1.used_entries == 2);
  1218. // change value in com
  1219. TEST_ESP_OK(nvs_set_i32(handle_1, "com", 0x01234567));
  1220. TEST_ESP_OK(nvs_get_stats(NULL, &stat2));
  1221. CHECK(stat2.free_entries == stat1.free_entries);
  1222. CHECK(stat2.namespace_count == 1);
  1223. CHECK(stat2.total_entries != 0);
  1224. CHECK(stat2.used_entries == 2);
  1225. // create pair key-value ru
  1226. TEST_ESP_OK(nvs_set_i32(handle_1, "ru", 0x00FF00FF));
  1227. TEST_ESP_OK(nvs_get_stats(NULL, &stat1));
  1228. CHECK(stat1.free_entries + 1 == stat2.free_entries);
  1229. CHECK(stat1.namespace_count == 1);
  1230. CHECK(stat1.total_entries != 0);
  1231. CHECK(stat1.used_entries == 3);
  1232. // amount valid pair in namespace 1
  1233. size_t h1_count_entries;
  1234. TEST_ESP_OK(nvs_get_used_entry_count(handle_1, &h1_count_entries));
  1235. CHECK(h1_count_entries == 2);
  1236. nvs_handle handle_2;
  1237. // create namespace test_k2
  1238. TEST_ESP_OK(nvs_open("test_k2", NVS_READWRITE, &handle_2));
  1239. TEST_ESP_OK(nvs_get_stats(NULL, &stat2));
  1240. CHECK(stat2.free_entries + 1 == stat1.free_entries);
  1241. CHECK(stat2.namespace_count == 2);
  1242. CHECK(stat2.total_entries == stat1.total_entries);
  1243. CHECK(stat2.used_entries == 4);
  1244. // create pair key-value
  1245. TEST_ESP_OK(nvs_set_i32(handle_2, "su1", 0x00000001));
  1246. TEST_ESP_OK(nvs_set_i32(handle_2, "su2", 0x00000002));
  1247. TEST_ESP_OK(nvs_set_i32(handle_2, "sus", 0x00000003));
  1248. TEST_ESP_OK(nvs_get_stats(NULL, &stat1));
  1249. CHECK(stat1.free_entries + 3 == stat2.free_entries);
  1250. CHECK(stat1.namespace_count == 2);
  1251. CHECK(stat1.total_entries == stat2.total_entries);
  1252. CHECK(stat1.used_entries == 7);
  1253. CHECK(stat1.total_entries == (stat1.used_entries + stat1.free_entries));
  1254. // amount valid pair in namespace 2
  1255. size_t h2_count_entries;
  1256. TEST_ESP_OK(nvs_get_used_entry_count(handle_2, &h2_count_entries));
  1257. CHECK(h2_count_entries == 3);
  1258. CHECK(stat1.used_entries == (h1_count_entries + h2_count_entries + stat1.namespace_count));
  1259. nvs_close(handle_1);
  1260. nvs_close(handle_2);
  1261. size_t temp = h2_count_entries;
  1262. TEST_ESP_ERR(nvs_get_used_entry_count(handle_1, &h2_count_entries), ESP_ERR_NVS_INVALID_HANDLE);
  1263. CHECK(h2_count_entries == 0);
  1264. h2_count_entries = temp;
  1265. TEST_ESP_ERR(nvs_get_used_entry_count(handle_1, NULL), ESP_ERR_INVALID_ARG);
  1266. nvs_handle handle_3;
  1267. // create namespace test_k3
  1268. TEST_ESP_OK(nvs_open("test_k3", NVS_READWRITE, &handle_3));
  1269. TEST_ESP_OK(nvs_get_stats(NULL, &stat2));
  1270. CHECK(stat2.free_entries + 1 == stat1.free_entries);
  1271. CHECK(stat2.namespace_count == 3);
  1272. CHECK(stat2.total_entries == stat1.total_entries);
  1273. CHECK(stat2.used_entries == 8);
  1274. // create pair blobs
  1275. uint32_t blob[12];
  1276. TEST_ESP_OK(nvs_set_blob(handle_3, "bl1", &blob, sizeof(blob)));
  1277. TEST_ESP_OK(nvs_get_stats(NULL, &stat1));
  1278. CHECK(stat1.free_entries + 4 == stat2.free_entries);
  1279. CHECK(stat1.namespace_count == 3);
  1280. CHECK(stat1.total_entries == stat2.total_entries);
  1281. CHECK(stat1.used_entries == 12);
  1282. // amount valid pair in namespace 2
  1283. size_t h3_count_entries;
  1284. TEST_ESP_OK(nvs_get_used_entry_count(handle_3, &h3_count_entries));
  1285. CHECK(h3_count_entries == 4);
  1286. CHECK(stat1.used_entries == (h1_count_entries + h2_count_entries + h3_count_entries + stat1.namespace_count));
  1287. nvs_close(handle_3);
  1288. }
  1289. TEST_CASE("Recovery from power-off when the entry being erased is not on active page", "[nvs]")
  1290. {
  1291. const size_t blob_size = Page::CHUNK_MAX_SIZE/2 ;
  1292. size_t read_size = blob_size;
  1293. uint8_t blob[blob_size] = {0x11};
  1294. SpiFlashEmulator emu(3);
  1295. TEST_ESP_OK( nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 3) );
  1296. nvs_handle handle;
  1297. TEST_ESP_OK( nvs_open("test", NVS_READWRITE, &handle) );
  1298. emu.clearStats();
  1299. emu.failAfter(Page::CHUNK_MAX_SIZE/4 + 75);
  1300. TEST_ESP_OK( nvs_set_blob(handle, "1a", blob, blob_size) );
  1301. TEST_ESP_OK( nvs_set_blob(handle, "1b", blob, blob_size) );
  1302. TEST_ESP_ERR( nvs_erase_key(handle, "1a"), ESP_ERR_FLASH_OP_FAIL );
  1303. TEST_ESP_OK( nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 3) );
  1304. /* Check 1a is erased fully*/
  1305. TEST_ESP_ERR( nvs_get_blob(handle, "1a", blob, &read_size), ESP_ERR_NVS_NOT_FOUND);
  1306. /* Check 2b is still accessible*/
  1307. TEST_ESP_OK( nvs_get_blob(handle, "1b", blob, &read_size));
  1308. nvs_close(handle);
  1309. }
  1310. TEST_CASE("Recovery from power-off when page is being freed.", "[nvs]")
  1311. {
  1312. const size_t blob_size = (Page::ENTRY_COUNT-3) * Page::ENTRY_SIZE;
  1313. size_t read_size = blob_size/2;
  1314. uint8_t blob[blob_size] = {0};
  1315. SpiFlashEmulator emu(3);
  1316. TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 3));
  1317. nvs_handle handle;
  1318. TEST_ESP_OK(nvs_open("test", NVS_READWRITE, &handle));
  1319. // Fill first page
  1320. TEST_ESP_OK(nvs_set_blob(handle, "1a", blob, blob_size/3));
  1321. TEST_ESP_OK(nvs_set_blob(handle, "1b", blob, blob_size/3));
  1322. TEST_ESP_OK(nvs_set_blob(handle, "1c", blob, blob_size/4));
  1323. // Fill second page
  1324. TEST_ESP_OK(nvs_set_blob(handle, "2a", blob, blob_size/2));
  1325. TEST_ESP_OK(nvs_set_blob(handle, "2b", blob, blob_size/2));
  1326. TEST_ESP_OK(nvs_erase_key(handle, "1c"));
  1327. emu.clearStats();
  1328. emu.failAfter(6 * Page::ENTRY_COUNT);
  1329. TEST_ESP_ERR(nvs_set_blob(handle, "1d", blob, blob_size/4), ESP_ERR_FLASH_OP_FAIL);
  1330. TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 3));
  1331. read_size = blob_size/3;
  1332. TEST_ESP_OK( nvs_get_blob(handle, "1a", blob, &read_size));
  1333. TEST_ESP_OK( nvs_get_blob(handle, "1b", blob, &read_size));
  1334. read_size = blob_size /4;
  1335. TEST_ESP_ERR( nvs_get_blob(handle, "1c", blob, &read_size), ESP_ERR_NVS_NOT_FOUND);
  1336. TEST_ESP_ERR( nvs_get_blob(handle, "1d", blob, &read_size), ESP_ERR_NVS_NOT_FOUND);
  1337. read_size = blob_size /2;
  1338. TEST_ESP_OK( nvs_get_blob(handle, "2a", blob, &read_size));
  1339. TEST_ESP_OK( nvs_get_blob(handle, "2b", blob, &read_size));
  1340. TEST_ESP_OK(nvs_commit(handle));
  1341. nvs_close(handle);
  1342. }
  1343. TEST_CASE("Multi-page blobs are supported", "[nvs]")
  1344. {
  1345. const size_t blob_size = Page::CHUNK_MAX_SIZE *2;
  1346. uint8_t blob[blob_size] = {0};
  1347. SpiFlashEmulator emu(5);
  1348. TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 5));
  1349. nvs_handle handle;
  1350. TEST_ESP_OK(nvs_open("test", NVS_READWRITE, &handle));
  1351. TEST_ESP_OK(nvs_set_blob(handle, "abc", blob, blob_size));
  1352. TEST_ESP_OK(nvs_commit(handle));
  1353. nvs_close(handle);
  1354. }
  1355. TEST_CASE("Failures are handled while storing multi-page blobs", "[nvs]")
  1356. {
  1357. const size_t blob_size = Page::CHUNK_MAX_SIZE *7;
  1358. uint8_t blob[blob_size] = {0};
  1359. SpiFlashEmulator emu(5);
  1360. TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 5));
  1361. nvs_handle handle;
  1362. TEST_ESP_OK(nvs_open("test", NVS_READWRITE, &handle));
  1363. TEST_ESP_ERR(nvs_set_blob(handle, "abc", blob, blob_size), ESP_ERR_NVS_VALUE_TOO_LONG);
  1364. TEST_ESP_OK(nvs_set_blob(handle, "abc", blob, Page::CHUNK_MAX_SIZE*2));
  1365. TEST_ESP_OK(nvs_commit(handle));
  1366. nvs_close(handle);
  1367. }
  1368. TEST_CASE("Reading multi-page blobs", "[nvs]")
  1369. {
  1370. const size_t blob_size = Page::CHUNK_MAX_SIZE *3;
  1371. uint8_t blob[blob_size];
  1372. uint8_t blob_read[blob_size];
  1373. size_t read_size = blob_size;
  1374. SpiFlashEmulator emu(5);
  1375. TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 5));
  1376. nvs_handle handle;
  1377. memset(blob, 0x11, blob_size);
  1378. memset(blob_read, 0xee, blob_size);
  1379. TEST_ESP_OK(nvs_open("readTest", NVS_READWRITE, &handle));
  1380. TEST_ESP_OK(nvs_set_blob(handle, "abc", blob, blob_size));
  1381. TEST_ESP_OK(nvs_get_blob(handle, "abc", blob_read, &read_size));
  1382. CHECK(memcmp(blob, blob_read, blob_size) == 0);
  1383. TEST_ESP_OK(nvs_commit(handle));
  1384. nvs_close(handle);
  1385. }
  1386. TEST_CASE("Modification of values for Multi-page blobs are supported", "[nvs]")
  1387. {
  1388. const size_t blob_size = Page::CHUNK_MAX_SIZE *2;
  1389. uint8_t blob[blob_size] = {0};
  1390. uint8_t blob_read[blob_size] = {0xfe};;
  1391. uint8_t blob2[blob_size] = {0x11};
  1392. uint8_t blob3[blob_size] = {0x22};
  1393. uint8_t blob4[blob_size] ={ 0x33};
  1394. size_t read_size = blob_size;
  1395. SpiFlashEmulator emu(6);
  1396. TEST_ESP_OK( nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 6) );
  1397. nvs_handle handle;
  1398. memset(blob, 0x11, blob_size);
  1399. memset(blob2, 0x22, blob_size);
  1400. memset(blob3, 0x33, blob_size);
  1401. memset(blob4, 0x44, blob_size);
  1402. memset(blob_read, 0xff, blob_size);
  1403. TEST_ESP_OK( nvs_open("test", NVS_READWRITE, &handle) );
  1404. TEST_ESP_OK( nvs_set_blob(handle, "abc", blob, blob_size) );
  1405. TEST_ESP_OK( nvs_set_blob(handle, "abc", blob2, blob_size) );
  1406. TEST_ESP_OK( nvs_set_blob(handle, "abc", blob3, blob_size) );
  1407. TEST_ESP_OK( nvs_set_blob(handle, "abc", blob4, blob_size) );
  1408. TEST_ESP_OK( nvs_get_blob(handle, "abc", blob_read, &read_size));
  1409. CHECK(memcmp(blob4, blob_read, blob_size) == 0);
  1410. TEST_ESP_OK( nvs_commit(handle) );
  1411. nvs_close(handle);
  1412. }
  1413. TEST_CASE("Modification from single page blob to multi-page", "[nvs]")
  1414. {
  1415. const size_t blob_size = Page::CHUNK_MAX_SIZE *3;
  1416. uint8_t blob[blob_size] = {0};
  1417. uint8_t blob_read[blob_size] = {0xff};
  1418. size_t read_size = blob_size;
  1419. SpiFlashEmulator emu(5);
  1420. TEST_ESP_OK( nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 5) );
  1421. nvs_handle handle;
  1422. TEST_ESP_OK(nvs_open("Test", NVS_READWRITE, &handle) );
  1423. TEST_ESP_OK(nvs_set_blob(handle, "abc", blob, Page::CHUNK_MAX_SIZE/2));
  1424. TEST_ESP_OK(nvs_set_blob(handle, "abc", blob, blob_size));
  1425. TEST_ESP_OK(nvs_get_blob(handle, "abc", blob_read, &read_size));
  1426. CHECK(memcmp(blob, blob_read, blob_size) == 0);
  1427. TEST_ESP_OK(nvs_commit(handle) );
  1428. nvs_close(handle);
  1429. }
  1430. TEST_CASE("Modification from multi-page to single page", "[nvs]")
  1431. {
  1432. const size_t blob_size = Page::CHUNK_MAX_SIZE *3;
  1433. uint8_t blob[blob_size] = {0};
  1434. uint8_t blob_read[blob_size] = {0xff};
  1435. size_t read_size = blob_size;
  1436. SpiFlashEmulator emu(5);
  1437. TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 5) );
  1438. nvs_handle handle;
  1439. TEST_ESP_OK(nvs_open("Test", NVS_READWRITE, &handle) );
  1440. TEST_ESP_OK(nvs_set_blob(handle, "abc", blob, blob_size));
  1441. TEST_ESP_OK(nvs_set_blob(handle, "abc", blob, Page::CHUNK_MAX_SIZE/2));
  1442. TEST_ESP_OK(nvs_set_blob(handle, "abc2", blob, blob_size));
  1443. TEST_ESP_OK(nvs_get_blob(handle, "abc", blob_read, &read_size));
  1444. CHECK(memcmp(blob, blob_read, Page::CHUNK_MAX_SIZE) == 0);
  1445. TEST_ESP_OK(nvs_commit(handle) );
  1446. nvs_close(handle);
  1447. }
  1448. TEST_CASE("Check that orphaned blobs are erased during init", "[nvs]")
  1449. {
  1450. const size_t blob_size = Page::CHUNK_MAX_SIZE *3 ;
  1451. uint8_t blob[blob_size] = {0x11};
  1452. uint8_t blob2[blob_size] = {0x22};
  1453. uint8_t blob3[blob_size] = {0x33};
  1454. SpiFlashEmulator emu(5);
  1455. Storage storage;
  1456. TEST_ESP_OK(storage.init(0, 5));
  1457. TEST_ESP_OK(storage.writeItem(1, ItemType::BLOB, "key", blob, sizeof(blob)));
  1458. TEST_ESP_OK(storage.init(0, 5));
  1459. /* Check that multi-page item is still available.**/
  1460. TEST_ESP_OK(storage.readItem(1, ItemType::BLOB, "key", blob, sizeof(blob)));
  1461. TEST_ESP_ERR(storage.writeItem(1, ItemType::BLOB, "key2", blob, sizeof(blob)), ESP_ERR_NVS_NOT_ENOUGH_SPACE);
  1462. Page p;
  1463. p.load(3); // This is where index will be placed.
  1464. p.erase();
  1465. TEST_ESP_OK(storage.init(0, 5));
  1466. TEST_ESP_ERR(storage.readItem(1, ItemType::BLOB, "key", blob, sizeof(blob)), ESP_ERR_NVS_NOT_FOUND);
  1467. TEST_ESP_OK(storage.writeItem(1, ItemType::BLOB, "key3", blob, sizeof(blob)));
  1468. }
  1469. TEST_CASE("nvs code handles errors properly when partition is near to full", "[nvs]")
  1470. {
  1471. const size_t blob_size = Page::CHUNK_MAX_SIZE * 0.3 ;
  1472. uint8_t blob[blob_size] = {0x11};
  1473. SpiFlashEmulator emu(5);
  1474. Storage storage;
  1475. char nvs_key[16] = "";
  1476. TEST_ESP_OK(storage.init(0, 5));
  1477. /* Four pages should fit roughly 12 blobs*/
  1478. for(uint8_t count = 1; count <= 12; count++) {
  1479. sprintf(nvs_key, "key:%u", count);
  1480. TEST_ESP_OK(storage.writeItem(1, ItemType::BLOB, nvs_key, blob, sizeof(blob)));
  1481. }
  1482. for(uint8_t count = 13; count <= 20; count++) {
  1483. sprintf(nvs_key, "key:%u", count);
  1484. TEST_ESP_ERR(storage.writeItem(1, ItemType::BLOB, nvs_key, blob, sizeof(blob)), ESP_ERR_NVS_NOT_ENOUGH_SPACE);
  1485. }
  1486. }
  1487. TEST_CASE("Check for nvs version incompatibility", "[nvs]")
  1488. {
  1489. SpiFlashEmulator emu(3);
  1490. int32_t val1 = 0x12345678;
  1491. Page p;
  1492. p.load(0);
  1493. TEST_ESP_OK(p.setVersion(Page::NVS_VERSION - 1));
  1494. TEST_ESP_OK(p.writeItem(1, ItemType::I32, "foo", &val1, sizeof(val1)));
  1495. TEST_ESP_ERR(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 3), ESP_ERR_NVS_NEW_VERSION_FOUND);
  1496. }
  1497. TEST_CASE("Check that NVS supports old blob format without blob index", "[nvs]")
  1498. {
  1499. SpiFlashEmulator emu("../nvs_partition_generator/part_old_blob_format.bin");
  1500. nvs_handle handle;
  1501. TEST_ESP_OK( nvs_flash_init_custom("test", 0, 2) );
  1502. TEST_ESP_OK( nvs_open_from_partition("test", "dummyNamespace", NVS_READONLY, &handle));
  1503. char buf[64] = {0};
  1504. size_t buflen = 64;
  1505. uint8_t hexdata[] = {0x01, 0x02, 0x03, 0xab, 0xcd, 0xef};
  1506. TEST_ESP_OK( nvs_get_blob(handle, "dummyHex2BinKey", buf, &buflen));
  1507. CHECK(memcmp(buf, hexdata, buflen) == 0);
  1508. buflen = 64;
  1509. uint8_t base64data[] = {'1', '2', '3', 'a', 'b', 'c'};
  1510. TEST_ESP_OK( nvs_get_blob(handle, "dummyBase64Key", buf, &buflen));
  1511. CHECK(memcmp(buf, base64data, buflen) == 0);
  1512. Page p;
  1513. p.load(0);
  1514. /* Check that item is stored in old format without blob index*/
  1515. TEST_ESP_OK(p.findItem(1, ItemType::BLOB, "dummyHex2BinKey"));
  1516. /* Modify the blob so that it is stored in the new format*/
  1517. hexdata[0] = hexdata[1] = hexdata[2] = 0x99;
  1518. TEST_ESP_OK(nvs_set_blob(handle, "dummyHex2BinKey", hexdata, sizeof(hexdata)));
  1519. Page p2;
  1520. p2.load(0);
  1521. /* Check the type of the blob. Expect type mismatch since the blob is stored in new format*/
  1522. TEST_ESP_ERR(p2.findItem(1, ItemType::BLOB, "dummyHex2BinKey"), ESP_ERR_NVS_TYPE_MISMATCH);
  1523. /* Check that index is present for the modified blob according to new format*/
  1524. TEST_ESP_OK(p2.findItem(1, ItemType::BLOB_IDX, "dummyHex2BinKey"));
  1525. /* Read the blob in new format and check the contents*/
  1526. buflen = 64;
  1527. TEST_ESP_OK( nvs_get_blob(handle, "dummyBase64Key", buf, &buflen));
  1528. CHECK(memcmp(buf, base64data, buflen) == 0);
  1529. }
  1530. TEST_CASE("monkey test with old-format blob present", "[nvs][monkey]")
  1531. {
  1532. std::random_device rd;
  1533. std::mt19937 gen(rd());
  1534. uint32_t seed = 3;
  1535. gen.seed(seed);
  1536. SpiFlashEmulator emu(10);
  1537. emu.randomize(seed);
  1538. emu.clearStats();
  1539. const uint32_t NVS_FLASH_SECTOR = 2;
  1540. const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 8;
  1541. static const size_t smallBlobLen = Page::CHUNK_MAX_SIZE / 3;
  1542. emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
  1543. TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  1544. nvs_handle handle;
  1545. TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle));
  1546. RandomTest test;
  1547. for ( uint8_t it = 0; it < 10; it++) {
  1548. size_t count = 200;
  1549. /* Erase index and chunks for the blob with "singlepage" key */
  1550. for (uint8_t num = NVS_FLASH_SECTOR; num < NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN; num++) {
  1551. Page p;
  1552. p.load(num);
  1553. p.eraseItem(1, ItemType::BLOB, "singlepage", Item::CHUNK_ANY, VerOffset::VER_ANY);
  1554. p.eraseItem(1, ItemType::BLOB_IDX, "singlepage", Item::CHUNK_ANY, VerOffset::VER_ANY);
  1555. p.eraseItem(1, ItemType::BLOB_DATA, "singlepage", Item::CHUNK_ANY, VerOffset::VER_ANY);
  1556. }
  1557. /* Now write "singlepage" blob in old format*/
  1558. for (uint8_t num = NVS_FLASH_SECTOR; num < NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN; num++) {
  1559. Page p;
  1560. p.load(num);
  1561. if (p.state() == Page::PageState::ACTIVE) {
  1562. uint8_t buf[smallBlobLen];
  1563. size_t blobLen = gen() % smallBlobLen;
  1564. if(blobLen > p.getVarDataTailroom()) {
  1565. blobLen = p.getVarDataTailroom();
  1566. }
  1567. std::generate_n(buf, blobLen, [&]() -> uint8_t {
  1568. return static_cast<uint8_t>(gen() % 256);
  1569. });
  1570. TEST_ESP_OK(p.writeItem(1, ItemType::BLOB, "singlepage", buf, blobLen, Item::CHUNK_ANY));
  1571. TEST_ESP_OK(p.findItem(1, ItemType::BLOB, "singlepage"));
  1572. test.handleExternalWriteAtIndex(9, buf, blobLen); // This assumes "singlepage" is always at index 9
  1573. break;
  1574. }
  1575. }
  1576. /* Initialize again */
  1577. TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  1578. TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle));
  1579. /* Perform random things */
  1580. auto res = test.doRandomThings(handle, gen, count);
  1581. if (res != ESP_OK) {
  1582. nvs_dump(NVS_DEFAULT_PART_NAME);
  1583. CHECK(0);
  1584. }
  1585. /* Check that only one version is present for "singlepage". Its possible that last iteration did not write
  1586. * anything for "singlepage". So either old version or new version should be present.*/
  1587. bool oldVerPresent = false, newVerPresent = false;
  1588. for (uint8_t num = NVS_FLASH_SECTOR; num < NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN; num++) {
  1589. Page p;
  1590. p.load(num);
  1591. if(!oldVerPresent && p.findItem(1, ItemType::BLOB, "singlepage", Item::CHUNK_ANY, VerOffset::VER_ANY) == ESP_OK) {
  1592. oldVerPresent = true;
  1593. }
  1594. if(!newVerPresent && p.findItem(1, ItemType::BLOB_IDX, "singlepage", Item::CHUNK_ANY, VerOffset::VER_ANY) == ESP_OK) {
  1595. newVerPresent = true;
  1596. }
  1597. }
  1598. CHECK(oldVerPresent != newVerPresent);
  1599. }
  1600. s_perf << "Monkey test: nErase=" << emu.getEraseOps() << " nWrite=" << emu.getWriteOps() << std::endl;
  1601. }
  1602. TEST_CASE("Recovery from power-off during modification of blob present in old-format (same page)", "[nvs]")
  1603. {
  1604. std::random_device rd;
  1605. std::mt19937 gen(rd());
  1606. uint32_t seed = 3;
  1607. gen.seed(seed);
  1608. SpiFlashEmulator emu(3);
  1609. emu.clearStats();
  1610. TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 3));
  1611. nvs_handle handle;
  1612. TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle));
  1613. uint8_t hexdata[] = {0x01, 0x02, 0x03, 0xab, 0xcd, 0xef};
  1614. uint8_t hexdata_old[] = {0x11, 0x12, 0x13, 0xbb, 0xcc, 0xee};
  1615. size_t buflen = sizeof(hexdata);
  1616. uint8_t buf[Page::CHUNK_MAX_SIZE];
  1617. /* Power-off when blob was being written on the same page where its old version in old format
  1618. * was present*/
  1619. Page p;
  1620. p.load(0);
  1621. /* Write blob in old-format*/
  1622. TEST_ESP_OK(p.writeItem(1, ItemType::BLOB, "singlepage", hexdata_old, sizeof(hexdata_old)));
  1623. /* Write blob in new format*/
  1624. TEST_ESP_OK(p.writeItem(1, ItemType::BLOB_DATA, "singlepage", hexdata, sizeof(hexdata), 0));
  1625. /* All pages are stored. Now store the index.*/
  1626. Item item;
  1627. item.blobIndex.dataSize = sizeof(hexdata);
  1628. item.blobIndex.chunkCount = 1;
  1629. item.blobIndex.chunkStart = VerOffset::VER_0_OFFSET;
  1630. TEST_ESP_OK(p.writeItem(1, ItemType::BLOB_IDX, "singlepage", item.data, sizeof(item.data)));
  1631. TEST_ESP_OK(p.findItem(1, ItemType::BLOB, "singlepage"));
  1632. /* Initialize again */
  1633. TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 3));
  1634. TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle));
  1635. TEST_ESP_OK( nvs_get_blob(handle, "singlepage", buf, &buflen));
  1636. CHECK(memcmp(buf, hexdata, buflen) == 0);
  1637. Page p2;
  1638. p2.load(0);
  1639. TEST_ESP_ERR(p2.findItem(1, ItemType::BLOB, "singlepage"), ESP_ERR_NVS_TYPE_MISMATCH);
  1640. }
  1641. TEST_CASE("Recovery from power-off during modification of blob present in old-format (different page)", "[nvs]")
  1642. {
  1643. std::random_device rd;
  1644. std::mt19937 gen(rd());
  1645. uint32_t seed = 3;
  1646. gen.seed(seed);
  1647. SpiFlashEmulator emu(3);
  1648. emu.clearStats();
  1649. TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 3));
  1650. nvs_handle handle;
  1651. TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle));
  1652. uint8_t hexdata[] = {0x01, 0x02, 0x03, 0xab, 0xcd, 0xef};
  1653. uint8_t hexdata_old[] = {0x11, 0x12, 0x13, 0xbb, 0xcc, 0xee};
  1654. size_t buflen = sizeof(hexdata);
  1655. uint8_t buf[Page::CHUNK_MAX_SIZE];
  1656. /* Power-off when blob was being written on the different page where its old version in old format
  1657. * was present*/
  1658. Page p;
  1659. p.load(0);
  1660. /* Write blob in old-format*/
  1661. TEST_ESP_OK(p.writeItem(1, ItemType::BLOB, "singlepage", hexdata_old, sizeof(hexdata_old)));
  1662. /* Write blob in new format*/
  1663. TEST_ESP_OK(p.writeItem(1, ItemType::BLOB_DATA, "singlepage", hexdata, sizeof(hexdata), 0));
  1664. /* All pages are stored. Now store the index.*/
  1665. Item item;
  1666. item.blobIndex.dataSize = sizeof(hexdata);
  1667. item.blobIndex.chunkCount = 1;
  1668. item.blobIndex.chunkStart = VerOffset::VER_0_OFFSET;
  1669. p.markFull();
  1670. Page p2;
  1671. p2.load(1);
  1672. p2.setSeqNumber(1);
  1673. TEST_ESP_OK(p2.writeItem(1, ItemType::BLOB_IDX, "singlepage", item.data, sizeof(item.data)));
  1674. TEST_ESP_OK(p.findItem(1, ItemType::BLOB, "singlepage"));
  1675. /* Initialize again */
  1676. TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 3));
  1677. TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle));
  1678. TEST_ESP_OK( nvs_get_blob(handle, "singlepage", buf, &buflen));
  1679. CHECK(memcmp(buf, hexdata, buflen) == 0);
  1680. Page p3;
  1681. p3.load(0);
  1682. TEST_ESP_ERR(p3.findItem(1, ItemType::BLOB, "singlepage"), ESP_ERR_NVS_NOT_FOUND);
  1683. }
  1684. /* Add new tests above */
  1685. /* This test has to be the final one */
  1686. TEST_CASE("check partition generation utility", "[nvs_part_gen]")
  1687. {
  1688. int childpid = fork();
  1689. if (childpid == 0) {
  1690. exit(execlp("python", "python",
  1691. "../nvs_partition_generator/nvs_partition_gen.py",
  1692. "../nvs_partition_generator/sample.csv",
  1693. "../nvs_partition_generator/partition.bin",
  1694. "12KB",NULL));
  1695. } else {
  1696. CHECK(childpid > 0);
  1697. int status;
  1698. waitpid(childpid, &status, 0);
  1699. CHECK(WEXITSTATUS(status) != -1);
  1700. }
  1701. }
  1702. TEST_CASE("read data from partition generated via partition generation utility", "[nvs_part_gen]")
  1703. {
  1704. SpiFlashEmulator emu("../nvs_partition_generator/partition.bin");
  1705. nvs_handle handle;
  1706. TEST_ESP_OK( nvs_flash_init_custom("test", 0, 3) );
  1707. TEST_ESP_OK( nvs_open_from_partition("test", "dummyNamespace", NVS_READONLY, &handle));
  1708. uint8_t u8v;
  1709. TEST_ESP_OK( nvs_get_u8(handle, "dummyU8Key", &u8v));
  1710. CHECK(u8v == 127);
  1711. int8_t i8v;
  1712. TEST_ESP_OK( nvs_get_i8(handle, "dummyI8Key", &i8v));
  1713. CHECK(i8v == -128);
  1714. uint16_t u16v;
  1715. TEST_ESP_OK( nvs_get_u16(handle, "dummyU16Key", &u16v));
  1716. CHECK(u16v == 32768);
  1717. uint32_t u32v;
  1718. TEST_ESP_OK( nvs_get_u32(handle, "dummyU32Key", &u32v));
  1719. CHECK(u32v == 4294967295);
  1720. int32_t i32v;
  1721. TEST_ESP_OK( nvs_get_i32(handle, "dummyI32Key", &i32v));
  1722. CHECK(i32v == -2147483648);
  1723. char buf[64] = {0};
  1724. size_t buflen = 64;
  1725. TEST_ESP_OK( nvs_get_str(handle, "dummyStringKey", buf, &buflen));
  1726. CHECK(strncmp(buf, "0A:0B:0C:0D:0E:0F", buflen) == 0);
  1727. uint8_t hexdata[] = {0x01, 0x02, 0x03, 0xab, 0xcd, 0xef};
  1728. buflen = 64;
  1729. int j;
  1730. TEST_ESP_OK( nvs_get_blob(handle, "dummyHex2BinKey", buf, &buflen));
  1731. CHECK(memcmp(buf, hexdata, buflen) == 0);
  1732. uint8_t base64data[] = {'1', '2', '3', 'a', 'b', 'c'};
  1733. TEST_ESP_OK( nvs_get_blob(handle, "dummyBase64Key", buf, &buflen));
  1734. CHECK(memcmp(buf, base64data, buflen) == 0);
  1735. buflen = 64;
  1736. uint8_t hexfiledata[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
  1737. TEST_ESP_OK( nvs_get_blob(handle, "hexFileKey", buf, &buflen));
  1738. CHECK(memcmp(buf, hexfiledata, buflen) == 0);
  1739. buflen = 64;
  1740. uint8_t strfiledata[64] = "abcdefghijklmnopqrstuvwxyz\0";
  1741. TEST_ESP_OK( nvs_get_str(handle, "stringFileKey", buf, &buflen));
  1742. CHECK(memcmp(buf, strfiledata, buflen) == 0);
  1743. char bin_data[5200];
  1744. size_t bin_len = sizeof(bin_data);
  1745. char binfiledata[5200];
  1746. ifstream file;
  1747. file.open("../nvs_partition_generator/testdata/sample.bin");
  1748. file.read(binfiledata,5200);
  1749. TEST_ESP_OK( nvs_get_blob(handle, "binFileKey", bin_data, &bin_len));
  1750. CHECK(memcmp(bin_data, binfiledata, bin_len) == 0);
  1751. file.close();
  1752. }
  1753. TEST_CASE("dump all performance data", "[nvs]")
  1754. {
  1755. std::cout << "====================" << std::endl << "Dumping benchmarks" << std::endl;
  1756. std::cout << s_perf.str() << std::endl;
  1757. std::cout << "====================" << std::endl;
  1758. }