| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436 |
- // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- #include "nvs_partition.hpp"
- #include "nvs.h"
- #include "nvs_page.hpp"
- #include "nvs_storage.hpp"
- #include <exception>
- #include <string>
- #ifdef CONFIG_NVS_ENCRYPTION
- #include "nvs_encrypted_partition.hpp"
- #endif
- extern "C" {
- #include "Mockesp_partition.h"
- }
- struct FixtureException : std::exception {
- FixtureException(const std::string& msg) : msg(msg) { }
- const char *what() {
- return msg.c_str();
- }
- std::string msg;
- };
- class PartitionMock : public nvs::Partition {
- public:
- PartitionMock(uint32_t address, uint32_t size)
- : partition(), address(address), size(size)
- {
- assert(size);
- }
- const char *get_partition_name() override
- {
- return "";
- }
- esp_err_t read_raw(size_t src_offset, void* dst, size_t size) override
- {
- return esp_partition_read_raw(&partition, src_offset, dst, size);
- }
- esp_err_t read(size_t src_offset, void* dst, size_t size) override
- {
- return esp_partition_read(&partition, src_offset, dst, size);
- }
- esp_err_t write_raw(size_t dst_offset, const void* src, size_t size) override
- {
- return esp_partition_write_raw(&partition, dst_offset, src, size);
- }
- esp_err_t write(size_t dst_offset, const void* src, size_t size) override
- {
- return esp_partition_write(&partition, dst_offset, src, size);
- }
- esp_err_t erase_range(size_t dst_offset, size_t size) override
- {
- return esp_partition_erase_range(&partition, dst_offset, size);
- }
- uint32_t get_address() override
- {
- return address;
- }
- uint32_t get_size() override
- {
- return size;
- }
- const esp_partition_t partition;
- private:
- uint32_t address;
- uint32_t size;
- };
- #ifdef CONFIG_NVS_ENCRYPTION
- struct EncryptedPartitionFixture {
- EncryptedPartitionFixture(nvs_sec_cfg_t *cfg,
- uint32_t start_sector = 0,
- uint32_t sector_size = 1,
- const char *partition_name = NVS_DEFAULT_PART_NAME)
- : esp_partition(), emu(start_sector + sector_size),
- part(partition_name, &esp_partition) {
- esp_partition.address = start_sector * SPI_FLASH_SEC_SIZE;
- esp_partition.size = sector_size * SPI_FLASH_SEC_SIZE;
- assert(part.init(cfg) == ESP_OK);
- }
- ~EncryptedPartitionFixture() { }
- esp_partition_t esp_partition;
- SpiFlashEmulator emu;
- nvs::NVSEncryptedPartition part;
- };
- #endif
- struct PartitionMockFixture {
- PartitionMockFixture(uint32_t start_sector = 0,
- uint32_t sector_size = 1,
- const char *partition_name = NVS_DEFAULT_PART_NAME)
- : part_mock(start_sector * SPI_FLASH_SEC_SIZE, sector_size * SPI_FLASH_SEC_SIZE) {
- std::fill_n(raw_header, sizeof(raw_header)/sizeof(raw_header[0]), UINT8_MAX);
- // This resets the mocks and prevents meeting accidental expectations from previous tests.
- Mockesp_partition_Init();
- }
- ~PartitionMockFixture() { }
- uint8_t raw_header[512];
- PartitionMock part_mock;
- };
- struct NVSPageFixture : public PartitionMockFixture {
- NVSPageFixture(uint32_t start_sector = 0,
- uint32_t sector_size = 1,
- const char *partition_name = NVS_DEFAULT_PART_NAME)
- : PartitionMockFixture(start_sector, sector_size, partition_name), page()
- {
- esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header, 32);
- for (int i = 0; i < 8; i++) {
- esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header, 512);
- }
- if (page.load(&part_mock, start_sector) != ESP_OK) throw FixtureException("couldn't setup page");
- }
- nvs::Page page;
- };
- struct NVSValidPageFlashFixture : public PartitionMockFixture {
- const static uint8_t NS_INDEX = 1;
- // valid header
- uint8_t raw_header_valid [32];
- // entry table with one entry
- uint8_t raw_entry_table [32];
- uint8_t ns_entry [32];
- uint8_t value_entry [32];
- NVSValidPageFlashFixture(uint32_t start_sector = 0,
- uint32_t sector_size = 1,
- const char *partition_name = NVS_DEFAULT_PART_NAME)
- : PartitionMockFixture(start_sector, sector_size, partition_name),
- raw_header_valid {0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x16, 0xdd, 0xdc},
- ns_entry {0x00, 0x01, 0x01, 0xff, 0x68, 0xc5, 0x3f, 0x0b, 't', 'e', 's', 't', '_', 'n', 's', '\0',
- '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- value_entry {0x01, 0x01, 0x01, 0xff, 0x3d, 0xf3, 0x99, 0xe5, 't', 'e', 's', 't', '_', 'v', 'a', 'l',
- 'u', 'e', '\0', '\0', '\0', '\0', '\0', '\0', 47, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
- {
- std::fill_n(raw_entry_table, sizeof(raw_entry_table)/sizeof(raw_entry_table[0]), 0);
- raw_entry_table[0] = 0xfa;
- // read page header
- esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header_valid, 32);
- // read entry table
- esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_entry_table, 32);
- // read next free entry's header
- esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header, 4);
- // read namespace entry
- esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32);
- // read normal entry
- esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_ReturnArrayThruPtr_dst(value_entry, 32);
- // read normal entry second time during duplicated entry check
- esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_ReturnArrayThruPtr_dst(value_entry, 32);
- }
- };
- struct NVSValidPageFixture : public NVSValidPageFlashFixture {
- NVSValidPageFixture(uint32_t start_sector = 0,
- uint32_t sector_size = 1,
- const char *partition_name = NVS_DEFAULT_PART_NAME)
- : NVSValidPageFlashFixture(start_sector, sector_size, partition_name), page()
- {
- if (page.load(&part_mock, start_sector) != ESP_OK) throw FixtureException("couldn't setup page");
- }
- nvs::Page page;
- };
- struct NVSValidStorageFixture : public PartitionMockFixture {
- const static uint8_t NS_INDEX = 1;
- uint8_t ns_entry [32];
- uint8_t empty_entry [32];
- NVSValidStorageFixture(uint32_t start_sector = 0,
- uint32_t sector_size = 3,
- const char *partition_name = NVS_DEFAULT_PART_NAME)
- : PartitionMockFixture(start_sector, sector_size, partition_name),
- ns_entry {0x00, 0x01, 0x01, 0xff, 0x68, 0xc5, 0x3f, 0x0b, 't', 'e', 's', 't', '_', 'n', 's', '\0',
- '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- empty_entry(),
- storage(&part_mock)
- {
- std::fill_n(empty_entry, sizeof(empty_entry)/sizeof(empty_entry[0]), 0xFF);
- // entry table with one entry
- uint8_t raw_entry_table [32];
- uint8_t header_full_page [] = {
- 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x16, 0xdd, 0xdc};
- uint8_t header_second_page [] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- uint8_t header_third_page [] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- // entry_table with all elements deleted except the namespace entry written and the last entry free
- std::fill_n(raw_entry_table, sizeof(raw_entry_table)/sizeof(raw_entry_table[0]), 0);
- raw_entry_table[0] = 0x02;
- raw_entry_table[31] = 0xFC;
- // read full page header
- esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_raw_ReturnArrayThruPtr_dst(header_full_page, 32);
- // read entry table
- esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_entry_table, 32);
- // reading entry table checks empty entry
- esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_raw_ReturnArrayThruPtr_dst(empty_entry, 32);
- // read namespace entry
- esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32);
- // read last two pages' headers, which trigger an automatic full read each because each page is empty
- esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_raw_ReturnArrayThruPtr_dst(header_second_page, 32);
- for (int i = 0; i < 8; i++) {
- esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header, 512);
- }
- esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_raw_ReturnArrayThruPtr_dst(header_third_page, 32);
- for (int i = 0; i < 8; i++) {
- esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header, 512);
- }
- // read namespace entry in duplicated header item check of pagemanager::load
- esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32);
- // storage finally actually reads namespace
- esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32);
- // storage looks for blob index entries
- esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32);
- // Storage::eraseOrphanDataBlobs() also wants to take it's turn...
- esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32);
- if (storage.init(start_sector, sector_size) != ESP_OK) throw FixtureException("couldn't setup page");
- }
- nvs::Storage storage;
- };
- struct NVSValidBlobPageFixture : public PartitionMockFixture {
- const static uint8_t NS_INDEX = 1;
- const static size_t BLOB_DATA_SIZE = 32;
- // valid header
- uint8_t raw_header_valid [32];
- // entry table with one entry
- uint8_t raw_entry_table [32];
- uint8_t ns_entry [32];
- uint8_t blob_entry [32];
- uint8_t blob_data [BLOB_DATA_SIZE];
- uint8_t blob_index [32];
- NVSValidBlobPageFixture(uint32_t start_sector = 0,
- uint32_t sector_size = 1,
- const char *partition_name = NVS_DEFAULT_PART_NAME)
- : PartitionMockFixture(start_sector, sector_size, partition_name),
- raw_header_valid {0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x16, 0xdd, 0xdc},
- ns_entry {0x00, 0x01, 0x01, 0xff, 0x68, 0xc5, 0x3f, 0x0b, 't', 'e', 's', 't', '_', 'n', 's', '\0',
- '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- blob_entry {0x01, 0x42, 0x02, 0x00, 0xaa, 0xf3, 0x23, 0x87, 't', 'e', 's', 't', '_', 'b', 'l', 'o',
- 'b', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 0x20, 0x00, 0xff, 0xff, 0xc6, 0x96, 0x86, 0xd9},
- blob_data {0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
- 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef},
- blob_index {0x01, 0x48, 0x01, 0xff, 0x42, 0x6b, 0xdf, 0x66, 't', 'e', 's', 't', '_', 'b', 'l', 'o',
- 'b', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff},
- page()
- {
- std::fill_n(raw_entry_table, sizeof(raw_entry_table)/sizeof(raw_entry_table[0]), 0xFF);
- raw_entry_table[0] = 0xaa;
- // read page header
- esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header_valid, 32);
- // read entry table
- esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_entry_table, 32);
- // read next free entry's header
- esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header, 4);
- // read namespace entry
- esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32);
- // read normal blob entry + index, not the data
- esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_ReturnArrayThruPtr_dst(blob_entry, 32);
- esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_ReturnArrayThruPtr_dst(blob_index, 32);
- // read normal entry second time during duplicated entry check
- esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_ReturnArrayThruPtr_dst(blob_entry, 32);
- if (page.load(&part_mock, start_sector) != ESP_OK) throw FixtureException("couldn't setup page");
- }
- nvs::Page page;
- };
- struct NVSFullPageFixture : public PartitionMockFixture {
- const static uint8_t NS_INDEX = 1;
- // valid header
- uint8_t raw_header_valid [32];
- // entry table with one entry
- uint8_t raw_entry_table [32];
- uint8_t ns_entry [32];
- uint8_t value_entry [32];
- NVSFullPageFixture(uint32_t start_sector = 0,
- uint32_t sector_size = 1,
- const char *partition_name = NVS_DEFAULT_PART_NAME,
- bool load = true)
- : PartitionMockFixture(start_sector, sector_size, partition_name),
- raw_header_valid {0xfc, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa3, 0x48, 0x9f, 0x38},
- ns_entry {0x00, 0x01, 0x01, 0xff, 0x68, 0xc5, 0x3f, 0x0b, 't', 'e', 's', 't', '_', 'n', 's', '\0',
- '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- value_entry {0x01, 0x01, 0x01, 0xff, 0x3d, 0xf3, 0x99, 0xe5, 't', 'e', 's', 't', '_', 'v', 'a', 'l',
- 'u', 'e', '\0', '\0', '\0', '\0', '\0', '\0', 47, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- page()
- {
- // entry_table with all elements deleted except the namespace entry written and the last entry free
- std::fill_n(raw_entry_table, sizeof(raw_entry_table)/sizeof(raw_entry_table[0]), 0);
- raw_entry_table[0] = 0x0a;
- raw_entry_table[31] = 0xFC;
- // read page header
- esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header_valid, 32);
- // read entry table
- esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_entry_table, 32);
- // no next free entry check, only one entry written
- // read namespace entry
- esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32);
- // read normal entry
- esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
- esp_partition_read_ReturnArrayThruPtr_dst(value_entry, 32);
- // no duplicated entry check
- if (load) {
- if (page.load(&part_mock, start_sector) != ESP_OK) throw FixtureException("couldn't setup page");
- }
- }
- nvs::Page page;
- };
|