test_nvs.cpp 85 KB

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