test_nvs.cpp 87 KB

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