test_fixtures.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  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 "nvs_partition.hpp"
  14. #include "nvs.h"
  15. #include "nvs_page.hpp"
  16. #include "nvs_storage.hpp"
  17. #include <exception>
  18. #include <string>
  19. #ifdef CONFIG_NVS_ENCRYPTION
  20. #include "nvs_encrypted_partition.hpp"
  21. #endif
  22. extern "C" {
  23. #include "Mockesp_partition.h"
  24. }
  25. struct FixtureException : std::exception {
  26. FixtureException(const std::string& msg) : msg(msg) { }
  27. const char *what() {
  28. return msg.c_str();
  29. }
  30. std::string msg;
  31. };
  32. class PartitionMock : public nvs::Partition {
  33. public:
  34. PartitionMock(uint32_t address, uint32_t size)
  35. : partition(), address(address), size(size)
  36. {
  37. assert(size);
  38. }
  39. const char *get_partition_name() override
  40. {
  41. return "";
  42. }
  43. esp_err_t read_raw(size_t src_offset, void* dst, size_t size) override
  44. {
  45. return esp_partition_read_raw(&partition, src_offset, dst, size);
  46. }
  47. esp_err_t read(size_t src_offset, void* dst, size_t size) override
  48. {
  49. return esp_partition_read(&partition, src_offset, dst, size);
  50. }
  51. esp_err_t write_raw(size_t dst_offset, const void* src, size_t size) override
  52. {
  53. return esp_partition_write_raw(&partition, dst_offset, src, size);
  54. }
  55. esp_err_t write(size_t dst_offset, const void* src, size_t size) override
  56. {
  57. return esp_partition_write(&partition, dst_offset, src, size);
  58. }
  59. esp_err_t erase_range(size_t dst_offset, size_t size) override
  60. {
  61. return esp_partition_erase_range(&partition, dst_offset, size);
  62. }
  63. uint32_t get_address() override
  64. {
  65. return address;
  66. }
  67. uint32_t get_size() override
  68. {
  69. return size;
  70. }
  71. const esp_partition_t partition;
  72. private:
  73. uint32_t address;
  74. uint32_t size;
  75. };
  76. #ifdef CONFIG_NVS_ENCRYPTION
  77. struct EncryptedPartitionFixture {
  78. EncryptedPartitionFixture(nvs_sec_cfg_t *cfg,
  79. uint32_t start_sector = 0,
  80. uint32_t sector_size = 1,
  81. const char *partition_name = NVS_DEFAULT_PART_NAME)
  82. : esp_partition(), emu(start_sector + sector_size),
  83. part(partition_name, &esp_partition) {
  84. esp_partition.address = start_sector * SPI_FLASH_SEC_SIZE;
  85. esp_partition.size = sector_size * SPI_FLASH_SEC_SIZE;
  86. assert(part.init(cfg) == ESP_OK);
  87. }
  88. ~EncryptedPartitionFixture() { }
  89. esp_partition_t esp_partition;
  90. SpiFlashEmulator emu;
  91. nvs::NVSEncryptedPartition part;
  92. };
  93. #endif
  94. struct PartitionMockFixture {
  95. PartitionMockFixture(uint32_t start_sector = 0,
  96. uint32_t sector_size = 1,
  97. const char *partition_name = NVS_DEFAULT_PART_NAME)
  98. : part_mock(start_sector * SPI_FLASH_SEC_SIZE, sector_size * SPI_FLASH_SEC_SIZE) {
  99. std::fill_n(raw_header, sizeof(raw_header)/sizeof(raw_header[0]), UINT8_MAX);
  100. // This resets the mocks and prevents meeting accidental expectations from previous tests.
  101. Mockesp_partition_Init();
  102. }
  103. ~PartitionMockFixture() { }
  104. uint8_t raw_header[512];
  105. PartitionMock part_mock;
  106. };
  107. struct NVSPageFixture : public PartitionMockFixture {
  108. NVSPageFixture(uint32_t start_sector = 0,
  109. uint32_t sector_size = 1,
  110. const char *partition_name = NVS_DEFAULT_PART_NAME)
  111. : PartitionMockFixture(start_sector, sector_size, partition_name), page()
  112. {
  113. esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
  114. esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header, 32);
  115. for (int i = 0; i < 8; i++) {
  116. esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
  117. esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header, 512);
  118. }
  119. if (page.load(&part_mock, start_sector) != ESP_OK) throw FixtureException("couldn't setup page");
  120. }
  121. nvs::Page page;
  122. };
  123. struct NVSValidPageFlashFixture : public PartitionMockFixture {
  124. const static uint8_t NS_INDEX = 1;
  125. // valid header
  126. uint8_t raw_header_valid [32];
  127. // entry table with one entry
  128. uint8_t raw_entry_table [32];
  129. uint8_t ns_entry [32];
  130. uint8_t value_entry [32];
  131. NVSValidPageFlashFixture(uint32_t start_sector = 0,
  132. uint32_t sector_size = 1,
  133. const char *partition_name = NVS_DEFAULT_PART_NAME)
  134. : PartitionMockFixture(start_sector, sector_size, partition_name),
  135. raw_header_valid {0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  136. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x16, 0xdd, 0xdc},
  137. ns_entry {0x00, 0x01, 0x01, 0xff, 0x68, 0xc5, 0x3f, 0x0b, 't', 'e', 's', 't', '_', 'n', 's', '\0',
  138. '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
  139. value_entry {0x01, 0x01, 0x01, 0xff, 0x3d, 0xf3, 0x99, 0xe5, 't', 'e', 's', 't', '_', 'v', 'a', 'l',
  140. 'u', 'e', '\0', '\0', '\0', '\0', '\0', '\0', 47, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
  141. {
  142. std::fill_n(raw_entry_table, sizeof(raw_entry_table)/sizeof(raw_entry_table[0]), 0);
  143. raw_entry_table[0] = 0xfa;
  144. // read page header
  145. esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
  146. esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header_valid, 32);
  147. // read entry table
  148. esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
  149. esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_entry_table, 32);
  150. // read next free entry's header
  151. esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
  152. esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header, 4);
  153. // read namespace entry
  154. esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
  155. esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32);
  156. // read normal entry
  157. esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
  158. esp_partition_read_ReturnArrayThruPtr_dst(value_entry, 32);
  159. // read normal entry second time during duplicated entry check
  160. esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
  161. esp_partition_read_ReturnArrayThruPtr_dst(value_entry, 32);
  162. }
  163. };
  164. struct NVSValidPageFixture : public NVSValidPageFlashFixture {
  165. NVSValidPageFixture(uint32_t start_sector = 0,
  166. uint32_t sector_size = 1,
  167. const char *partition_name = NVS_DEFAULT_PART_NAME)
  168. : NVSValidPageFlashFixture(start_sector, sector_size, partition_name), page()
  169. {
  170. if (page.load(&part_mock, start_sector) != ESP_OK) throw FixtureException("couldn't setup page");
  171. }
  172. nvs::Page page;
  173. };
  174. struct NVSValidStorageFixture : public PartitionMockFixture {
  175. const static uint8_t NS_INDEX = 1;
  176. uint8_t ns_entry [32];
  177. uint8_t empty_entry [32];
  178. NVSValidStorageFixture(uint32_t start_sector = 0,
  179. uint32_t sector_size = 3,
  180. const char *partition_name = NVS_DEFAULT_PART_NAME)
  181. : PartitionMockFixture(start_sector, sector_size, partition_name),
  182. ns_entry {0x00, 0x01, 0x01, 0xff, 0x68, 0xc5, 0x3f, 0x0b, 't', 'e', 's', 't', '_', 'n', 's', '\0',
  183. '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
  184. empty_entry(),
  185. storage(&part_mock)
  186. {
  187. std::fill_n(empty_entry, sizeof(empty_entry)/sizeof(empty_entry[0]), 0xFF);
  188. // entry table with one entry
  189. uint8_t raw_entry_table [32];
  190. uint8_t header_full_page [] = {
  191. 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  192. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x16, 0xdd, 0xdc};
  193. uint8_t header_second_page [] = {
  194. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  195. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
  196. uint8_t header_third_page [] = {
  197. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  198. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
  199. // entry_table with all elements deleted except the namespace entry written and the last entry free
  200. std::fill_n(raw_entry_table, sizeof(raw_entry_table)/sizeof(raw_entry_table[0]), 0);
  201. raw_entry_table[0] = 0x02;
  202. raw_entry_table[31] = 0xFC;
  203. // read full page header
  204. esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
  205. esp_partition_read_raw_ReturnArrayThruPtr_dst(header_full_page, 32);
  206. // read entry table
  207. esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
  208. esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_entry_table, 32);
  209. // reading entry table checks empty entry
  210. esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
  211. esp_partition_read_raw_ReturnArrayThruPtr_dst(empty_entry, 32);
  212. // read namespace entry
  213. esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
  214. esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32);
  215. // read last two pages' headers, which trigger an automatic full read each because each page is empty
  216. esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
  217. esp_partition_read_raw_ReturnArrayThruPtr_dst(header_second_page, 32);
  218. for (int i = 0; i < 8; i++) {
  219. esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
  220. esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header, 512);
  221. }
  222. esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
  223. esp_partition_read_raw_ReturnArrayThruPtr_dst(header_third_page, 32);
  224. for (int i = 0; i < 8; i++) {
  225. esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
  226. esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header, 512);
  227. }
  228. // read namespace entry in duplicated header item check of pagemanager::load
  229. esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
  230. esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32);
  231. // storage finally actually reads namespace
  232. esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
  233. esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32);
  234. // storage looks for blob index entries
  235. esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
  236. esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32);
  237. // Storage::eraseOrphanDataBlobs() also wants to take it's turn...
  238. esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
  239. esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32);
  240. if (storage.init(start_sector, sector_size) != ESP_OK) throw FixtureException("couldn't setup page");
  241. }
  242. nvs::Storage storage;
  243. };
  244. struct NVSValidBlobPageFixture : public PartitionMockFixture {
  245. const static uint8_t NS_INDEX = 1;
  246. const static size_t BLOB_DATA_SIZE = 32;
  247. // valid header
  248. uint8_t raw_header_valid [32];
  249. // entry table with one entry
  250. uint8_t raw_entry_table [32];
  251. uint8_t ns_entry [32];
  252. uint8_t blob_entry [32];
  253. uint8_t blob_data [BLOB_DATA_SIZE];
  254. uint8_t blob_index [32];
  255. NVSValidBlobPageFixture(uint32_t start_sector = 0,
  256. uint32_t sector_size = 1,
  257. const char *partition_name = NVS_DEFAULT_PART_NAME)
  258. : PartitionMockFixture(start_sector, sector_size, partition_name),
  259. raw_header_valid {0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  260. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x16, 0xdd, 0xdc},
  261. ns_entry {0x00, 0x01, 0x01, 0xff, 0x68, 0xc5, 0x3f, 0x0b, 't', 'e', 's', 't', '_', 'n', 's', '\0',
  262. '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
  263. blob_entry {0x01, 0x42, 0x02, 0x00, 0xaa, 0xf3, 0x23, 0x87, 't', 'e', 's', 't', '_', 'b', 'l', 'o',
  264. 'b', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 0x20, 0x00, 0xff, 0xff, 0xc6, 0x96, 0x86, 0xd9},
  265. blob_data {0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
  266. 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef},
  267. blob_index {0x01, 0x48, 0x01, 0xff, 0x42, 0x6b, 0xdf, 0x66, 't', 'e', 's', 't', '_', 'b', 'l', 'o',
  268. 'b', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff},
  269. page()
  270. {
  271. std::fill_n(raw_entry_table, sizeof(raw_entry_table)/sizeof(raw_entry_table[0]), 0xFF);
  272. raw_entry_table[0] = 0xaa;
  273. // read page header
  274. esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
  275. esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header_valid, 32);
  276. // read entry table
  277. esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
  278. esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_entry_table, 32);
  279. // read next free entry's header
  280. esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
  281. esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header, 4);
  282. // read namespace entry
  283. esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
  284. esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32);
  285. // read normal blob entry + index, not the data
  286. esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
  287. esp_partition_read_ReturnArrayThruPtr_dst(blob_entry, 32);
  288. esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
  289. esp_partition_read_ReturnArrayThruPtr_dst(blob_index, 32);
  290. // read normal entry second time during duplicated entry check
  291. esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
  292. esp_partition_read_ReturnArrayThruPtr_dst(blob_entry, 32);
  293. if (page.load(&part_mock, start_sector) != ESP_OK) throw FixtureException("couldn't setup page");
  294. }
  295. nvs::Page page;
  296. };
  297. struct NVSFullPageFixture : public PartitionMockFixture {
  298. const static uint8_t NS_INDEX = 1;
  299. // valid header
  300. uint8_t raw_header_valid [32];
  301. // entry table with one entry
  302. uint8_t raw_entry_table [32];
  303. uint8_t ns_entry [32];
  304. uint8_t value_entry [32];
  305. NVSFullPageFixture(uint32_t start_sector = 0,
  306. uint32_t sector_size = 1,
  307. const char *partition_name = NVS_DEFAULT_PART_NAME,
  308. bool load = true)
  309. : PartitionMockFixture(start_sector, sector_size, partition_name),
  310. raw_header_valid {0xfc, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  311. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa3, 0x48, 0x9f, 0x38},
  312. ns_entry {0x00, 0x01, 0x01, 0xff, 0x68, 0xc5, 0x3f, 0x0b, 't', 'e', 's', 't', '_', 'n', 's', '\0',
  313. '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
  314. value_entry {0x01, 0x01, 0x01, 0xff, 0x3d, 0xf3, 0x99, 0xe5, 't', 'e', 's', 't', '_', 'v', 'a', 'l',
  315. 'u', 'e', '\0', '\0', '\0', '\0', '\0', '\0', 47, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
  316. page()
  317. {
  318. // entry_table with all elements deleted except the namespace entry written and the last entry free
  319. std::fill_n(raw_entry_table, sizeof(raw_entry_table)/sizeof(raw_entry_table[0]), 0);
  320. raw_entry_table[0] = 0x0a;
  321. raw_entry_table[31] = 0xFC;
  322. // read page header
  323. esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
  324. esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header_valid, 32);
  325. // read entry table
  326. esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
  327. esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_entry_table, 32);
  328. // no next free entry check, only one entry written
  329. // read namespace entry
  330. esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
  331. esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32);
  332. // read normal entry
  333. esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
  334. esp_partition_read_ReturnArrayThruPtr_dst(value_entry, 32);
  335. // no duplicated entry check
  336. if (load) {
  337. if (page.load(&part_mock, start_sector) != ESP_OK) throw FixtureException("couldn't setup page");
  338. }
  339. }
  340. nvs::Page page;
  341. };