test_nvs.cpp 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254
  1. // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. // http://www.apache.org/licenses/LICENSE-2.0
  7. //
  8. // Unless required by applicable law or agreed to in writing, software
  9. // distributed under the License is distributed on an "AS IS" BASIS,
  10. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. #include "catch.hpp"
  14. #include "nvs.hpp"
  15. #include "nvs_test_api.h"
  16. #include "spi_flash_emulation.h"
  17. #include <sstream>
  18. #include <iostream>
  19. #define TEST_ESP_ERR(rc, res) CHECK((rc) == (res))
  20. #define TEST_ESP_OK(rc) CHECK((rc) == ESP_OK)
  21. using namespace std;
  22. using namespace nvs;
  23. stringstream s_perf;
  24. void dumpBytes(const uint8_t* data, size_t count)
  25. {
  26. for (uint32_t i = 0; i < count; ++i) {
  27. if (i % 32 == 0) {
  28. printf("%08x ", i);
  29. }
  30. printf("%02x ", data[i]);
  31. if ((i + 1) % 32 == 0) {
  32. printf("\n");
  33. }
  34. }
  35. }
  36. TEST_CASE("crc32 behaves as expected", "[nvs]")
  37. {
  38. Item item1;
  39. item1.datatype = ItemType::I32;
  40. item1.nsIndex = 1;
  41. item1.crc32 = 0;
  42. item1.reserved = 0xff;
  43. fill_n(item1.key, sizeof(item1.key), 0xbb);
  44. fill_n(item1.data, sizeof(item1.data), 0xaa);
  45. auto crc32_1 = item1.calculateCrc32();
  46. Item item2 = item1;
  47. item2.crc32 = crc32_1;
  48. CHECK(crc32_1 == item2.calculateCrc32());
  49. item2 = item1;
  50. item2.nsIndex = 2;
  51. CHECK(crc32_1 != item2.calculateCrc32());
  52. item2 = item1;
  53. item2.datatype = ItemType::U32;
  54. CHECK(crc32_1 != item2.calculateCrc32());
  55. item2 = item1;
  56. strncpy(item2.key, "foo", Item::MAX_KEY_LENGTH);
  57. CHECK(crc32_1 != item2.calculateCrc32());
  58. }
  59. TEST_CASE("starting with empty flash, page is in uninitialized state", "[nvs]")
  60. {
  61. SpiFlashEmulator emu(1);
  62. Page page;
  63. CHECK(page.state() == Page::PageState::INVALID);
  64. CHECK(page.load(0) == ESP_OK);
  65. CHECK(page.state() == Page::PageState::UNINITIALIZED);
  66. }
  67. TEST_CASE("can distinguish namespaces", "[nvs]")
  68. {
  69. SpiFlashEmulator emu(1);
  70. Page page;
  71. CHECK(page.load(0) == ESP_OK);
  72. int32_t val1 = 0x12345678;
  73. CHECK(page.writeItem(1, ItemType::I32, "intval1", &val1, sizeof(val1)) == ESP_OK);
  74. int32_t val2 = 0x23456789;
  75. CHECK(page.writeItem(2, ItemType::I32, "intval1", &val2, sizeof(val2)) == ESP_OK);
  76. int32_t readVal;
  77. CHECK(page.readItem(2, ItemType::I32, "intval1", &readVal, sizeof(readVal)) == ESP_OK);
  78. CHECK(readVal == val2);
  79. }
  80. TEST_CASE("reading with different type causes type mismatch error", "[nvs]")
  81. {
  82. SpiFlashEmulator emu(1);
  83. Page page;
  84. CHECK(page.load(0) == ESP_OK);
  85. int32_t val = 0x12345678;
  86. CHECK(page.writeItem(1, ItemType::I32, "intval1", &val, sizeof(val)) == ESP_OK);
  87. CHECK(page.readItem(1, ItemType::U32, "intval1", &val, sizeof(val)) == ESP_ERR_NVS_TYPE_MISMATCH);
  88. }
  89. TEST_CASE("when page is erased, it's state becomes UNITIALIZED", "[nvs]")
  90. {
  91. SpiFlashEmulator emu(1);
  92. Page page;
  93. CHECK(page.load(0) == ESP_OK);
  94. int32_t val = 0x12345678;
  95. CHECK(page.writeItem(1, ItemType::I32, "intval1", &val, sizeof(val)) == ESP_OK);
  96. CHECK(page.erase() == ESP_OK);
  97. CHECK(page.state() == Page::PageState::UNINITIALIZED);
  98. }
  99. TEST_CASE("when writing and erasing, used/erased counts are updated correctly", "[nvs]")
  100. {
  101. SpiFlashEmulator emu(1);
  102. Page page;
  103. CHECK(page.load(0) == ESP_OK);
  104. CHECK(page.getUsedEntryCount() == 0);
  105. CHECK(page.getErasedEntryCount() == 0);
  106. uint32_t foo1 = 0;
  107. CHECK(page.writeItem(1, "foo1", foo1) == ESP_OK);
  108. CHECK(page.getUsedEntryCount() == 1);
  109. CHECK(page.writeItem(2, "foo1", foo1) == ESP_OK);
  110. CHECK(page.getUsedEntryCount() == 2);
  111. CHECK(page.eraseItem<uint32_t>(2, "foo1") == ESP_OK);
  112. CHECK(page.getUsedEntryCount() == 1);
  113. CHECK(page.getErasedEntryCount() == 1);
  114. for (size_t i = 0; i < Page::ENTRY_COUNT - 2; ++i) {
  115. char name[16];
  116. snprintf(name, sizeof(name), "i%ld", i);
  117. CHECK(page.writeItem(1, name, i) == ESP_OK);
  118. }
  119. CHECK(page.getUsedEntryCount() == Page::ENTRY_COUNT - 1);
  120. CHECK(page.getErasedEntryCount() == 1);
  121. for (size_t i = 0; i < Page::ENTRY_COUNT - 2; ++i) {
  122. char name[16];
  123. snprintf(name, sizeof(name), "i%ld", i);
  124. CHECK(page.eraseItem(1, itemTypeOf<size_t>(), name) == ESP_OK);
  125. }
  126. CHECK(page.getUsedEntryCount() == 1);
  127. CHECK(page.getErasedEntryCount() == Page::ENTRY_COUNT - 1);
  128. }
  129. TEST_CASE("when page is full, adding an element fails", "[nvs]")
  130. {
  131. SpiFlashEmulator emu(1);
  132. Page page;
  133. CHECK(page.load(0) == ESP_OK);
  134. for (size_t i = 0; i < Page::ENTRY_COUNT; ++i) {
  135. char name[16];
  136. snprintf(name, sizeof(name), "i%ld", i);
  137. CHECK(page.writeItem(1, name, i) == ESP_OK);
  138. }
  139. CHECK(page.writeItem(1, "foo", 64UL) == ESP_ERR_NVS_PAGE_FULL);
  140. }
  141. TEST_CASE("page maintains its seq number")
  142. {
  143. SpiFlashEmulator emu(1);
  144. {
  145. Page page;
  146. CHECK(page.load(0) == ESP_OK);
  147. CHECK(page.setSeqNumber(123) == ESP_OK);
  148. int32_t val = 42;
  149. CHECK(page.writeItem(1, ItemType::I32, "dummy", &val, sizeof(val)) == ESP_OK);
  150. }
  151. {
  152. Page page;
  153. CHECK(page.load(0) == ESP_OK);
  154. uint32_t seqno;
  155. CHECK(page.getSeqNumber(seqno) == ESP_OK);
  156. CHECK(seqno == 123);
  157. }
  158. }
  159. TEST_CASE("can write and read variable length data", "[nvs]")
  160. {
  161. SpiFlashEmulator emu(1);
  162. Page page;
  163. CHECK(page.load(0) == ESP_OK);
  164. const char str[] = "foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234";
  165. size_t len = strlen(str);
  166. CHECK(page.writeItem(1, "stuff1", 42) == ESP_OK);
  167. CHECK(page.writeItem(1, "stuff2", 1) == ESP_OK);
  168. CHECK(page.writeItem(1, ItemType::SZ, "foobaar", str, len + 1) == ESP_OK);
  169. CHECK(page.writeItem(1, "stuff3", 2) == ESP_OK);
  170. CHECK(page.writeItem(1, ItemType::BLOB, "baz", str, len) == ESP_OK);
  171. CHECK(page.writeItem(1, "stuff4", 0x7abbccdd) == ESP_OK);
  172. char buf[sizeof(str) + 16];
  173. int32_t value;
  174. CHECK(page.readItem(1, "stuff1", value) == ESP_OK);
  175. CHECK(value == 42);
  176. CHECK(page.readItem(1, "stuff2", value) == ESP_OK);
  177. CHECK(value == 1);
  178. CHECK(page.readItem(1, "stuff3", value) == ESP_OK);
  179. CHECK(value == 2);
  180. CHECK(page.readItem(1, "stuff4", value) == ESP_OK);
  181. CHECK(value == 0x7abbccdd);
  182. fill_n(buf, sizeof(buf), 0xff);
  183. CHECK(page.readItem(1, ItemType::SZ, "foobaar", buf, sizeof(buf)) == ESP_OK);
  184. CHECK(memcmp(buf, str, strlen(str) + 1) == 0);
  185. fill_n(buf, sizeof(buf), 0xff);
  186. CHECK(page.readItem(1, ItemType::BLOB, "baz", buf, sizeof(buf)) == ESP_OK);
  187. CHECK(memcmp(buf, str, strlen(str)) == 0);
  188. }
  189. TEST_CASE("different key names are distinguished even if the pointer is the same", "[nvs]")
  190. {
  191. SpiFlashEmulator emu(1);
  192. Page page;
  193. TEST_ESP_OK(page.load(0));
  194. TEST_ESP_OK(page.writeItem(1, "i1", 1));
  195. TEST_ESP_OK(page.writeItem(1, "i2", 2));
  196. int32_t value;
  197. char keyname[10] = {0};
  198. for (int i = 0; i < 2; ++i) {
  199. strncpy(keyname, "i1", sizeof(keyname) - 1);
  200. TEST_ESP_OK(page.readItem(1, keyname, value));
  201. CHECK(value == 1);
  202. strncpy(keyname, "i2", sizeof(keyname) - 1);
  203. TEST_ESP_OK(page.readItem(1, keyname, value));
  204. CHECK(value == 2);
  205. }
  206. }
  207. TEST_CASE("Page validates key size", "[nvs]")
  208. {
  209. SpiFlashEmulator emu(4);
  210. Page page;
  211. TEST_ESP_OK(page.load(0));
  212. // 16-character key fails
  213. TEST_ESP_ERR(page.writeItem(1, "0123456789123456", 1), ESP_ERR_NVS_KEY_TOO_LONG);
  214. // 15-character key is okay
  215. TEST_ESP_OK(page.writeItem(1, "012345678912345", 1));
  216. }
  217. TEST_CASE("Page validates blob size", "[nvs]")
  218. {
  219. SpiFlashEmulator emu(4);
  220. Page page;
  221. TEST_ESP_OK(page.load(0));
  222. char buf[2048] = { 0 };
  223. // There are two potential errors here:
  224. // - not enough space in the page (because one value has been written already)
  225. // - value is too long
  226. // Check that the second one is actually returned.
  227. TEST_ESP_ERR(page.writeItem(1, ItemType::BLOB, "2", buf, Page::ENTRY_COUNT * Page::ENTRY_SIZE), ESP_ERR_NVS_VALUE_TOO_LONG);
  228. // Should fail as well
  229. TEST_ESP_ERR(page.writeItem(1, ItemType::BLOB, "2", buf, Page::BLOB_MAX_SIZE + 1), ESP_ERR_NVS_VALUE_TOO_LONG);
  230. TEST_ESP_OK(page.writeItem(1, ItemType::BLOB, "2", buf, Page::BLOB_MAX_SIZE));
  231. }
  232. TEST_CASE("can init PageManager in empty flash", "[nvs]")
  233. {
  234. SpiFlashEmulator emu(4);
  235. PageManager pm;
  236. CHECK(pm.load(0, 4) == ESP_OK);
  237. }
  238. TEST_CASE("PageManager adds page in the correct order", "[nvs]")
  239. {
  240. const size_t pageCount = 8;
  241. SpiFlashEmulator emu(pageCount);
  242. uint32_t pageNo[pageCount] = { -1U, 50, 11, -1U, 23, 22, 24, 49};
  243. for (uint32_t i = 0; i < pageCount; ++i) {
  244. Page p;
  245. p.load(i);
  246. if (pageNo[i] != -1U) {
  247. p.setSeqNumber(pageNo[i]);
  248. p.writeItem(1, "foo", 10U);
  249. }
  250. }
  251. PageManager pageManager;
  252. CHECK(pageManager.load(0, pageCount) == ESP_OK);
  253. uint32_t lastSeqNo = 0;
  254. for (auto it = std::begin(pageManager); it != std::end(pageManager); ++it) {
  255. uint32_t seqNo;
  256. CHECK(it->getSeqNumber(seqNo) == ESP_OK);
  257. CHECK(seqNo > lastSeqNo);
  258. }
  259. }
  260. TEST_CASE("can init storage in empty flash", "[nvs]")
  261. {
  262. SpiFlashEmulator emu(8);
  263. Storage storage;
  264. emu.setBounds(4, 8);
  265. CHECK(storage.init(4, 4) == ESP_OK);
  266. s_perf << "Time to init empty storage (4 sectors): " << emu.getTotalTime() << " us" << std::endl;
  267. }
  268. TEST_CASE("storage doesn't add duplicates within one page", "[nvs]")
  269. {
  270. SpiFlashEmulator emu(8);
  271. Storage storage;
  272. emu.setBounds(4, 8);
  273. CHECK(storage.init(4, 4) == ESP_OK);
  274. int bar = 0;
  275. CHECK(storage.writeItem(1, "bar", bar) == ESP_OK);
  276. CHECK(storage.writeItem(1, "bar", bar) == ESP_OK);
  277. Page page;
  278. page.load(4);
  279. CHECK(page.getUsedEntryCount() == 1);
  280. CHECK(page.getErasedEntryCount() == 1);
  281. }
  282. TEST_CASE("can write one item a thousand times", "[nvs]")
  283. {
  284. SpiFlashEmulator emu(8);
  285. Storage storage;
  286. emu.setBounds(4, 8);
  287. CHECK(storage.init(4, 4) == ESP_OK);
  288. for (size_t i = 0; i < Page::ENTRY_COUNT * 4 * 2; ++i) {
  289. REQUIRE(storage.writeItem(1, "i", static_cast<int>(i)) == ESP_OK);
  290. }
  291. 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;
  292. }
  293. TEST_CASE("storage doesn't add duplicates within multiple pages", "[nvs]")
  294. {
  295. SpiFlashEmulator emu(8);
  296. Storage storage;
  297. emu.setBounds(4, 8);
  298. CHECK(storage.init(4, 4) == ESP_OK);
  299. int bar = 0;
  300. CHECK(storage.writeItem(1, "bar", bar) == ESP_OK);
  301. for (size_t i = 0; i < Page::ENTRY_COUNT; ++i) {
  302. CHECK(storage.writeItem(1, "foo", static_cast<int>(bar)) == ESP_OK);
  303. }
  304. CHECK(storage.writeItem(1, "bar", bar) == ESP_OK);
  305. Page page;
  306. page.load(4);
  307. CHECK(page.findItem(1, itemTypeOf<int>(), "bar") == ESP_ERR_NVS_NOT_FOUND);
  308. page.load(5);
  309. CHECK(page.findItem(1, itemTypeOf<int>(), "bar") == ESP_OK);
  310. }
  311. TEST_CASE("storage can find items on second page if first is not fully written and has cached search data", "[nvs]")
  312. {
  313. SpiFlashEmulator emu(3);
  314. Storage storage;
  315. CHECK(storage.init(0, 3) == ESP_OK);
  316. int bar = 0;
  317. uint8_t bigdata[Page::BLOB_MAX_SIZE] = {0};
  318. // write one big chunk of data
  319. ESP_ERROR_CHECK(storage.writeItem(0, ItemType::BLOB, "1", bigdata, sizeof(bigdata)));
  320. // write another big chunk of data
  321. ESP_ERROR_CHECK(storage.writeItem(0, ItemType::BLOB, "2", bigdata, sizeof(bigdata)));
  322. // write third one; it will not fit into the first page
  323. ESP_ERROR_CHECK(storage.writeItem(0, ItemType::BLOB, "3", bigdata, sizeof(bigdata)));
  324. size_t size;
  325. ESP_ERROR_CHECK(storage.getItemDataSize(0, ItemType::BLOB, "1", size));
  326. CHECK(size == sizeof(bigdata));
  327. ESP_ERROR_CHECK(storage.getItemDataSize(0, ItemType::BLOB, "3", size));
  328. CHECK(size == sizeof(bigdata));
  329. }
  330. TEST_CASE("can write and read variable length data lots of times", "[nvs]")
  331. {
  332. SpiFlashEmulator emu(8);
  333. Storage storage;
  334. emu.setBounds(4, 8);
  335. CHECK(storage.init(4, 4) == ESP_OK);
  336. const char str[] = "foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234";
  337. char buf[sizeof(str) + 16];
  338. size_t len = strlen(str);
  339. for (size_t i = 0; i < Page::ENTRY_COUNT * 4 * 2; ++i) {
  340. CAPTURE(i);
  341. CHECK(storage.writeItem(1, ItemType::SZ, "foobaar", str, len + 1) == ESP_OK);
  342. CHECK(storage.writeItem(1, "foo", static_cast<uint32_t>(i)) == ESP_OK);
  343. uint32_t value;
  344. CHECK(storage.readItem(1, "foo", value) == ESP_OK);
  345. CHECK(value == i);
  346. fill_n(buf, sizeof(buf), 0xff);
  347. CHECK(storage.readItem(1, ItemType::SZ, "foobaar", buf, sizeof(buf)) == ESP_OK);
  348. CHECK(memcmp(buf, str, strlen(str) + 1) == 0);
  349. }
  350. 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;
  351. }
  352. TEST_CASE("can get length of variable length data", "[nvs]")
  353. {
  354. SpiFlashEmulator emu(8);
  355. emu.randomize(200);
  356. Storage storage;
  357. emu.setBounds(4, 8);
  358. CHECK(storage.init(4, 4) == ESP_OK);
  359. const char str[] = "foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234foobar1234";
  360. size_t len = strlen(str);
  361. CHECK(storage.writeItem(1, ItemType::SZ, "foobaar", str, len + 1) == ESP_OK);
  362. size_t dataSize;
  363. CHECK(storage.getItemDataSize(1, ItemType::SZ, "foobaar", dataSize) == ESP_OK);
  364. CHECK(dataSize == len + 1);
  365. CHECK(storage.writeItem(2, ItemType::BLOB, "foobaar", str, len) == ESP_OK);
  366. CHECK(storage.getItemDataSize(2, ItemType::BLOB, "foobaar", dataSize) == ESP_OK);
  367. CHECK(dataSize == len);
  368. }
  369. TEST_CASE("can create namespaces", "[nvs]")
  370. {
  371. SpiFlashEmulator emu(8);
  372. Storage storage;
  373. emu.setBounds(4, 8);
  374. CHECK(storage.init(4, 4) == ESP_OK);
  375. uint8_t nsi;
  376. CHECK(storage.createOrOpenNamespace("wifi", false, nsi) == ESP_ERR_NVS_NOT_FOUND);
  377. CHECK(storage.createOrOpenNamespace("wifi", true, nsi) == ESP_OK);
  378. Page page;
  379. page.load(4);
  380. CHECK(page.findItem(Page::NS_INDEX, ItemType::U8, "wifi") == ESP_OK);
  381. }
  382. TEST_CASE("storage may become full", "[nvs]")
  383. {
  384. SpiFlashEmulator emu(8);
  385. Storage storage;
  386. emu.setBounds(4, 8);
  387. CHECK(storage.init(4, 4) == ESP_OK);
  388. for (size_t i = 0; i < Page::ENTRY_COUNT * 3; ++i) {
  389. char name[Item::MAX_KEY_LENGTH + 1];
  390. snprintf(name, sizeof(name), "key%05d", static_cast<int>(i));
  391. REQUIRE(storage.writeItem(1, name, static_cast<int>(i)) == ESP_OK);
  392. }
  393. REQUIRE(storage.writeItem(1, "foo", 10) == ESP_ERR_NVS_NOT_ENOUGH_SPACE);
  394. }
  395. TEST_CASE("can modify an item on a page which will be erased", "[nvs]")
  396. {
  397. SpiFlashEmulator emu(2);
  398. Storage storage;
  399. CHECK(storage.init(0, 2) == ESP_OK);
  400. for (size_t i = 0; i < Page::ENTRY_COUNT * 3 + 1; ++i) {
  401. REQUIRE(storage.writeItem(1, "foo", 42U) == ESP_OK);
  402. }
  403. }
  404. TEST_CASE("can erase items", "[nvs]")
  405. {
  406. SpiFlashEmulator emu(3);
  407. Storage storage;
  408. CHECK(storage.init(0, 3) == ESP_OK);
  409. for (size_t i = 0; i < Page::ENTRY_COUNT * 2 - 3; ++i) {
  410. char name[Item::MAX_KEY_LENGTH + 1];
  411. snprintf(name, sizeof(name), "key%05d", static_cast<int>(i));
  412. REQUIRE(storage.writeItem(3, name, static_cast<int>(i)) == ESP_OK);
  413. }
  414. CHECK(storage.writeItem(1, "foo", 32) == ESP_OK);
  415. CHECK(storage.writeItem(2, "foo", 64) == ESP_OK);
  416. CHECK(storage.eraseItem(2, "foo") == ESP_OK);
  417. int val;
  418. CHECK(storage.readItem(1, "foo", val) == ESP_OK);
  419. CHECK(val == 32);
  420. CHECK(storage.eraseNamespace(3) == ESP_OK);
  421. CHECK(storage.readItem(2, "foo", val) == ESP_ERR_NVS_NOT_FOUND);
  422. CHECK(storage.readItem(3, "key00222", val) == ESP_ERR_NVS_NOT_FOUND);
  423. }
  424. TEST_CASE("nvs api tests", "[nvs]")
  425. {
  426. SpiFlashEmulator emu(10);
  427. emu.randomize(100);
  428. nvs_handle handle_1;
  429. const uint32_t NVS_FLASH_SECTOR = 6;
  430. const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
  431. emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
  432. TEST_ESP_ERR(nvs_open("namespace1", NVS_READWRITE, &handle_1), ESP_ERR_NVS_NOT_INITIALIZED);
  433. for (uint16_t i = NVS_FLASH_SECTOR; i <NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN; ++i) {
  434. spi_flash_erase_sector(i);
  435. }
  436. TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  437. TEST_ESP_ERR(nvs_open("namespace1", NVS_READONLY, &handle_1), ESP_ERR_NVS_NOT_FOUND);
  438. // TEST_ESP_ERR(nvs_set_i32(handle_1, "foo", 0x12345678), ESP_ERR_NVS_READ_ONLY);
  439. // nvs_close(handle_1);
  440. TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle_1));
  441. TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x12345678));
  442. TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x23456789));
  443. nvs_handle handle_2;
  444. TEST_ESP_OK(nvs_open("namespace2", NVS_READWRITE, &handle_2));
  445. TEST_ESP_OK(nvs_set_i32(handle_2, "foo", 0x3456789a));
  446. const char* str = "value 0123456789abcdef0123456789abcdef";
  447. TEST_ESP_OK(nvs_set_str(handle_2, "key", str));
  448. int32_t v1;
  449. TEST_ESP_OK(nvs_get_i32(handle_1, "foo", &v1));
  450. CHECK(0x23456789 == v1);
  451. int32_t v2;
  452. TEST_ESP_OK(nvs_get_i32(handle_2, "foo", &v2));
  453. CHECK(0x3456789a == v2);
  454. char buf[strlen(str) + 1];
  455. size_t buf_len = sizeof(buf);
  456. size_t buf_len_needed;
  457. TEST_ESP_OK(nvs_get_str(handle_2, "key", NULL, &buf_len_needed));
  458. CHECK(buf_len_needed == buf_len);
  459. size_t buf_len_short = buf_len - 1;
  460. TEST_ESP_ERR(ESP_ERR_NVS_INVALID_LENGTH, nvs_get_str(handle_2, "key", buf, &buf_len_short));
  461. CHECK(buf_len_short == buf_len);
  462. size_t buf_len_long = buf_len + 1;
  463. TEST_ESP_OK(nvs_get_str(handle_2, "key", buf, &buf_len_long));
  464. CHECK(buf_len_long == buf_len);
  465. TEST_ESP_OK(nvs_get_str(handle_2, "key", buf, &buf_len));
  466. CHECK(0 == strcmp(buf, str));
  467. }
  468. TEST_CASE("wifi test", "[nvs]")
  469. {
  470. SpiFlashEmulator emu(10);
  471. emu.randomize(10);
  472. const uint32_t NVS_FLASH_SECTOR = 5;
  473. const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
  474. emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
  475. TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  476. nvs_handle misc_handle;
  477. TEST_ESP_OK(nvs_open("nvs.net80211", NVS_READWRITE, &misc_handle));
  478. char log[33];
  479. size_t log_size = sizeof(log);
  480. TEST_ESP_ERR(nvs_get_str(misc_handle, "log", log, &log_size), ESP_ERR_NVS_NOT_FOUND);
  481. strcpy(log, "foobarbazfizzz");
  482. TEST_ESP_OK(nvs_set_str(misc_handle, "log", log));
  483. nvs_handle net80211_handle;
  484. TEST_ESP_OK(nvs_open("nvs.net80211", NVS_READWRITE, &net80211_handle));
  485. uint8_t opmode = 2;
  486. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "wifi.opmode", &opmode), ESP_ERR_NVS_NOT_FOUND);
  487. TEST_ESP_OK(nvs_set_u8(net80211_handle, "wifi.opmode", opmode));
  488. uint8_t country = 0;
  489. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "wifi.country", &opmode), ESP_ERR_NVS_NOT_FOUND);
  490. TEST_ESP_OK(nvs_set_u8(net80211_handle, "wifi.country", opmode));
  491. char ssid[36];
  492. size_t size = sizeof(ssid);
  493. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.ssid", ssid, &size), ESP_ERR_NVS_NOT_FOUND);
  494. strcpy(ssid, "my android AP");
  495. TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.ssid", ssid, size));
  496. char mac[6];
  497. size = sizeof(mac);
  498. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.mac", mac, &size), ESP_ERR_NVS_NOT_FOUND);
  499. memset(mac, 0xab, 6);
  500. TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.mac", mac, size));
  501. uint8_t authmode = 1;
  502. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "sta.authmode", &authmode), ESP_ERR_NVS_NOT_FOUND);
  503. TEST_ESP_OK(nvs_set_u8(net80211_handle, "sta.authmode", authmode));
  504. char pswd[65];
  505. size = sizeof(pswd);
  506. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.pswd", pswd, &size), ESP_ERR_NVS_NOT_FOUND);
  507. strcpy(pswd, "`123456788990-=");
  508. TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.pswd", pswd, size));
  509. char pmk[32];
  510. size = sizeof(pmk);
  511. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.pmk", pmk, &size), ESP_ERR_NVS_NOT_FOUND);
  512. memset(pmk, 1, size);
  513. TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.pmk", pmk, size));
  514. uint8_t chan = 1;
  515. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "sta.chan", &chan), ESP_ERR_NVS_NOT_FOUND);
  516. TEST_ESP_OK(nvs_set_u8(net80211_handle, "sta.chan", chan));
  517. uint8_t autoconn = 1;
  518. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "auto.conn", &autoconn), ESP_ERR_NVS_NOT_FOUND);
  519. TEST_ESP_OK(nvs_set_u8(net80211_handle, "auto.conn", autoconn));
  520. uint8_t bssid_set = 1;
  521. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "bssid.set", &bssid_set), ESP_ERR_NVS_NOT_FOUND);
  522. TEST_ESP_OK(nvs_set_u8(net80211_handle, "bssid.set", bssid_set));
  523. char bssid[6];
  524. size = sizeof(bssid);
  525. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.bssid", bssid, &size), ESP_ERR_NVS_NOT_FOUND);
  526. memset(mac, 0xcd, 6);
  527. TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.bssid", bssid, size));
  528. uint8_t phym = 3;
  529. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "sta.phym", &phym), ESP_ERR_NVS_NOT_FOUND);
  530. TEST_ESP_OK(nvs_set_u8(net80211_handle, "sta.phym", phym));
  531. uint8_t phybw = 2;
  532. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "sta.phybw", &phybw), ESP_ERR_NVS_NOT_FOUND);
  533. TEST_ESP_OK(nvs_set_u8(net80211_handle, "sta.phybw", phybw));
  534. char apsw[2];
  535. size = sizeof(apsw);
  536. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.apsw", apsw, &size), ESP_ERR_NVS_NOT_FOUND);
  537. memset(apsw, 0x2, size);
  538. TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.apsw", apsw, size));
  539. char apinfo[700];
  540. size = sizeof(apinfo);
  541. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "sta.apinfo", apinfo, &size), ESP_ERR_NVS_NOT_FOUND);
  542. memset(apinfo, 0, size);
  543. TEST_ESP_OK(nvs_set_blob(net80211_handle, "sta.apinfo", apinfo, size));
  544. size = sizeof(ssid);
  545. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "ap.ssid", ssid, &size), ESP_ERR_NVS_NOT_FOUND);
  546. strcpy(ssid, "ESP_A2F340");
  547. TEST_ESP_OK(nvs_set_blob(net80211_handle, "ap.ssid", ssid, size));
  548. size = sizeof(mac);
  549. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "ap.mac", mac, &size), ESP_ERR_NVS_NOT_FOUND);
  550. memset(mac, 0xac, 6);
  551. TEST_ESP_OK(nvs_set_blob(net80211_handle, "ap.mac", mac, size));
  552. size = sizeof(pswd);
  553. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "ap.passwd", pswd, &size), ESP_ERR_NVS_NOT_FOUND);
  554. strcpy(pswd, "");
  555. TEST_ESP_OK(nvs_set_blob(net80211_handle, "ap.passwd", pswd, size));
  556. size = sizeof(pmk);
  557. TEST_ESP_ERR(nvs_get_blob(net80211_handle, "ap.pmk", pmk, &size), ESP_ERR_NVS_NOT_FOUND);
  558. memset(pmk, 1, size);
  559. TEST_ESP_OK(nvs_set_blob(net80211_handle, "ap.pmk", pmk, size));
  560. chan = 6;
  561. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "ap.chan", &chan), ESP_ERR_NVS_NOT_FOUND);
  562. TEST_ESP_OK(nvs_set_u8(net80211_handle, "ap.chan", chan));
  563. authmode = 0;
  564. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "ap.authmode", &authmode), ESP_ERR_NVS_NOT_FOUND);
  565. TEST_ESP_OK(nvs_set_u8(net80211_handle, "ap.authmode", authmode));
  566. uint8_t hidden = 0;
  567. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "ap.hidden", &hidden), ESP_ERR_NVS_NOT_FOUND);
  568. TEST_ESP_OK(nvs_set_u8(net80211_handle, "ap.hidden", hidden));
  569. uint8_t max_conn = 4;
  570. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "ap.max.conn", &max_conn), ESP_ERR_NVS_NOT_FOUND);
  571. TEST_ESP_OK(nvs_set_u8(net80211_handle, "ap.max.conn", max_conn));
  572. uint8_t bcn_interval = 2;
  573. TEST_ESP_ERR(nvs_get_u8(net80211_handle, "bcn_interval", &bcn_interval), ESP_ERR_NVS_NOT_FOUND);
  574. TEST_ESP_OK(nvs_set_u8(net80211_handle, "bcn_interval", bcn_interval));
  575. 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;
  576. }
  577. TEST_CASE("can init storage from flash with random contents", "[nvs]")
  578. {
  579. SpiFlashEmulator emu(10);
  580. emu.randomize(42);
  581. nvs_handle handle;
  582. const uint32_t NVS_FLASH_SECTOR = 5;
  583. const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
  584. emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
  585. TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  586. TEST_ESP_OK(nvs_open("nvs.net80211", NVS_READWRITE, &handle));
  587. uint8_t opmode = 2;
  588. if (nvs_get_u8(handle, "wifi.opmode", &opmode) != ESP_OK) {
  589. TEST_ESP_OK(nvs_set_u8(handle, "wifi.opmode", opmode));
  590. }
  591. }
  592. TEST_CASE("nvs api tests, starting with random data in flash", "[nvs][.][long]")
  593. {
  594. for (size_t count = 0; count < 10000; ++count) {
  595. SpiFlashEmulator emu(10);
  596. emu.randomize(static_cast<uint32_t>(count));
  597. const uint32_t NVS_FLASH_SECTOR = 6;
  598. const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
  599. emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
  600. TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  601. nvs_handle handle_1;
  602. TEST_ESP_ERR(nvs_open("namespace1", NVS_READONLY, &handle_1), ESP_ERR_NVS_NOT_FOUND);
  603. TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle_1));
  604. TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x12345678));
  605. for (size_t i = 0; i < 500; ++i) {
  606. nvs_handle handle_2;
  607. TEST_ESP_OK(nvs_open("namespace2", NVS_READWRITE, &handle_2));
  608. TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x23456789 % (i + 1)));
  609. TEST_ESP_OK(nvs_set_i32(handle_2, "foo", static_cast<int32_t>(i)));
  610. const char* str = "value 0123456789abcdef0123456789abcdef %09d";
  611. char str_buf[128];
  612. snprintf(str_buf, sizeof(str_buf), str, i + count * 1024);
  613. TEST_ESP_OK(nvs_set_str(handle_2, "key", str_buf));
  614. int32_t v1;
  615. TEST_ESP_OK(nvs_get_i32(handle_1, "foo", &v1));
  616. CHECK(0x23456789 % (i + 1) == v1);
  617. int32_t v2;
  618. TEST_ESP_OK(nvs_get_i32(handle_2, "foo", &v2));
  619. CHECK(static_cast<int32_t>(i) == v2);
  620. char buf[128];
  621. size_t buf_len = sizeof(buf);
  622. TEST_ESP_OK(nvs_get_str(handle_2, "key", buf, &buf_len));
  623. CHECK(0 == strcmp(buf, str_buf));
  624. nvs_close(handle_2);
  625. }
  626. nvs_close(handle_1);
  627. }
  628. }
  629. extern "C" void nvs_dump(const char *partName);
  630. class RandomTest {
  631. static const size_t nKeys = 9;
  632. int32_t v1 = 0, v2 = 0;
  633. uint64_t v3 = 0, v4 = 0;
  634. static const size_t strBufLen = 1024;
  635. char v5[strBufLen], v6[strBufLen], v7[strBufLen], v8[strBufLen], v9[strBufLen];
  636. bool written[nKeys];
  637. public:
  638. RandomTest()
  639. {
  640. std::fill_n(written, nKeys, false);
  641. }
  642. template<typename TGen>
  643. esp_err_t doRandomThings(nvs_handle handle, TGen gen, size_t& count) {
  644. const char* keys[] = {"foo", "bar", "longkey_0123456", "another key", "param1", "param2", "param3", "param4", "param5"};
  645. const ItemType types[] = {ItemType::I32, ItemType::I32, ItemType::U64, ItemType::U64, ItemType::SZ, ItemType::SZ, ItemType::SZ, ItemType::SZ, ItemType::SZ};
  646. void* values[] = {&v1, &v2, &v3, &v4, &v5, &v6, &v7, &v8, &v9};
  647. const size_t nKeys = sizeof(keys) / sizeof(keys[0]);
  648. static_assert(nKeys == sizeof(types) / sizeof(types[0]), "");
  649. static_assert(nKeys == sizeof(values) / sizeof(values[0]), "");
  650. auto randomRead = [&](size_t index) -> esp_err_t {
  651. switch (types[index]) {
  652. case ItemType::I32:
  653. {
  654. int32_t val;
  655. auto err = nvs_get_i32(handle, keys[index], &val);
  656. if (err == ESP_ERR_FLASH_OP_FAIL) {
  657. return err;
  658. }
  659. if (!written[index]) {
  660. REQUIRE(err == ESP_ERR_NVS_NOT_FOUND);
  661. }
  662. else {
  663. REQUIRE(err == ESP_OK);
  664. REQUIRE(val == *reinterpret_cast<int32_t*>(values[index]));
  665. }
  666. break;
  667. }
  668. case ItemType::U64:
  669. {
  670. uint64_t val;
  671. auto err = nvs_get_u64(handle, keys[index], &val);
  672. if (err == ESP_ERR_FLASH_OP_FAIL) {
  673. return err;
  674. }
  675. if (!written[index]) {
  676. REQUIRE(err == ESP_ERR_NVS_NOT_FOUND);
  677. }
  678. else {
  679. REQUIRE(err == ESP_OK);
  680. REQUIRE(val == *reinterpret_cast<uint64_t*>(values[index]));
  681. }
  682. break;
  683. }
  684. case ItemType::SZ:
  685. {
  686. char buf[strBufLen];
  687. size_t len = strBufLen;
  688. auto err = nvs_get_str(handle, keys[index], buf, &len);
  689. if (err == ESP_ERR_FLASH_OP_FAIL) {
  690. return err;
  691. }
  692. if (!written[index]) {
  693. REQUIRE(err == ESP_ERR_NVS_NOT_FOUND);
  694. }
  695. else {
  696. REQUIRE(err == ESP_OK);
  697. REQUIRE(strncmp(buf, reinterpret_cast<const char*>(values[index]), strBufLen) == 0);
  698. }
  699. break;
  700. }
  701. default:
  702. assert(0);
  703. }
  704. return ESP_OK;
  705. };
  706. auto randomWrite = [&](size_t index) -> esp_err_t {
  707. switch (types[index]) {
  708. case ItemType::I32:
  709. {
  710. int32_t val = static_cast<int32_t>(gen());
  711. auto err = nvs_set_i32(handle, keys[index], val);
  712. if (err == ESP_ERR_FLASH_OP_FAIL) {
  713. return err;
  714. }
  715. if (err == ESP_ERR_NVS_REMOVE_FAILED) {
  716. written[index] = true;
  717. *reinterpret_cast<int32_t*>(values[index]) = val;
  718. return ESP_ERR_FLASH_OP_FAIL;
  719. }
  720. REQUIRE(err == ESP_OK);
  721. written[index] = true;
  722. *reinterpret_cast<int32_t*>(values[index]) = val;
  723. break;
  724. }
  725. case ItemType::U64:
  726. {
  727. uint64_t val = static_cast<uint64_t>(gen());
  728. auto err = nvs_set_u64(handle, keys[index], val);
  729. if (err == ESP_ERR_FLASH_OP_FAIL) {
  730. return err;
  731. }
  732. if (err == ESP_ERR_NVS_REMOVE_FAILED) {
  733. written[index] = true;
  734. *reinterpret_cast<uint64_t*>(values[index]) = val;
  735. return ESP_ERR_FLASH_OP_FAIL;
  736. }
  737. REQUIRE(err == ESP_OK);
  738. written[index] = true;
  739. *reinterpret_cast<uint64_t*>(values[index]) = val;
  740. break;
  741. }
  742. case ItemType::SZ:
  743. {
  744. char buf[strBufLen];
  745. size_t len = strBufLen;
  746. size_t strLen = gen() % (strBufLen - 1);
  747. std::generate_n(buf, strLen, [&]() -> char {
  748. const char c = static_cast<char>(gen() % 127);
  749. return (c < 32) ? 32 : c;
  750. });
  751. buf[strLen] = 0;
  752. auto err = nvs_set_str(handle, keys[index], buf);
  753. if (err == ESP_ERR_FLASH_OP_FAIL) {
  754. return err;
  755. }
  756. if (err == ESP_ERR_NVS_REMOVE_FAILED) {
  757. written[index] = true;
  758. strncpy(reinterpret_cast<char*>(values[index]), buf, strBufLen);
  759. return ESP_ERR_FLASH_OP_FAIL;
  760. }
  761. REQUIRE(err == ESP_OK);
  762. written[index] = true;
  763. strncpy(reinterpret_cast<char*>(values[index]), buf, strBufLen);
  764. break;
  765. }
  766. default:
  767. assert(0);
  768. }
  769. return ESP_OK;
  770. };
  771. for (; count != 0; --count) {
  772. size_t index = gen() % nKeys;
  773. switch (gen() % 3) {
  774. case 0: // read, 1/3
  775. if (randomRead(index) == ESP_ERR_FLASH_OP_FAIL) {
  776. return ESP_ERR_FLASH_OP_FAIL;
  777. }
  778. break;
  779. default: // write, 2/3
  780. if (randomWrite(index) == ESP_ERR_FLASH_OP_FAIL) {
  781. return ESP_ERR_FLASH_OP_FAIL;
  782. }
  783. break;
  784. }
  785. }
  786. return ESP_OK;
  787. }
  788. };
  789. TEST_CASE("monkey test", "[nvs][monkey]")
  790. {
  791. std::random_device rd;
  792. std::mt19937 gen(rd());
  793. uint32_t seed = 3;
  794. gen.seed(seed);
  795. SpiFlashEmulator emu(10);
  796. emu.randomize(seed);
  797. emu.clearStats();
  798. const uint32_t NVS_FLASH_SECTOR = 6;
  799. const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
  800. emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
  801. TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  802. nvs_handle handle;
  803. TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle));
  804. RandomTest test;
  805. size_t count = 1000;
  806. CHECK(test.doRandomThings(handle, gen, count) == ESP_OK);
  807. s_perf << "Monkey test: nErase=" << emu.getEraseOps() << " nWrite=" << emu.getWriteOps() << std::endl;
  808. }
  809. TEST_CASE("test recovery from sudden poweroff", "[.][long][nvs][recovery][monkey]")
  810. {
  811. std::random_device rd;
  812. std::mt19937 gen(rd());
  813. uint32_t seed = 3;
  814. gen.seed(seed);
  815. const size_t iter_count = 2000;
  816. SpiFlashEmulator emu(10);
  817. const uint32_t NVS_FLASH_SECTOR = 6;
  818. const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
  819. emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
  820. size_t totalOps = 0;
  821. int lastPercent = -1;
  822. for (uint32_t errDelay = 0; ; ++errDelay) {
  823. INFO(errDelay);
  824. emu.randomize(seed);
  825. emu.clearStats();
  826. emu.failAfter(errDelay);
  827. RandomTest test;
  828. if (totalOps != 0) {
  829. int percent = errDelay * 100 / totalOps;
  830. if (percent > lastPercent) {
  831. printf("%d/%d (%d%%)\r\n", errDelay, static_cast<int>(totalOps), percent);
  832. lastPercent = percent;
  833. }
  834. }
  835. nvs_handle handle;
  836. size_t count = iter_count;
  837. if (nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK) {
  838. if (nvs_open("namespace1", NVS_READWRITE, &handle) == ESP_OK) {
  839. if(test.doRandomThings(handle, gen, count) != ESP_ERR_FLASH_OP_FAIL) {
  840. nvs_close(handle);
  841. break;
  842. }
  843. nvs_close(handle);
  844. }
  845. }
  846. TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  847. TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle));
  848. auto res = test.doRandomThings(handle, gen, count);
  849. if (res != ESP_OK) {
  850. nvs_dump(NVS_DEFAULT_PART_NAME);
  851. CHECK(0);
  852. }
  853. nvs_close(handle);
  854. totalOps = emu.getEraseOps() + emu.getWriteBytes() / 4;
  855. }
  856. }
  857. TEST_CASE("test for memory leaks in open/set", "[leaks]")
  858. {
  859. SpiFlashEmulator emu(10);
  860. const uint32_t NVS_FLASH_SECTOR = 6;
  861. const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
  862. emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);
  863. TEST_ESP_OK(nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
  864. for (int i = 0; i < 100000; ++i) {
  865. nvs_handle light_handle = 0;
  866. char lightbulb[1024] = {12, 13, 14, 15, 16};
  867. TEST_ESP_OK(nvs_open("light", NVS_READWRITE, &light_handle));
  868. TEST_ESP_OK(nvs_set_blob(light_handle, "key", lightbulb, sizeof(lightbulb)));
  869. TEST_ESP_OK(nvs_commit(light_handle));
  870. nvs_close(light_handle);
  871. }
  872. }
  873. TEST_CASE("duplicate items are removed", "[nvs][dupes]")
  874. {
  875. SpiFlashEmulator emu(3);
  876. {
  877. // create one item
  878. nvs::Page p;
  879. p.load(0);
  880. p.writeItem<uint8_t>(1, "opmode", 3);
  881. }
  882. {
  883. // add another two without deleting the first one
  884. nvs::Item item(1, ItemType::U8, 1, "opmode");
  885. item.data[0] = 2;
  886. item.crc32 = item.calculateCrc32();
  887. emu.write(3 * 32, reinterpret_cast<const uint32_t*>(&item), sizeof(item));
  888. emu.write(4 * 32, reinterpret_cast<const uint32_t*>(&item), sizeof(item));
  889. uint32_t mask = 0xFFFFFFEA;
  890. emu.write(32, &mask, 4);
  891. }
  892. {
  893. // load page and check that second item persists
  894. nvs::Storage s;
  895. s.init(0, 3);
  896. uint8_t val;
  897. ESP_ERROR_CHECK(s.readItem(1, "opmode", val));
  898. CHECK(val == 2);
  899. }
  900. {
  901. Page p;
  902. p.load(0);
  903. CHECK(p.getErasedEntryCount() == 2);
  904. CHECK(p.getUsedEntryCount() == 1);
  905. }
  906. }
  907. TEST_CASE("recovery after failure to write data", "[nvs]")
  908. {
  909. SpiFlashEmulator emu(3);
  910. const char str[] = "value 0123456789abcdef012345678value 0123456789abcdef012345678";
  911. // make flash write fail exactly in Page::writeEntryData
  912. emu.failAfter(17);
  913. {
  914. Storage storage;
  915. TEST_ESP_OK(storage.init(0, 3));
  916. TEST_ESP_ERR(storage.writeItem(1, ItemType::SZ, "key", str, strlen(str)), ESP_ERR_FLASH_OP_FAIL);
  917. // check that repeated operations cause an error
  918. TEST_ESP_ERR(storage.writeItem(1, ItemType::SZ, "key", str, strlen(str)), ESP_ERR_NVS_INVALID_STATE);
  919. uint8_t val;
  920. TEST_ESP_ERR(storage.readItem(1, ItemType::U8, "key", &val, sizeof(val)), ESP_ERR_NVS_NOT_FOUND);
  921. }
  922. {
  923. // load page and check that data was erased
  924. Page p;
  925. p.load(0);
  926. CHECK(p.getErasedEntryCount() == 3);
  927. CHECK(p.getUsedEntryCount() == 0);
  928. // try to write again
  929. TEST_ESP_OK(p.writeItem(1, ItemType::SZ, "key", str, strlen(str)));
  930. }
  931. }
  932. TEST_CASE("crc errors in item header are handled", "[nvs]")
  933. {
  934. SpiFlashEmulator emu(3);
  935. Storage storage;
  936. // prepare some data
  937. TEST_ESP_OK(storage.init(0, 3));
  938. TEST_ESP_OK(storage.writeItem(0, "ns1", static_cast<uint8_t>(1)));
  939. TEST_ESP_OK(storage.writeItem(1, "value1", static_cast<uint32_t>(1)));
  940. TEST_ESP_OK(storage.writeItem(1, "value2", static_cast<uint32_t>(2)));
  941. // corrupt item header
  942. uint32_t val = 0;
  943. emu.write(32 * 3, &val, 4);
  944. // check that storage can recover
  945. TEST_ESP_OK(storage.init(0, 3));
  946. TEST_ESP_OK(storage.readItem(1, "value2", val));
  947. CHECK(val == 2);
  948. // check that the corrupted item is no longer present
  949. TEST_ESP_ERR(ESP_ERR_NVS_NOT_FOUND, storage.readItem(1, "value1", val));
  950. // add more items to make the page full
  951. for (size_t i = 0; i < Page::ENTRY_COUNT; ++i) {
  952. char item_name[Item::MAX_KEY_LENGTH + 1];
  953. snprintf(item_name, sizeof(item_name), "item_%ld", i);
  954. TEST_ESP_OK(storage.writeItem(1, item_name, static_cast<uint32_t>(i)));
  955. }
  956. // corrupt another item on the full page
  957. val = 0;
  958. emu.write(32 * 4, &val, 4);
  959. // check that storage can recover
  960. TEST_ESP_OK(storage.init(0, 3));
  961. // check that the corrupted item is no longer present
  962. TEST_ESP_ERR(ESP_ERR_NVS_NOT_FOUND, storage.readItem(1, "value2", val));
  963. }
  964. TEST_CASE("crc error in variable length item is handled", "[nvs]")
  965. {
  966. SpiFlashEmulator emu(3);
  967. const uint64_t before_val = 0xbef04e;
  968. const uint64_t after_val = 0xaf7e4;
  969. // write some data
  970. {
  971. Page p;
  972. p.load(0);
  973. TEST_ESP_OK(p.writeItem<uint64_t>(0, "before", before_val));
  974. const char* str = "foobar";
  975. TEST_ESP_OK(p.writeItem(0, ItemType::SZ, "key", str, strlen(str)));
  976. TEST_ESP_OK(p.writeItem<uint64_t>(0, "after", after_val));
  977. }
  978. // corrupt some data
  979. uint32_t w;
  980. CHECK(emu.read(&w, 32 * 3 + 8, sizeof(w)));
  981. w &= 0xf000000f;
  982. CHECK(emu.write(32 * 3 + 8, &w, sizeof(w)));
  983. // load and check
  984. {
  985. Page p;
  986. p.load(0);
  987. CHECK(p.getUsedEntryCount() == 2);
  988. CHECK(p.getErasedEntryCount() == 2);
  989. uint64_t val;
  990. TEST_ESP_OK(p.readItem<uint64_t>(0, "before", val));
  991. CHECK(val == before_val);
  992. TEST_ESP_ERR(p.findItem(0, ItemType::SZ, "key"), ESP_ERR_NVS_NOT_FOUND);
  993. TEST_ESP_OK(p.readItem<uint64_t>(0, "after", val));
  994. CHECK(val == after_val);
  995. }
  996. }
  997. TEST_CASE("read/write failure (TW8406)", "[nvs]")
  998. {
  999. SpiFlashEmulator emu(3);
  1000. nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 3);
  1001. for (int attempts = 0; attempts < 3; ++attempts) {
  1002. int i = 0;
  1003. nvs_handle light_handle = 0;
  1004. char key[15] = {0};
  1005. char data[76] = {12, 13, 14, 15, 16};
  1006. uint8_t number = 20;
  1007. size_t data_len = sizeof(data);
  1008. ESP_ERROR_CHECK(nvs_open("LIGHT", NVS_READWRITE, &light_handle));
  1009. ESP_ERROR_CHECK(nvs_set_u8(light_handle, "RecordNum", number));
  1010. for (i = 0; i < number; ++i) {
  1011. sprintf(key, "light%d", i);
  1012. ESP_ERROR_CHECK(nvs_set_blob(light_handle, key, data, sizeof(data)));
  1013. }
  1014. nvs_commit(light_handle);
  1015. uint8_t get_number = 0;
  1016. ESP_ERROR_CHECK(nvs_get_u8(light_handle, "RecordNum", &get_number));
  1017. REQUIRE(number == get_number);
  1018. for (i = 0; i < number; ++i) {
  1019. char data[76] = {0};
  1020. sprintf(key, "light%d", i);
  1021. ESP_ERROR_CHECK(nvs_get_blob(light_handle, key, data, &data_len));
  1022. }
  1023. nvs_close(light_handle);
  1024. }
  1025. }
  1026. TEST_CASE("nvs_flash_init checks for an empty page", "[nvs]")
  1027. {
  1028. const size_t blob_size = Page::BLOB_MAX_SIZE;
  1029. uint8_t blob[blob_size] = {0};
  1030. SpiFlashEmulator emu(5);
  1031. TEST_ESP_OK( nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 5) );
  1032. nvs_handle handle;
  1033. TEST_ESP_OK( nvs_open("test", NVS_READWRITE, &handle) );
  1034. // Fill first page
  1035. TEST_ESP_OK( nvs_set_blob(handle, "1a", blob, blob_size) );
  1036. TEST_ESP_OK( nvs_set_blob(handle, "1b", blob, blob_size) );
  1037. // Fill second page
  1038. TEST_ESP_OK( nvs_set_blob(handle, "2a", blob, blob_size) );
  1039. TEST_ESP_OK( nvs_set_blob(handle, "2b", blob, blob_size) );
  1040. // Fill third page
  1041. TEST_ESP_OK( nvs_set_blob(handle, "3a", blob, blob_size) );
  1042. TEST_ESP_OK( nvs_set_blob(handle, "3b", blob, blob_size) );
  1043. TEST_ESP_OK( nvs_commit(handle) );
  1044. nvs_close(handle);
  1045. // first two pages are now full, third one is writable, last two are empty
  1046. // init should fail
  1047. TEST_ESP_ERR( nvs_flash_init_custom(NVS_DEFAULT_PART_NAME, 0, 3), ESP_ERR_NVS_NO_FREE_PAGES );
  1048. }
  1049. TEST_CASE("multiple partitions access check", "[nvs]")
  1050. {
  1051. SpiFlashEmulator emu(10);
  1052. TEST_ESP_OK( nvs_flash_init_custom("nvs1", 0, 5) );
  1053. TEST_ESP_OK( nvs_flash_init_custom("nvs2", 5, 5) );
  1054. nvs_handle handle1, handle2;
  1055. TEST_ESP_OK( nvs_open_from_partition("nvs1", "test", NVS_READWRITE, &handle1) );
  1056. TEST_ESP_OK( nvs_open_from_partition("nvs2", "test", NVS_READWRITE, &handle2) );
  1057. TEST_ESP_OK( nvs_set_i32(handle1, "foo", 0xdeadbeef));
  1058. TEST_ESP_OK( nvs_set_i32(handle2, "foo", 0xcafebabe));
  1059. int32_t v1, v2;
  1060. TEST_ESP_OK( nvs_get_i32(handle1, "foo", &v1));
  1061. TEST_ESP_OK( nvs_get_i32(handle2, "foo", &v2));
  1062. CHECK(v1 == 0xdeadbeef);
  1063. CHECK(v2 == 0xcafebabe);
  1064. }
  1065. TEST_CASE("dump all performance data", "[nvs]")
  1066. {
  1067. std::cout << "====================" << std::endl << "Dumping benchmarks" << std::endl;
  1068. std::cout << s_perf.str() << std::endl;
  1069. std::cout << "====================" << std::endl;
  1070. }