mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 03:00:34 +03:00
refactor(nvs_flash): NVS Host tests cleaned-up and test cases commented
- Host test were refactored to allow for BDL and non-BDL NVS implementation - Introduceed `NVSPartitionTestHelper` class replacing `PartitionEmulationFixture` - Refactored all tests to use `NVSPartitionTestHelper` instead of legacy emulation fixture - Removed legacy `PartitionEmulationFixture` and `PartitionEmulationFixture2` classes - Removed `TEMPORARILY_DISABLED` macro usage by reducing partition size in applicable tests - Enhanced test coverage and readability with comments and validation steps for each TC - Added utility functions for partition stats tracking, file loading, and erase count check
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
components/nvs_flash/host_test:
|
components/nvs_flash/host_test:
|
||||||
depends_components:
|
depends_components:
|
||||||
- spi_flash
|
|
||||||
- nvs_flash
|
- nvs_flash
|
||||||
- nvs_sec_provider
|
- nvs_sec_provider
|
||||||
|
- esp_blockdev
|
||||||
- esp_partition
|
- esp_partition
|
||||||
- esp_blockdev
|
- esp_blockdev
|
||||||
enable:
|
enable:
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
idf_component_register(SRCS "test_nvs.cpp"
|
idf_component_register(SRCS "bdl_ramdisk.cpp" "test_nvs.cpp"
|
||||||
"test_partition_manager.cpp"
|
"test_partition_manager.cpp"
|
||||||
"test_nvs_cxx_api.cpp"
|
"test_nvs_cxx_api.cpp"
|
||||||
"test_nvs_handle.cpp"
|
"test_nvs_handle.cpp"
|
||||||
"test_nvs_initialization.cpp"
|
"test_nvs_initialization.cpp"
|
||||||
"test_nvs_storage.cpp"
|
"test_nvs_storage.cpp"
|
||||||
|
"test_fixtures.cpp"
|
||||||
|
"bdl_ramdisk.cpp"
|
||||||
INCLUDE_DIRS
|
INCLUDE_DIRS
|
||||||
"../../../src"
|
"../../../src"
|
||||||
"../../../private_include"
|
"../../../private_include"
|
||||||
|
|||||||
@@ -0,0 +1,202 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "bdl_ramdisk.hpp"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
static esp_err_t ramdisk_dev_read(esp_blockdev_handle_t dev_handle, uint8_t* dst_buf, size_t dst_buf_size, uint64_t src_addr, size_t data_read_len)
|
||||||
|
{
|
||||||
|
if (!dev_handle || !dst_buf) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
bdl_ramdisk_ctx_t* ctx = (bdl_ramdisk_ctx_t*)dev_handle->ctx;
|
||||||
|
|
||||||
|
if (dst_buf_size < data_read_len) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src_addr + data_read_len > ctx->total_size) {
|
||||||
|
return ESP_ERR_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check alignment for read_size
|
||||||
|
if (dev_handle->geometry.read_size > 0) {
|
||||||
|
if (src_addr % dev_handle->geometry.read_size != 0 ||
|
||||||
|
data_read_len % dev_handle->geometry.read_size != 0) {
|
||||||
|
return ESP_ERR_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(dst_buf, ctx->data + src_addr, data_read_len);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t ramdisk_dev_write(esp_blockdev_handle_t dev_handle, const uint8_t* src_buf, uint64_t dst_addr, size_t data_write_len)
|
||||||
|
{
|
||||||
|
if (!dev_handle || !src_buf) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev_handle->device_flags.read_only) {
|
||||||
|
return ESP_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
bdl_ramdisk_ctx_t* ctx = (bdl_ramdisk_ctx_t*)dev_handle->ctx;
|
||||||
|
|
||||||
|
if (dst_addr + data_write_len > ctx->total_size) {
|
||||||
|
return ESP_ERR_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check alignment for write_size
|
||||||
|
if (dev_handle->geometry.write_size > 0) {
|
||||||
|
if (dst_addr % dev_handle->geometry.write_size != 0 ||
|
||||||
|
data_write_len % dev_handle->geometry.write_size != 0) {
|
||||||
|
return ESP_ERR_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(ctx->data + dst_addr, src_buf, data_write_len);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t ramdisk_dev_erase(esp_blockdev_handle_t dev_handle, uint64_t start_addr, size_t erase_len)
|
||||||
|
{
|
||||||
|
if (!dev_handle) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev_handle->device_flags.read_only) {
|
||||||
|
return ESP_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
bdl_ramdisk_ctx_t* ctx = (bdl_ramdisk_ctx_t*)dev_handle->ctx;
|
||||||
|
|
||||||
|
if (start_addr + erase_len > ctx->total_size) {
|
||||||
|
return ESP_ERR_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check alignment for erase_size
|
||||||
|
if (dev_handle->geometry.erase_size > 0) {
|
||||||
|
if (start_addr % dev_handle->geometry.erase_size != 0 ||
|
||||||
|
erase_len % dev_handle->geometry.erase_size != 0) {
|
||||||
|
return ESP_ERR_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill with default erase value (0xFF for flash-like behavior)
|
||||||
|
uint8_t erase_value = dev_handle->device_flags.default_val_after_erase ? 0xFF : 0x00;
|
||||||
|
memset(ctx->data + start_addr, erase_value, erase_len);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t ramdisk_dev_sync(esp_blockdev_handle_t dev_handle)
|
||||||
|
{
|
||||||
|
// RAM disk doesn't need sync - all operations are immediate
|
||||||
|
(void)dev_handle;
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t ramdisk_dev_ioctl(esp_blockdev_handle_t dev_handle, const uint8_t cmd, void* args)
|
||||||
|
{
|
||||||
|
if (dev_handle == nullptr || args == nullptr) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case ESP_BLOCKDEV_CMD_MARK_DELETED:
|
||||||
|
case ESP_BLOCKDEV_CMD_ERASE_CONTENTS:
|
||||||
|
// For RAM disk, mark as deleted is equivalent to erase
|
||||||
|
if (args) {
|
||||||
|
esp_blockdev_cmd_arg_erase_t* erase_args = (esp_blockdev_cmd_arg_erase_t*)args;
|
||||||
|
return ramdisk_dev_erase(dev_handle, erase_args->start_addr, erase_args->erase_len);
|
||||||
|
}
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ESP_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t ramdisk_dev_release(esp_blockdev_handle_t dev_handle)
|
||||||
|
{
|
||||||
|
if (!dev_handle) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
bdl_ramdisk_ctx_t* ctx = (bdl_ramdisk_ctx_t*)dev_handle->ctx;
|
||||||
|
if (ctx && ctx->data) {
|
||||||
|
free(ctx->data);
|
||||||
|
}
|
||||||
|
free(ctx);
|
||||||
|
free(dev_handle);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Const operations structure - shared by all instances
|
||||||
|
static const esp_blockdev_ops_t s_bdl_ramdisk_ops = {
|
||||||
|
.read = ramdisk_dev_read,
|
||||||
|
.write = ramdisk_dev_write,
|
||||||
|
.erase = ramdisk_dev_erase,
|
||||||
|
.sync = ramdisk_dev_sync,
|
||||||
|
.ioctl = ramdisk_dev_ioctl,
|
||||||
|
.release = ramdisk_dev_release
|
||||||
|
};
|
||||||
|
|
||||||
|
esp_err_t ramdisk_dev_get_blockdev(esp_blockdev_handle_t* blockdev_handle_out, const size_t total_size, const size_t erase_size)
|
||||||
|
{
|
||||||
|
if (total_size == 0 || erase_size == 0 || total_size % erase_size != 0) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate the block device structure
|
||||||
|
esp_blockdev_t* bdl = (esp_blockdev_t*)calloc(1, sizeof(esp_blockdev_t));
|
||||||
|
if (!bdl) {
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate the context
|
||||||
|
bdl_ramdisk_ctx_t* ctx = (bdl_ramdisk_ctx_t*)calloc(1, sizeof(bdl_ramdisk_ctx_t));
|
||||||
|
if (!ctx) {
|
||||||
|
free(bdl);
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate the RAM storage
|
||||||
|
ctx->data = (uint8_t*)malloc(total_size);
|
||||||
|
if (!ctx->data) {
|
||||||
|
free(ctx);
|
||||||
|
free(bdl);
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize with erased state (0xFF)
|
||||||
|
memset(ctx->data, 0xFF, total_size);
|
||||||
|
|
||||||
|
ctx->total_size = total_size;
|
||||||
|
ctx->erase_size = erase_size;
|
||||||
|
|
||||||
|
// Setup block device structure
|
||||||
|
bdl->ctx = ctx;
|
||||||
|
bdl->ops = &s_bdl_ramdisk_ops;
|
||||||
|
|
||||||
|
// Configure device flags for flash-like behavior
|
||||||
|
ESP_BLOCKDEV_FLAGS_INST_CONFIG_DEFAULT(bdl->device_flags);
|
||||||
|
|
||||||
|
// Configure geometry
|
||||||
|
bdl->geometry.disk_size = total_size;
|
||||||
|
bdl->geometry.read_size = 1; // Can read single bytes
|
||||||
|
bdl->geometry.write_size = 1; // Can write single bytes
|
||||||
|
bdl->geometry.erase_size = erase_size; // Erase block size
|
||||||
|
bdl->geometry.recommended_read_size = 32; // Optimal read size
|
||||||
|
bdl->geometry.recommended_write_size = 32; // Optimal write size
|
||||||
|
bdl->geometry.recommended_erase_size = erase_size;
|
||||||
|
|
||||||
|
*blockdev_handle_out = bdl;
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esp_blockdev.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief RAM disk context structure
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint8_t *data; /*!< Pointer to RAM storage */
|
||||||
|
size_t total_size; /*!< Total size of the RAM disk */
|
||||||
|
size_t erase_size; /*!< Erase block size */
|
||||||
|
} bdl_ramdisk_ctx_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a new RAM disk block device
|
||||||
|
*
|
||||||
|
* @param blockdev_handle_out Pointer to store the created block device handle
|
||||||
|
* @param total_size Total size of the RAM disk in bytes
|
||||||
|
* @param erase_size Erase block size in bytes
|
||||||
|
* @return esp_err_t ESP_OK on success, or an error code on failure
|
||||||
|
*/
|
||||||
|
esp_err_t ramdisk_dev_get_blockdev(esp_blockdev_handle_t* blockdev_handle_out, const size_t total_size, const size_t erase_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Release a RAM disk block device
|
||||||
|
*
|
||||||
|
* @param handle Handle to the RAM disk to release
|
||||||
|
* @return esp_err_t ESP_OK on success
|
||||||
|
*/
|
||||||
|
esp_err_t ramdisk_dev_release(esp_blockdev_handle_t handle);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief C++ wrapper class for RAM disk
|
||||||
|
*/
|
||||||
|
class bdl_ramdisk {
|
||||||
|
public:
|
||||||
|
bdl_ramdisk(const size_t total_size, const size_t erase_size) {
|
||||||
|
handle = nullptr;
|
||||||
|
ramdisk_dev_get_blockdev(&handle, total_size, erase_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
~bdl_ramdisk() {
|
||||||
|
if (handle) {
|
||||||
|
ramdisk_dev_release(handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
operator esp_blockdev_handle_t() const {
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_blockdev_handle_t get_handle() const {
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
esp_blockdev_handle_t handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,584 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sdkconfig.h" // for CONFIG_NVS_BDL_STACK
|
||||||
|
#include <catch2/catch_test_macros.hpp> // for Catch2 test macros
|
||||||
|
#include "test_fixtures.hpp" // for test fixtures class definition
|
||||||
|
#include "nvs_partition.hpp" // for NVSPartition class
|
||||||
|
#include "esp_partition.h" // for BDL and native esp_partition related functions
|
||||||
|
#include "esp_private/partition_linux.h" // for partition_linux functions like statistics and emulated sector size
|
||||||
|
#include <random> // for std::random_device, std::mt19937, std::generate_n
|
||||||
|
#include <fcntl.h> // for open()
|
||||||
|
#include <unistd.h> // for close(), read(), write(), lseek()
|
||||||
|
#include "nvs_constants.h" // for NVS_CONST_PAGE_SIZE
|
||||||
|
#include "esp_log.h" // for ESP_LOGE
|
||||||
|
|
||||||
|
#define TAG "NVSPartitionTestHelper"
|
||||||
|
|
||||||
|
// Initialize the static variable(s) of NVSPartitionTestHelper
|
||||||
|
int NVSPartitionTestHelper::s_instance_count = 0;
|
||||||
|
|
||||||
|
#ifndef CONFIG_NVS_BDL_STACK
|
||||||
|
NVSPartitionTestHelper::NVSPartitionTestHelper(const char *part_name, const bool erase_partition) :
|
||||||
|
// First call to the esp_partition_find_first maps the partition memory
|
||||||
|
nvs::NVSPartition(esp_partition_find_first(
|
||||||
|
ESP_PARTITION_TYPE_DATA,
|
||||||
|
ESP_PARTITION_SUBTYPE_DATA_NVS,
|
||||||
|
part_name))
|
||||||
|
{
|
||||||
|
// Increase the instance count
|
||||||
|
s_instance_count++;
|
||||||
|
|
||||||
|
CHECK(mESPPartition != nullptr);
|
||||||
|
|
||||||
|
// Remember the erase size of the BDL
|
||||||
|
mOriginalEraseSize = ((esp_partition_t*) mESPPartition)->erase_size;
|
||||||
|
|
||||||
|
if(erase_partition)
|
||||||
|
{
|
||||||
|
// erase the partition before testing
|
||||||
|
CHECK(erase_range(0, get_size()) == ESP_OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NVSPartitionTestHelper::~NVSPartitionTestHelper()
|
||||||
|
{
|
||||||
|
// Decrease the instance count
|
||||||
|
s_instance_count--;
|
||||||
|
|
||||||
|
// reset the erase size to the original value
|
||||||
|
set_erase_size(mOriginalEraseSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t NVSPartitionTestHelper::load_from_file(const char *file_name)
|
||||||
|
{
|
||||||
|
return load_from_file(get_partition_name(), file_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t NVSPartitionTestHelper::get_sectors()
|
||||||
|
{
|
||||||
|
return get_size() / NVS_CONST_PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t NVSPartitionTestHelper::set_erase_size(const size_t size)
|
||||||
|
{
|
||||||
|
if(mESPPartition == nullptr) {
|
||||||
|
return ESP_ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
((esp_partition_t*) mESPPartition)->erase_size = size;
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t NVSPartitionTestHelper::get_first_emulated_sector_index()
|
||||||
|
{
|
||||||
|
if (mESPPartition == nullptr) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return ((esp_partition_t*) mESPPartition)->address / ESP_PARTITION_EMULATED_SECTOR_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t NVSPartitionTestHelper::get_sector_erase_count(size_t nvs_sector_index)
|
||||||
|
{
|
||||||
|
// The esp_partition_get_sector_erase_count function is global across all partitions
|
||||||
|
// it's sector index is relative to the emulated flash and the unit of the sector is defined by ESP_PARTITION_EMULATED_SECTOR_SIZE.
|
||||||
|
// nvs_sector_index parameter is the index of the sector in the partition and the unit of the sector is defined by NVS_CONST_PAGE_SIZE.
|
||||||
|
// Therefore, we need to convert the sector index to the emulated flash sector index.
|
||||||
|
if (mESPPartition == nullptr || nvs_sector_index >= get_sectors()) {
|
||||||
|
return 0; // Invalid sector index
|
||||||
|
}
|
||||||
|
// To get the correct sector index, we need to calculate the offset of the first sector
|
||||||
|
size_t first_sector = get_first_emulated_sector_index();
|
||||||
|
size_t emulated_sector_index = (nvs_sector_index * NVS_CONST_PAGE_SIZE) / ESP_PARTITION_EMULATED_SECTOR_SIZE;
|
||||||
|
|
||||||
|
return esp_partition_get_sector_erase_count(emulated_sector_index + first_sector);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static methods to make testing easier
|
||||||
|
|
||||||
|
esp_err_t NVSPartitionTestHelper::randomize_partition(const char *part_name, const uint32_t seed)
|
||||||
|
{
|
||||||
|
// Erase the whole partition before randomizing
|
||||||
|
esp_err_t ret = erase_partition(part_name);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the partition by name
|
||||||
|
const esp_partition_t *part = esp_partition_find_first(
|
||||||
|
ESP_PARTITION_TYPE_DATA,
|
||||||
|
ESP_PARTITION_SUBTYPE_DATA_NVS,
|
||||||
|
part_name);
|
||||||
|
|
||||||
|
if (part == nullptr) {
|
||||||
|
return ESP_ERR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::random_device rd;
|
||||||
|
std::mt19937 gen(rd());
|
||||||
|
gen.seed(seed);
|
||||||
|
|
||||||
|
uint8_t buf[NVS_CONST_PAGE_SIZE];
|
||||||
|
|
||||||
|
// loop over all sectors in the partition
|
||||||
|
// and fill them with random data
|
||||||
|
for (uint32_t i = 0; i < part->size / NVS_CONST_PAGE_SIZE; i++)
|
||||||
|
{
|
||||||
|
// fill the buffer with random data
|
||||||
|
std::generate_n(buf, NVS_CONST_PAGE_SIZE, gen);
|
||||||
|
|
||||||
|
ret = esp_partition_write(part, i * NVS_CONST_PAGE_SIZE, buf, NVS_CONST_PAGE_SIZE);
|
||||||
|
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Erase the whole partition
|
||||||
|
esp_err_t NVSPartitionTestHelper::erase_partition(const char *part_name)
|
||||||
|
{
|
||||||
|
// Find the partition by name
|
||||||
|
const esp_partition_t *part = esp_partition_find_first(
|
||||||
|
ESP_PARTITION_TYPE_DATA,
|
||||||
|
ESP_PARTITION_SUBTYPE_DATA_NVS,
|
||||||
|
part_name);
|
||||||
|
|
||||||
|
if (part == nullptr) {
|
||||||
|
return ESP_ERR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
// Erase the whole partition
|
||||||
|
return esp_partition_erase_range(part, 0, part->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get number of NVS sectors in the partition
|
||||||
|
uint32_t NVSPartitionTestHelper::get_sectors(const char *part_name)
|
||||||
|
{
|
||||||
|
// Find the partition by name
|
||||||
|
const esp_partition_t *part = esp_partition_find_first(
|
||||||
|
ESP_PARTITION_TYPE_DATA,
|
||||||
|
ESP_PARTITION_SUBTYPE_DATA_NVS,
|
||||||
|
part_name);
|
||||||
|
|
||||||
|
if (part == nullptr) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return part->size / NVS_CONST_PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the partition from a file
|
||||||
|
esp_err_t NVSPartitionTestHelper::load_from_file(const char *part_name, const char *file_name)
|
||||||
|
{
|
||||||
|
// Find the partition by name
|
||||||
|
const esp_partition_t *part = esp_partition_find_first(
|
||||||
|
ESP_PARTITION_TYPE_DATA,
|
||||||
|
ESP_PARTITION_SUBTYPE_DATA_NVS,
|
||||||
|
part_name);
|
||||||
|
|
||||||
|
if (part == nullptr) {
|
||||||
|
return ESP_ERR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the partition from file
|
||||||
|
int file_fd = open(file_name, O_RDONLY);
|
||||||
|
if (file_fd == -1) {
|
||||||
|
return ESP_ERR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t size = lseek(file_fd, 0L, SEEK_END);
|
||||||
|
if (size < 0) {
|
||||||
|
close(file_fd);
|
||||||
|
return ESP_ERR_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if file fits into the partition
|
||||||
|
if (size > part->size) {
|
||||||
|
close(file_fd);
|
||||||
|
return ESP_ERR_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *p_buff = malloc((size_t)size);
|
||||||
|
if (p_buff == nullptr) {
|
||||||
|
close(file_fd);
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
lseek(file_fd, 0L, SEEK_SET);
|
||||||
|
ssize_t read_size = ::read(file_fd, p_buff, size);
|
||||||
|
close(file_fd);
|
||||||
|
|
||||||
|
if (read_size != size) {
|
||||||
|
free(p_buff);
|
||||||
|
return ESP_ERR_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t ret = esp_partition_erase_range(part, 0, part->size);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
free(p_buff);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = esp_partition_write(part, 0, p_buff, size);
|
||||||
|
free(p_buff);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NVSPartitionTestHelper::clear_stats(void)
|
||||||
|
{
|
||||||
|
return esp_partition_clear_stats();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t NVSPartitionTestHelper::get_read_ops(void)
|
||||||
|
{
|
||||||
|
return esp_partition_get_read_ops();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t NVSPartitionTestHelper::get_write_ops(void)
|
||||||
|
{
|
||||||
|
return esp_partition_get_write_ops();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t NVSPartitionTestHelper::get_erase_ops(void)
|
||||||
|
{
|
||||||
|
return esp_partition_get_erase_ops();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t NVSPartitionTestHelper::get_read_bytes(void)
|
||||||
|
{
|
||||||
|
return esp_partition_get_read_bytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t NVSPartitionTestHelper::get_write_bytes(void)
|
||||||
|
{
|
||||||
|
return esp_partition_get_write_bytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t NVSPartitionTestHelper::get_total_time(void)
|
||||||
|
{
|
||||||
|
return esp_partition_get_total_time();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NVSPartitionTestHelper::fail_after(size_t count, uint8_t mode)
|
||||||
|
{
|
||||||
|
esp_partition_fail_after(count, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // CONFIG_NVS_BDL_STACK
|
||||||
|
// BDL implementation of NVSPartitionTestHelper
|
||||||
|
NVSPartitionTestHelper::NVSPartitionTestHelper(const char *part_name, const bool erase_partition) :
|
||||||
|
// Call parent constructor with non-zero though invalid pointer to BDL handle, we will retrieve the correct one later
|
||||||
|
nvs::NVSPartition(part_name, (esp_blockdev_handle_t)0x1 , false)
|
||||||
|
{
|
||||||
|
// Retrieve the BDL handle for the partition
|
||||||
|
esp_err_t err = esp_partition_get_blockdev(
|
||||||
|
ESP_PARTITION_TYPE_DATA,
|
||||||
|
ESP_PARTITION_SUBTYPE_DATA_NVS,
|
||||||
|
part_name,
|
||||||
|
&mBDL);
|
||||||
|
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "Failed to get BDL handle for NVS partition %s: %s", part_name, esp_err_to_name(err));
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK(mBDL != nullptr);
|
||||||
|
|
||||||
|
// Increase the instance count
|
||||||
|
s_instance_count++;
|
||||||
|
|
||||||
|
// Remember the erase size of the BDL
|
||||||
|
mOriginalEraseSize = mBDL->geometry.erase_size;
|
||||||
|
|
||||||
|
if(erase_partition)
|
||||||
|
{
|
||||||
|
// erase the partition before testing
|
||||||
|
CHECK(erase_range(0, get_size()) == ESP_OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NVSPartitionTestHelper::~NVSPartitionTestHelper()
|
||||||
|
{
|
||||||
|
// reset the erase size to the original value
|
||||||
|
set_erase_size(mOriginalEraseSize);
|
||||||
|
|
||||||
|
// Decrease the instance count
|
||||||
|
s_instance_count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t NVSPartitionTestHelper::load_from_file(const char *file_name)
|
||||||
|
{
|
||||||
|
return load_from_file(get_partition_name(), file_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t NVSPartitionTestHelper::get_sectors()
|
||||||
|
{
|
||||||
|
return get_size() / NVS_CONST_PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t NVSPartitionTestHelper::set_erase_size(const size_t size)
|
||||||
|
{
|
||||||
|
// Set the new erase size in the BDL geometry
|
||||||
|
mBDL->geometry.erase_size = size;
|
||||||
|
|
||||||
|
// We have to set also the erase size in the esp_partition_t structure
|
||||||
|
const esp_partition_t* part = esp_partition_find_first(
|
||||||
|
ESP_PARTITION_TYPE_DATA,
|
||||||
|
ESP_PARTITION_SUBTYPE_DATA_NVS,
|
||||||
|
get_partition_name());
|
||||||
|
|
||||||
|
if(part != nullptr) {
|
||||||
|
((esp_partition_t*)part)->erase_size = size;
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_ERR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t NVSPartitionTestHelper::get_first_emulated_sector_index()
|
||||||
|
{
|
||||||
|
// TODO: Change this implementation to reflect the concept of sectors counting for statistics once it is
|
||||||
|
// implemented in BDL.
|
||||||
|
|
||||||
|
// Current implementation assumes the esp_partition API and it's linux implementation evaluates statistics
|
||||||
|
// based on the emulated flash sectors, which are defined by ESP_PARTITION_EMULATED_SECTOR_SIZE.
|
||||||
|
// In order to evaluate the statistics correctly, we need to return index of the first sector number this
|
||||||
|
// partition resides in the emulated flash.
|
||||||
|
|
||||||
|
const esp_partition_t* part = esp_partition_find_first(
|
||||||
|
ESP_PARTITION_TYPE_DATA,
|
||||||
|
ESP_PARTITION_SUBTYPE_DATA_NVS,
|
||||||
|
get_partition_name());
|
||||||
|
|
||||||
|
CHECK(part != nullptr);
|
||||||
|
|
||||||
|
return part->address / ESP_PARTITION_EMULATED_SECTOR_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t NVSPartitionTestHelper::get_sector_erase_count(size_t nvs_sector_index)
|
||||||
|
{
|
||||||
|
// TODO: Once BDL implementation supports sector erase count tracking, we will need to re-implement
|
||||||
|
|
||||||
|
// The esp_partition_get_sector_erase_count function is global across all partitions
|
||||||
|
// it's sector index is relative to the emulated flash and the unit of the sector is defined by ESP_PARTITION_EMULATED_SECTOR_SIZE.
|
||||||
|
// nvs_sector_index parameter is the index of the sector in the partition and the unit of the sector is defined by NVS_CONST_PAGE_SIZE.
|
||||||
|
// Therefore, we need to convert the sector index to the emulated flash sector index.
|
||||||
|
|
||||||
|
CHECK(nvs_sector_index < get_sectors());
|
||||||
|
|
||||||
|
// The statistics are based on the emulated flash sectors, which are defined by ESP_PARTITION_EMULATED_SECTOR_SIZE.
|
||||||
|
// Therefore, we need to convert the sector index to the emulated flash sector index.
|
||||||
|
|
||||||
|
// Get the first sector index of the partition in the emulated flash
|
||||||
|
size_t first_sector = get_first_emulated_sector_index();
|
||||||
|
|
||||||
|
// Calculate the emulated sector index based on the NVS sector index (the unis are defined by NVS_CONST_PAGE_SIZE)
|
||||||
|
size_t emulated_sector_index = (nvs_sector_index * NVS_CONST_PAGE_SIZE) / ESP_PARTITION_EMULATED_SECTOR_SIZE;
|
||||||
|
|
||||||
|
// Call the esp_partition_get_sector_erase_count function with the emulated sector index
|
||||||
|
return esp_partition_get_sector_erase_count(emulated_sector_index + first_sector);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static methods to make testing easier
|
||||||
|
|
||||||
|
esp_err_t NVSPartitionTestHelper::randomize_partition(const char *part_name, const uint32_t seed)
|
||||||
|
{
|
||||||
|
// Erase the whole partition before randomizing
|
||||||
|
esp_err_t ret = erase_partition(part_name);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_blockdev_handle_t bdl_handle;
|
||||||
|
|
||||||
|
// get the BDL handle for the partition
|
||||||
|
ret = esp_partition_get_blockdev(
|
||||||
|
ESP_PARTITION_TYPE_DATA,
|
||||||
|
ESP_PARTITION_SUBTYPE_DATA_NVS,
|
||||||
|
part_name,
|
||||||
|
&bdl_handle);
|
||||||
|
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::random_device rd;
|
||||||
|
std::mt19937 gen(rd());
|
||||||
|
gen.seed(seed);
|
||||||
|
|
||||||
|
uint8_t buf[NVS_CONST_PAGE_SIZE];
|
||||||
|
|
||||||
|
// loop over all sectors in the partition
|
||||||
|
// and fill them with random data
|
||||||
|
for (uint32_t i = 0; i < bdl_handle->geometry.disk_size / NVS_CONST_PAGE_SIZE; i++)
|
||||||
|
{
|
||||||
|
// fill the buffer with random data
|
||||||
|
std::generate_n(buf, NVS_CONST_PAGE_SIZE, gen);
|
||||||
|
|
||||||
|
// Write the random data to the partition using the BDL handle
|
||||||
|
ret = bdl_handle->ops->write(bdl_handle, buf, i * NVS_CONST_PAGE_SIZE, NVS_CONST_PAGE_SIZE);
|
||||||
|
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Erase the whole partition
|
||||||
|
esp_err_t NVSPartitionTestHelper::erase_partition(const char *part_name)
|
||||||
|
{
|
||||||
|
// get the BDL handle for the partition
|
||||||
|
esp_blockdev_handle_t bdl_handle;
|
||||||
|
|
||||||
|
esp_err_t ret = esp_partition_get_blockdev(
|
||||||
|
ESP_PARTITION_TYPE_DATA,
|
||||||
|
ESP_PARTITION_SUBTYPE_DATA_NVS,
|
||||||
|
part_name,
|
||||||
|
&bdl_handle);
|
||||||
|
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Erase the whole partition
|
||||||
|
return bdl_handle->ops->erase(bdl_handle, 0, bdl_handle->geometry.disk_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get number of NVS sectors in the partition
|
||||||
|
uint32_t NVSPartitionTestHelper::get_sectors(const char *part_name)
|
||||||
|
{
|
||||||
|
// get the BDL handle for the partition
|
||||||
|
esp_blockdev_handle_t bdl_handle;
|
||||||
|
|
||||||
|
esp_err_t ret = esp_partition_get_blockdev(
|
||||||
|
ESP_PARTITION_TYPE_DATA,
|
||||||
|
ESP_PARTITION_SUBTYPE_DATA_NVS,
|
||||||
|
part_name,
|
||||||
|
&bdl_handle);
|
||||||
|
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bdl_handle->geometry.disk_size / NVS_CONST_PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the partition from a file
|
||||||
|
esp_err_t NVSPartitionTestHelper::load_from_file(const char *part_name, const char *file_name)
|
||||||
|
{
|
||||||
|
// get the BDL handle for the partition
|
||||||
|
esp_blockdev_handle_t bdl_handle;
|
||||||
|
|
||||||
|
esp_err_t ret = esp_partition_get_blockdev(
|
||||||
|
ESP_PARTITION_TYPE_DATA,
|
||||||
|
ESP_PARTITION_SUBTYPE_DATA_NVS,
|
||||||
|
part_name,
|
||||||
|
&bdl_handle);
|
||||||
|
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the partition from file
|
||||||
|
int file_fd = open(file_name, O_RDONLY);
|
||||||
|
if (file_fd == -1) {
|
||||||
|
return ESP_ERR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t size = lseek(file_fd, 0L, SEEK_END);
|
||||||
|
if (size < 0) {
|
||||||
|
close(file_fd);
|
||||||
|
return ESP_ERR_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if file fits into the partition
|
||||||
|
if (size > bdl_handle->geometry.disk_size) {
|
||||||
|
close(file_fd);
|
||||||
|
return ESP_ERR_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *p_buff = malloc((size_t)size);
|
||||||
|
if (p_buff == nullptr) {
|
||||||
|
close(file_fd);
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
lseek(file_fd, 0L, SEEK_SET);
|
||||||
|
ssize_t read_size = ::read(file_fd, p_buff, size);
|
||||||
|
close(file_fd);
|
||||||
|
|
||||||
|
if (read_size != size) {
|
||||||
|
free(p_buff);
|
||||||
|
return ESP_ERR_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = erase_partition(part_name);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
free(p_buff);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = bdl_handle->ops->write(bdl_handle, (const uint8_t*) p_buff, 0, size);
|
||||||
|
free(p_buff);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NVSPartitionTestHelper::clear_stats(void)
|
||||||
|
{
|
||||||
|
// TODO: Once BDL implementation supports statistics, we will need to re-implement this function
|
||||||
|
|
||||||
|
return esp_partition_clear_stats();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t NVSPartitionTestHelper::get_read_ops(void)
|
||||||
|
{
|
||||||
|
// TODO: Once BDL implementation supports statistics, we will need to re-implement this function
|
||||||
|
|
||||||
|
return esp_partition_get_read_ops();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t NVSPartitionTestHelper::get_write_ops(void)
|
||||||
|
{
|
||||||
|
// TODO: Once BDL implementation supports statistics, we will need to re-implement this function
|
||||||
|
|
||||||
|
return esp_partition_get_write_ops();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t NVSPartitionTestHelper::get_erase_ops(void)
|
||||||
|
{
|
||||||
|
// TODO: Once BDL implementation supports statistics, we will need to re-implement this function
|
||||||
|
|
||||||
|
return esp_partition_get_erase_ops();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t NVSPartitionTestHelper::get_read_bytes(void)
|
||||||
|
{
|
||||||
|
// TODO: Once BDL implementation supports statistics, we will need to re-implement this function
|
||||||
|
return esp_partition_get_read_bytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t NVSPartitionTestHelper::get_write_bytes(void)
|
||||||
|
{
|
||||||
|
// TODO: Once BDL implementation supports statistics, we will need to re-implement this function
|
||||||
|
|
||||||
|
return esp_partition_get_write_bytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t NVSPartitionTestHelper::get_total_time(void)
|
||||||
|
{
|
||||||
|
// TODO: Once BDL implementation supports statistics, we will need to re-implement this function
|
||||||
|
|
||||||
|
return esp_partition_get_total_time();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NVSPartitionTestHelper::fail_after(size_t count, uint8_t mode)
|
||||||
|
{
|
||||||
|
// TODO: Once BDL implementation supports programmed failures, we will need to re-implement this function
|
||||||
|
|
||||||
|
esp_partition_fail_after(count, mode);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -1,206 +1,75 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
#include "nvs_partition.hpp"
|
|
||||||
#include "esp_private/partition_linux.h"
|
|
||||||
#include "nvs.h"
|
|
||||||
#include <random>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include "esp_partition.h"
|
|
||||||
|
|
||||||
class PartitionEmulationFixture {
|
#pragma once
|
||||||
|
|
||||||
|
#include "nvs_partition.hpp" // for NVSPartition class
|
||||||
|
#include "esp_err.h" // for esp_err_t
|
||||||
|
#include "esp_private/partition_linux.h" // for constants of the fail_after() ESP_PARTITION_FAIL_AFTER_MODE_BOTH
|
||||||
|
|
||||||
|
class NVSPartitionTestHelper : public nvs::NVSPartition {
|
||||||
public:
|
public:
|
||||||
PartitionEmulationFixture( uint32_t start_sector = 0,
|
// Constructor uses esp_partition API to initialize the partition
|
||||||
uint32_t sector_size = 1,
|
// Parameters:
|
||||||
const char *partition_name = NVS_DEFAULT_PART_NAME) :
|
// - part_name: name of the partition to be used for testing
|
||||||
esp_partition()
|
// - erase_partition: if true, the partition will be erased before testing
|
||||||
{
|
NVSPartitionTestHelper(const char *part_name, const bool erase_partition = true);
|
||||||
|
|
||||||
if (esp_partition_file_mmap((const uint8_t **) &p_part_desc_addr_start) != ESP_OK) {
|
// Destructor decreases the instance count
|
||||||
FAIL("Failed to initialize esp_partition_file_mmap");
|
// and unmaps the partition memory if this is the last instance
|
||||||
}
|
virtual ~NVSPartitionTestHelper();
|
||||||
|
|
||||||
const uint32_t sec_size = esp_partition_get_main_flash_sector_size();
|
// Load the partition from a file
|
||||||
esp_partition.address = start_sector * sec_size;
|
esp_err_t load_from_file(const char *file_name);
|
||||||
esp_partition.size = (start_sector + sector_size) * sec_size;
|
|
||||||
esp_partition.erase_size = ESP_PARTITION_EMULATED_SECTOR_SIZE;
|
|
||||||
esp_partition.type = ESP_PARTITION_TYPE_DATA;
|
|
||||||
esp_partition.subtype = ESP_PARTITION_SUBTYPE_DATA_NVS;
|
|
||||||
strncpy(esp_partition.label, partition_name, NVS_PART_NAME_MAX_SIZE);
|
|
||||||
p_part = new (std::nothrow) nvs::NVSPartition(&esp_partition);
|
|
||||||
REQUIRE(p_part != nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// initializes the partition and loads partition binary file into it
|
// Return the number of NVS sectors in the partition
|
||||||
PartitionEmulationFixture( uint32_t start_sector,
|
uint32_t get_sectors();
|
||||||
uint32_t sector_size,
|
|
||||||
const char *partition_name,
|
|
||||||
const char *partition_binary) : PartitionEmulationFixture(start_sector, sector_size, partition_name)
|
|
||||||
{
|
|
||||||
int file_fd = -1;
|
|
||||||
off_t size = -1;
|
|
||||||
void *p_buff = nullptr;
|
|
||||||
char const *fail_msg = nullptr;
|
|
||||||
const uint32_t sec_size = esp_partition_get_main_flash_sector_size();
|
|
||||||
|
|
||||||
do {
|
// Overrides the erase size to the specified size
|
||||||
// get file size
|
esp_err_t set_erase_size(const size_t size);
|
||||||
file_fd = open(partition_binary, O_RDONLY);
|
|
||||||
if (file_fd == -1) {
|
|
||||||
fail_msg = "Failed to open file with partition content";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
size = lseek(file_fd, 0L, SEEK_END);
|
|
||||||
if (size < 0) {
|
|
||||||
fail_msg = "failed to seek in file with partition content";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if file fits into the partitiion
|
// Function returns the starting sector index of the partition in the emulated flash
|
||||||
if (size > sector_size * sec_size) {
|
// The size of emulated sector is defined by ESP_PARTITION_EMULATED_SECTOR_SIZE
|
||||||
fail_msg = "file with partition content doesn't fit into the partition";
|
// First emulated sector of the partition is any number, it depends on the partition location
|
||||||
break;
|
// in the emulated flash
|
||||||
}
|
size_t get_first_emulated_sector_index();
|
||||||
|
|
||||||
// allocate local buffer
|
// Get the erase count of a specific NVS sector within the partition
|
||||||
p_buff = malloc((size_t) size);
|
// The size of NVS sector is defined by NVS_CONST_PAGE_SIZE
|
||||||
if (p_buff == nullptr) {
|
// First sector index is 0
|
||||||
fail_msg = "unable to allocate buffer for reading file with partition content";
|
size_t get_sector_erase_count(size_t nvs_sector_index);
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// laoad file into local buffer
|
//--------------- Static helper methods to make testing easier --------------------------
|
||||||
int res = lseek(file_fd, 0L, SEEK_SET);
|
|
||||||
if (res < 0) {
|
|
||||||
fail_msg = "failed to seek in file with partition content";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
size = read(file_fd, p_buff, size);
|
|
||||||
if (size < 0) {
|
|
||||||
fail_msg = "cannot read file with partition content";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// erase whole partition
|
// Randomize the whole partition with a given seed
|
||||||
if (ESP_OK != esp_partition_erase_range(&esp_partition, 0, sector_size * sec_size)) {
|
static esp_err_t randomize_partition(const char *part_name, const uint32_t seed);
|
||||||
fail_msg = "cannot erase partition prior to write partition binary from file";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// write local buffer to the partition
|
// Erase the whole partition
|
||||||
if (ESP_OK != esp_partition_write_raw(&esp_partition, 0, p_buff, size)) {
|
static esp_err_t erase_partition(const char *part_name);
|
||||||
fail_msg = "cannot write to the partition";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (false);
|
|
||||||
|
|
||||||
// close file
|
// Get number of NVS sectors in the partition
|
||||||
if (file_fd >= 0) {
|
static uint32_t get_sectors(const char *part_name);
|
||||||
close(file_fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
// deallocate buffer
|
// Load the partition from a file
|
||||||
if (p_buff != nullptr) {
|
static esp_err_t load_from_file(const char *part_name, const char *file_name);
|
||||||
free(p_buff);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(fail_msg != nullptr) {
|
// Set of functions to access partition statistics
|
||||||
FAIL(fail_msg);
|
// At the moment these functions are global, it means that they do not distinguish between
|
||||||
}
|
// different partitions
|
||||||
}
|
// Be aware that host tests mixing multiple partitions
|
||||||
|
// will not work correctly, as the statistics will be summed up for all partitions
|
||||||
void randomize(uint32_t seed)
|
static void clear_stats(void);
|
||||||
{
|
static size_t get_read_ops(void);
|
||||||
std::random_device rd;
|
static size_t get_write_ops(void);
|
||||||
std::mt19937 gen(rd());
|
static size_t get_erase_ops(void);
|
||||||
gen.seed(seed);
|
static size_t get_read_bytes(void);
|
||||||
|
static size_t get_write_bytes(void);
|
||||||
esp_partition_file_mmap_ctrl_t *p_ctrl = esp_partition_get_file_mmap_ctrl_act();
|
static size_t get_total_time(void);
|
||||||
REQUIRE(p_ctrl != nullptr);
|
static void fail_after(size_t count, uint8_t mode);
|
||||||
std::generate_n(p_part_desc_addr_start, p_ctrl->flash_file_size, gen);
|
private:
|
||||||
}
|
static int s_instance_count; // Static variable to track instance count
|
||||||
|
size_t mOriginalEraseSize; // Erase size of the Partition at the moment of the object creation
|
||||||
// absolute sectorNumber is used here
|
|
||||||
bool erase(size_t sectorNumber)
|
|
||||||
{
|
|
||||||
const uint32_t sec_size = esp_partition_get_main_flash_sector_size();
|
|
||||||
size_t offset = sectorNumber * sec_size;
|
|
||||||
|
|
||||||
// check the upper bound
|
|
||||||
esp_partition_file_mmap_ctrl_t *p_ctrl = esp_partition_get_file_mmap_ctrl_act();
|
|
||||||
REQUIRE(p_ctrl != nullptr);
|
|
||||||
if (offset > p_ctrl->flash_file_size) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// esp_partition_erase_range uses offset relative to the beginning of partition
|
|
||||||
return (esp_partition_erase_range(&esp_partition,
|
|
||||||
offset - esp_partition.address,
|
|
||||||
sec_size) == ESP_OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
~PartitionEmulationFixture()
|
|
||||||
{
|
|
||||||
delete p_part;
|
|
||||||
|
|
||||||
// ensure underlying mapped file gets deleted after unmap.
|
|
||||||
esp_partition_file_mmap_ctrl_t *p_ctrl = esp_partition_get_file_mmap_ctrl_input();
|
|
||||||
p_ctrl->remove_dump = true;
|
|
||||||
esp_partition_file_munmap();
|
|
||||||
}
|
|
||||||
|
|
||||||
nvs::NVSPartition *part()
|
|
||||||
{
|
|
||||||
return p_part;
|
|
||||||
}
|
|
||||||
|
|
||||||
const esp_partition_t *get_esp_partition() const
|
|
||||||
{
|
|
||||||
return &esp_partition;
|
|
||||||
}
|
|
||||||
|
|
||||||
nvs::NVSPartition *p_part;
|
|
||||||
esp_partition_t esp_partition;
|
|
||||||
uint8_t *p_part_desc_addr_start;
|
|
||||||
};
|
|
||||||
|
|
||||||
// fixture with 2 partitions
|
|
||||||
class PartitionEmulationFixture2 : public PartitionEmulationFixture {
|
|
||||||
public:
|
|
||||||
PartitionEmulationFixture2( uint32_t start_sector1 = 0,
|
|
||||||
uint32_t sector_size1 = 1,
|
|
||||||
const char *partition_name1 = "nvs1",
|
|
||||||
uint32_t start_sector2 = 1,
|
|
||||||
uint32_t sector_size2 = 1,
|
|
||||||
const char *partition_name2 = "nvs2"
|
|
||||||
) :
|
|
||||||
PartitionEmulationFixture(start_sector1, sector_size1, partition_name1), esp_partition2()
|
|
||||||
{
|
|
||||||
const uint32_t sec_size = esp_partition_get_main_flash_sector_size();
|
|
||||||
// for 2nd partition
|
|
||||||
esp_partition2.address = start_sector2 * sec_size;
|
|
||||||
esp_partition2.size = (start_sector2 + sector_size2) * sec_size;
|
|
||||||
esp_partition2.erase_size = ESP_PARTITION_EMULATED_SECTOR_SIZE;
|
|
||||||
esp_partition2.type = ESP_PARTITION_TYPE_DATA;
|
|
||||||
esp_partition2.subtype = ESP_PARTITION_SUBTYPE_DATA_NVS;
|
|
||||||
strncpy(esp_partition2.label, partition_name2, NVS_PART_NAME_MAX_SIZE);
|
|
||||||
p_part2 = new (std::nothrow) nvs::NVSPartition(&esp_partition2);
|
|
||||||
REQUIRE(p_part2 != nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
~PartitionEmulationFixture2()
|
|
||||||
{
|
|
||||||
delete p_part2;
|
|
||||||
}
|
|
||||||
|
|
||||||
nvs::NVSPartition *part2()
|
|
||||||
{
|
|
||||||
return p_part2;
|
|
||||||
}
|
|
||||||
|
|
||||||
nvs::NVSPartition *p_part2;
|
|
||||||
esp_partition_t esp_partition2;
|
|
||||||
};
|
};
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,49 +1,51 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
#include <algorithm>
|
#include "nvs_flash.h"
|
||||||
#include <cstring>
|
|
||||||
#include "nvs_handle_simple.hpp"
|
#include "nvs_handle_simple.hpp"
|
||||||
#include "nvs_partition_manager.hpp"
|
#include "nvs_partition_manager.hpp"
|
||||||
#include "test_fixtures.hpp"
|
|
||||||
#include <iostream>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
#define TEST_DEFAULT_PARTITION_NAME "nvs"
|
||||||
|
|
||||||
TEST_CASE("NVSHandleSimple CXX api open invalid arguments", "[nvs cxx]")
|
TEST_CASE("NVSHandleSimple CXX api open invalid arguments", "[nvs cxx]")
|
||||||
{
|
{
|
||||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
// Test case for invalid arguments in open_nvs_handle_from_partition
|
||||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
// Combination of nullptr partition name and namespace name
|
||||||
PartitionEmulationFixture f(0, 10, "test");
|
|
||||||
esp_err_t result;
|
esp_err_t result;
|
||||||
shared_ptr<nvs::NVSHandle> handle;
|
shared_ptr<nvs::NVSHandle> handle;
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->
|
// Init the default partition
|
||||||
init_custom(f.part(), NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK);
|
REQUIRE(nvs_flash_init_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
handle = nvs::open_nvs_handle_from_partition(nullptr, "ns_1", NVS_READWRITE, &result);
|
handle = nvs::open_nvs_handle_from_partition(nullptr, "ns_1", NVS_READWRITE, &result);
|
||||||
CHECK(result == ESP_ERR_INVALID_ARG);
|
CHECK(result == ESP_ERR_INVALID_ARG);
|
||||||
CHECK(!handle);
|
CHECK(!handle);
|
||||||
|
|
||||||
handle = nvs::open_nvs_handle_from_partition("test", nullptr, NVS_READWRITE, &result);
|
handle = nvs::open_nvs_handle_from_partition(TEST_DEFAULT_PARTITION_NAME, nullptr, NVS_READWRITE, &result);
|
||||||
CHECK(result == ESP_ERR_INVALID_ARG);
|
CHECK(result == ESP_ERR_INVALID_ARG);
|
||||||
CHECK(!handle);
|
CHECK(!handle);
|
||||||
|
|
||||||
nvs::NVSPartitionManager::get_instance()->deinit_partition("test");
|
nvs_flash_deinit_partition(TEST_DEFAULT_PARTITION_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("NVSHandleSimple CXX api open partition uninitialized", "[nvs cxx]")
|
TEST_CASE("NVSHandleSimple CXX api open partition uninitialized", "[nvs cxx]")
|
||||||
{
|
{
|
||||||
uint8_t *p_part_desc_addr_start;
|
// Negative TC for opening a handle from a partition that has not been initialized
|
||||||
CHECK(esp_partition_file_mmap((const uint8_t **)&p_part_desc_addr_start) == ESP_OK);
|
|
||||||
|
|
||||||
esp_err_t result;
|
esp_err_t result;
|
||||||
shared_ptr<nvs::NVSHandle> handle;
|
shared_ptr<nvs::NVSHandle> handle;
|
||||||
|
|
||||||
handle = nvs::open_nvs_handle_from_partition("test", "ns_1", NVS_READWRITE, &result);
|
handle = nvs::open_nvs_handle_from_partition(TEST_DEFAULT_PARTITION_NAME, "ns_1", NVS_READWRITE, &result);
|
||||||
bool result_expected = result == ESP_ERR_NVS_NOT_INITIALIZED || result == ESP_ERR_NVS_PART_NOT_FOUND;
|
bool result_expected = result == ESP_ERR_NVS_NOT_INITIALIZED || result == ESP_ERR_NVS_PART_NOT_FOUND;
|
||||||
CHECK(result_expected);
|
CHECK(result_expected);
|
||||||
CHECK(!handle);
|
CHECK(!handle);
|
||||||
@@ -51,18 +53,20 @@ TEST_CASE("NVSHandleSimple CXX api open partition uninitialized", "[nvs cxx]")
|
|||||||
|
|
||||||
TEST_CASE("NVSHandleSimple CXX api open successful", "[nvs cxx]")
|
TEST_CASE("NVSHandleSimple CXX api open successful", "[nvs cxx]")
|
||||||
{
|
{
|
||||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
// Positive TC for opening a handle using open_nvs_handle_from_partition from an initialized partition
|
||||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
|
||||||
PartitionEmulationFixture f(0, 10, "test");
|
|
||||||
esp_err_t result;
|
esp_err_t result;
|
||||||
shared_ptr<nvs::NVSHandle> handle;
|
shared_ptr<nvs::NVSHandle> handle;
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
// Erase the partition to ensure it is clean
|
||||||
== ESP_OK);
|
REQUIRE(nvs_flash_erase_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
|
// Init the default partition
|
||||||
|
REQUIRE(nvs_flash_init_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||||
|
|
||||||
handle = nvs::open_nvs_handle_from_partition("test", "ns_1", NVS_READWRITE, &result);
|
handle = nvs::open_nvs_handle_from_partition(TEST_DEFAULT_PARTITION_NAME, "ns_1", NVS_READWRITE, &result);
|
||||||
CHECK(result == ESP_OK);
|
CHECK(result == ESP_OK);
|
||||||
CHECK(handle);
|
CHECK(handle);
|
||||||
|
|
||||||
@@ -72,23 +76,27 @@ TEST_CASE("NVSHandleSimple CXX api open successful", "[nvs cxx]")
|
|||||||
|
|
||||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||||
|
|
||||||
nvs::NVSPartitionManager::get_instance()->deinit_partition("test");
|
nvs_flash_deinit_partition(TEST_DEFAULT_PARTITION_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("NVSHandleSimple CXX api open default part successful", "[nvs cxx]")
|
TEST_CASE("NVSHandleSimple CXX api open default part successful", "[nvs cxx]")
|
||||||
{
|
{
|
||||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
// Positive TC for opening a handle using open_nvs_handle from an initialized default partition
|
||||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
|
||||||
PartitionEmulationFixture f(0, 10);
|
|
||||||
esp_err_t result;
|
esp_err_t result;
|
||||||
shared_ptr<nvs::NVSHandle> handle;
|
shared_ptr<nvs::NVSHandle> handle;
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
// Erase the partition to ensure it is clean
|
||||||
== ESP_OK);
|
REQUIRE(nvs_flash_erase_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
|
// Init the default partition
|
||||||
|
REQUIRE(nvs_flash_init_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||||
|
|
||||||
handle = nvs::open_nvs_handle("ns_1", NVS_READWRITE, &result);
|
// Open handle without specifying partition name
|
||||||
|
// This should open the default partition "nvs"
|
||||||
|
handle = nvs::open_nvs_handle_from_partition(TEST_DEFAULT_PARTITION_NAME, "ns_1", NVS_READWRITE, &result);
|
||||||
CHECK(result == ESP_OK);
|
CHECK(result == ESP_OK);
|
||||||
CHECK(handle);
|
CHECK(handle);
|
||||||
|
|
||||||
@@ -98,46 +106,50 @@ TEST_CASE("NVSHandleSimple CXX api open default part successful", "[nvs cxx]")
|
|||||||
|
|
||||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||||
|
|
||||||
nvs::NVSPartitionManager::get_instance()->deinit_partition("nvs");
|
nvs_flash_deinit_partition(TEST_DEFAULT_PARTITION_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("NVSHandleSimple CXX api open default part ns NULL", "[nvs cxx]")
|
TEST_CASE("NVSHandleSimple CXX api open default part ns NULL", "[nvs cxx]")
|
||||||
{
|
{
|
||||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
// Negative TC for opening a handle using open_nvs_handle from a partition name specified as nullptr
|
||||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
|
||||||
PartitionEmulationFixture f(0, 10);
|
|
||||||
esp_err_t result;
|
esp_err_t result;
|
||||||
shared_ptr<nvs::NVSHandle> handle;
|
shared_ptr<nvs::NVSHandle> handle;
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
// Erase the partition to ensure it is clean
|
||||||
== ESP_OK);
|
REQUIRE(nvs_flash_erase_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
|
// Init the default partition
|
||||||
|
REQUIRE(nvs_flash_init_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||||
|
|
||||||
handle = nvs::open_nvs_handle(nullptr, NVS_READWRITE, &result);
|
handle = nvs::open_nvs_handle_from_partition(TEST_DEFAULT_PARTITION_NAME, nullptr, NVS_READWRITE, &result);
|
||||||
CHECK(result == ESP_ERR_INVALID_ARG);
|
CHECK(result == ESP_ERR_INVALID_ARG);
|
||||||
CHECK(!handle);
|
CHECK(!handle);
|
||||||
|
|
||||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||||
|
|
||||||
nvs::NVSPartitionManager::get_instance()->deinit_partition("nvs");
|
nvs_flash_deinit_partition(TEST_DEFAULT_PARTITION_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("NVSHandleSimple CXX api read/write string", "[nvs cxx]")
|
TEST_CASE("NVSHandleSimple CXX api read/write string", "[nvs cxx]")
|
||||||
{
|
{
|
||||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
// Positive TC for reading and writing a string using NVSHandleSimple CXX API
|
||||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
|
||||||
PartitionEmulationFixture f(0, 10);
|
|
||||||
char read_buffer [256];
|
char read_buffer [256];
|
||||||
esp_err_t result;
|
esp_err_t result;
|
||||||
shared_ptr<nvs::NVSHandle> handle;
|
shared_ptr<nvs::NVSHandle> handle;
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
// Erase the partition to ensure it is clean
|
||||||
== ESP_OK);
|
REQUIRE(nvs_flash_erase_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
|
// Init the default partition
|
||||||
|
REQUIRE(nvs_flash_init_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||||
|
|
||||||
handle = nvs::open_nvs_handle("test_ns", NVS_READWRITE, &result);
|
handle = nvs::open_nvs_handle_from_partition(TEST_DEFAULT_PARTITION_NAME, "test_ns", NVS_READWRITE, &result);
|
||||||
CHECK(result == ESP_OK);
|
CHECK(result == ESP_OK);
|
||||||
REQUIRE(handle);
|
REQUIRE(handle);
|
||||||
|
|
||||||
@@ -149,25 +161,27 @@ TEST_CASE("NVSHandleSimple CXX api read/write string", "[nvs cxx]")
|
|||||||
|
|
||||||
CHECK(string(read_buffer) == "test string");
|
CHECK(string(read_buffer) == "test string");
|
||||||
|
|
||||||
nvs::NVSPartitionManager::get_instance()->deinit_partition("nvs");
|
nvs_flash_deinit_partition(TEST_DEFAULT_PARTITION_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("NVSHandleSimple CXX api read/write blob", "[nvs cxx]")
|
TEST_CASE("NVSHandleSimple CXX api read/write blob", "[nvs cxx]")
|
||||||
{
|
{
|
||||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
// Positive TC for reading and writing a blob using NVSHandleSimple CXX API
|
||||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
|
||||||
PartitionEmulationFixture f(0, 10);
|
|
||||||
const char blob [6] = {15, 16, 17, 18, 19};
|
const char blob [6] = {15, 16, 17, 18, 19};
|
||||||
char read_blob[6] = {0};
|
char read_blob[6] = {0};
|
||||||
esp_err_t result;
|
esp_err_t result;
|
||||||
shared_ptr<nvs::NVSHandle> handle;
|
shared_ptr<nvs::NVSHandle> handle;
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
// Erase the partition to ensure it is clean
|
||||||
== ESP_OK);
|
REQUIRE(nvs_flash_erase_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
|
// Init the default partition
|
||||||
|
REQUIRE(nvs_flash_init_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||||
|
|
||||||
handle = nvs::open_nvs_handle("test_ns", NVS_READWRITE, &result);
|
handle = nvs::open_nvs_handle_from_partition(TEST_DEFAULT_PARTITION_NAME, "test_ns", NVS_READWRITE, &result);
|
||||||
CHECK(result == ESP_OK);
|
CHECK(result == ESP_OK);
|
||||||
REQUIRE(handle);
|
REQUIRE(handle);
|
||||||
|
|
||||||
@@ -179,5 +193,5 @@ TEST_CASE("NVSHandleSimple CXX api read/write blob", "[nvs cxx]")
|
|||||||
|
|
||||||
CHECK(vector<char>(blob, blob + sizeof(blob)) == vector<char>(read_blob, read_blob + sizeof(read_blob)));
|
CHECK(vector<char>(blob, blob + sizeof(blob)) == vector<char>(read_blob, read_blob + sizeof(read_blob)));
|
||||||
|
|
||||||
nvs::NVSPartitionManager::get_instance()->deinit_partition("nvs");
|
nvs_flash_deinit_partition(TEST_DEFAULT_PARTITION_NAME);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,34 +1,34 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
#include <algorithm>
|
#include "nvs_flash.h"
|
||||||
#include <cstring>
|
|
||||||
#include "nvs_handle_simple.hpp"
|
#include "nvs_handle_simple.hpp"
|
||||||
#include "nvs_partition_manager.hpp"
|
#include "nvs_partition_manager.hpp"
|
||||||
#include "test_fixtures.hpp"
|
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
#define TEMPORARILY_DISABLED(x)
|
#define TEST_DEFAULT_PARTITION_NAME "nvs" // Default partition name used in the tests - 10 sectors
|
||||||
|
#define TEST_3SEC_PARTITION_NAME "nvs_3sec" // Partition used in the space constrained tests - 3 sectors
|
||||||
|
|
||||||
TEST_CASE("NVSHandleSimple closes its reference in PartitionManager", "[partition_mgr]")
|
TEST_CASE("NVSHandleSimple closes its reference in PartitionManager", "[partition_mgr]")
|
||||||
{
|
{
|
||||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
// Positive TC verifying that NVSHandleSimple closes its reference in PartitionManager
|
||||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
// when it is deleted.
|
||||||
PartitionEmulationFixture f(0, 10, "test");
|
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
// Erase the partition to ensure it is clean
|
||||||
== ESP_OK);
|
REQUIRE(nvs_flash_erase_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
|
// Init the default partition
|
||||||
|
REQUIRE(nvs_flash_init_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||||
|
|
||||||
nvs::NVSHandleSimple *handle;
|
nvs::NVSHandleSimple *handle = nullptr;
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->open_handle("test", "ns_1", NVS_READWRITE, &handle) == ESP_OK);
|
REQUIRE(nvs::NVSPartitionManager::get_instance()->open_handle(TEST_DEFAULT_PARTITION_NAME, "ns_1", NVS_READWRITE, &handle) == ESP_OK);
|
||||||
|
|
||||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 1);
|
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 1);
|
||||||
|
|
||||||
@@ -36,29 +36,29 @@ TEST_CASE("NVSHandleSimple closes its reference in PartitionManager", "[partitio
|
|||||||
|
|
||||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->deinit_partition("test") == ESP_OK);
|
REQUIRE(nvs_flash_deinit_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("NVSHandleSimple multiple open and closes with PartitionManager", "[partition_mgr]")
|
TEST_CASE("NVSHandleSimple multiple open and closes with PartitionManager", "[partition_mgr]")
|
||||||
{
|
{
|
||||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
// Positive TC for multiple open and close of NVSHandleSimple with PartitionManager
|
||||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
|
||||||
PartitionEmulationFixture f(0, 10, "test");
|
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
// Erase the partition to ensure it is clean
|
||||||
== ESP_OK);
|
REQUIRE(nvs_flash_erase_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
|
// Init the default partition
|
||||||
|
REQUIRE(nvs_flash_init_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||||
|
|
||||||
nvs::NVSHandleSimple *handle1;
|
nvs::NVSHandleSimple *handle1 = nullptr;
|
||||||
nvs::NVSHandleSimple *handle2;
|
nvs::NVSHandleSimple *handle2 = nullptr;
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->open_handle("test", "ns_1", NVS_READWRITE, &handle1) == ESP_OK);
|
REQUIRE(nvs::NVSPartitionManager::get_instance()->open_handle(TEST_DEFAULT_PARTITION_NAME, "ns_1", NVS_READWRITE, &handle1) == ESP_OK);
|
||||||
|
|
||||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 1);
|
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 1);
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->open_handle("test", "ns_1", NVS_READWRITE, &handle2) == ESP_OK);
|
REQUIRE(nvs::NVSPartitionManager::get_instance()->open_handle(TEST_DEFAULT_PARTITION_NAME, "ns_1", NVS_READWRITE, &handle2) == ESP_OK);
|
||||||
|
|
||||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 2);
|
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 2);
|
||||||
|
|
||||||
@@ -70,61 +70,60 @@ TEST_CASE("NVSHandleSimple multiple open and closes with PartitionManager", "[pa
|
|||||||
|
|
||||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->deinit_partition("test") == ESP_OK);
|
REQUIRE(nvs_flash_deinit_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("NVSHandleSimple readonly fails", "[partition_mgr]")
|
TEST_CASE("NVSHandleSimple readonly fails", "[partition_mgr]")
|
||||||
{
|
{
|
||||||
PartitionEmulationFixture f(0, 10);
|
// Negative TC for opening a handle with read-only mode and trying to write to it
|
||||||
|
|
||||||
nvs::NVSPartitionManager::get_instance()->deinit_partition(NVS_DEFAULT_PART_NAME);
|
// Erase the partition to ensure it is clean
|
||||||
nvs::NVSHandleSimple *handle_1;
|
REQUIRE(nvs_flash_erase_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
nvs::NVSHandleSimple *handle_2;
|
|
||||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
// Init the default partition
|
||||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
REQUIRE(nvs_flash_init_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
TEMPORARILY_DISABLED(f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);)
|
|
||||||
|
nvs::NVSHandleSimple *handle_1 = nullptr;
|
||||||
|
nvs::NVSHandleSimple *handle_2 = nullptr;
|
||||||
|
|
||||||
CHECK(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK);
|
|
||||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||||
|
|
||||||
// first, creating namespace...
|
// first, creating namespace...
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->open_handle(NVS_DEFAULT_PART_NAME, "ns_1", NVS_READWRITE, &handle_1) == ESP_OK);
|
REQUIRE(nvs::NVSPartitionManager::get_instance()->open_handle(TEST_3SEC_PARTITION_NAME, "ns_1", NVS_READWRITE, &handle_1) == ESP_OK);
|
||||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 1);
|
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 1);
|
||||||
|
|
||||||
delete handle_1;
|
delete handle_1;
|
||||||
|
|
||||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->open_handle(NVS_DEFAULT_PART_NAME, "ns_1", NVS_READONLY, &handle_2) == ESP_OK);
|
REQUIRE(nvs::NVSPartitionManager::get_instance()->open_handle(TEST_3SEC_PARTITION_NAME, "ns_1", NVS_READONLY, &handle_2) == ESP_OK);
|
||||||
CHECK(handle_2->set_item("key", 47) == ESP_ERR_NVS_READ_ONLY);
|
CHECK(handle_2->set_item("key", 47) == ESP_ERR_NVS_READ_ONLY);
|
||||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 1);
|
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 1);
|
||||||
|
|
||||||
delete handle_2;
|
delete handle_2;
|
||||||
|
|
||||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
CHECK(nvs::NVSPartitionManager::get_instance()->open_handles_size() == 0);
|
||||||
|
|
||||||
// without deinit it affects "nvs api tests"
|
// without deinit it affects "nvs api tests"
|
||||||
CHECK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME) == ESP_OK);
|
REQUIRE(nvs_flash_deinit_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("NVSHandleSimple set/get char", "[partition_mgr]")
|
TEST_CASE("NVSHandleSimple set/get char", "[partition_mgr]")
|
||||||
{
|
{
|
||||||
|
// Positive TC for setting and getting a char using NVSHandleSimple
|
||||||
enum class TestEnum : char {
|
enum class TestEnum : char {
|
||||||
FOO = -1,
|
FOO = -1,
|
||||||
BEER,
|
BEER,
|
||||||
BAR
|
BAR
|
||||||
};
|
};
|
||||||
|
|
||||||
PartitionEmulationFixture f(0, 10);
|
// Erase the partition to ensure it is clean
|
||||||
|
REQUIRE(nvs_flash_erase_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
// Init the default partition
|
||||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
REQUIRE(nvs_flash_init_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
TEMPORARILY_DISABLED(f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);)
|
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
nvs::NVSHandleSimple *handle = nullptr;
|
||||||
== ESP_OK);
|
REQUIRE(nvs::NVSPartitionManager::get_instance()->open_handle(TEST_3SEC_PARTITION_NAME, "ns_1", NVS_READWRITE, &handle) == ESP_OK);
|
||||||
|
|
||||||
nvs::NVSHandleSimple *handle;
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->open_handle(NVS_DEFAULT_PART_NAME, "ns_1", NVS_READWRITE, &handle) == ESP_OK);
|
|
||||||
|
|
||||||
char test_e = 'a';
|
char test_e = 'a';
|
||||||
char test_e_read = 'z';
|
char test_e_read = 'z';
|
||||||
@@ -136,27 +135,25 @@ TEST_CASE("NVSHandleSimple set/get char", "[partition_mgr]")
|
|||||||
|
|
||||||
delete handle;
|
delete handle;
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->deinit_partition(NVS_DEFAULT_PART_NAME) == ESP_OK);
|
REQUIRE(nvs_flash_deinit_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("NVSHandleSimple correctly sets/gets int enum", "[partition_mgr]")
|
TEST_CASE("NVSHandleSimple correctly sets/gets int enum", "[partition_mgr]")
|
||||||
{
|
{
|
||||||
|
// Positive TC for setting and getting an int enum using NVSHandleSimple
|
||||||
enum class TestEnum : int {
|
enum class TestEnum : int {
|
||||||
FOO,
|
FOO,
|
||||||
BAR
|
BAR
|
||||||
};
|
};
|
||||||
|
|
||||||
PartitionEmulationFixture f(0, 10);
|
// Erase the partition to ensure it is clean
|
||||||
|
REQUIRE(nvs_flash_erase_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
// Init the default partition
|
||||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
REQUIRE(nvs_flash_init_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
TEMPORARILY_DISABLED(f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);)
|
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
nvs::NVSHandleSimple *handle = nullptr;
|
||||||
== ESP_OK);
|
REQUIRE(nvs::NVSPartitionManager::get_instance()->open_handle(TEST_3SEC_PARTITION_NAME, "ns_1", NVS_READWRITE, &handle) == ESP_OK);
|
||||||
|
|
||||||
nvs::NVSHandleSimple *handle;
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->open_handle(NVS_DEFAULT_PART_NAME, "ns_1", NVS_READWRITE, &handle) == ESP_OK);
|
|
||||||
|
|
||||||
TestEnum test_e = TestEnum::BAR;
|
TestEnum test_e = TestEnum::BAR;
|
||||||
TestEnum test_e_read = TestEnum::FOO;
|
TestEnum test_e_read = TestEnum::FOO;
|
||||||
@@ -168,28 +165,26 @@ TEST_CASE("NVSHandleSimple correctly sets/gets int enum", "[partition_mgr]")
|
|||||||
|
|
||||||
delete handle;
|
delete handle;
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->deinit_partition(NVS_DEFAULT_PART_NAME) == ESP_OK);
|
REQUIRE(nvs_flash_deinit_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("NVSHandleSimple correctly sets/gets int enum with negative values", "[partition_mgr]")
|
TEST_CASE("NVSHandleSimple correctly sets/gets int enum with negative values", "[partition_mgr]")
|
||||||
{
|
{
|
||||||
|
// Positive TC for setting and getting an int enum with negative values using NVSHandleSimple
|
||||||
enum class TestEnum : int {
|
enum class TestEnum : int {
|
||||||
FOO = -1,
|
FOO = -1,
|
||||||
BEER,
|
BEER,
|
||||||
BAR
|
BAR
|
||||||
};
|
};
|
||||||
|
|
||||||
PartitionEmulationFixture f(0, 10);
|
// Erase the partition to ensure it is clean
|
||||||
|
REQUIRE(nvs_flash_erase_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
// Init the default partition
|
||||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
REQUIRE(nvs_flash_init_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
TEMPORARILY_DISABLED(f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);)
|
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
nvs::NVSHandleSimple *handle = nullptr;
|
||||||
== ESP_OK);
|
REQUIRE(nvs::NVSPartitionManager::get_instance()->open_handle(TEST_3SEC_PARTITION_NAME, "ns_1", NVS_READWRITE, &handle) == ESP_OK);
|
||||||
|
|
||||||
nvs::NVSHandleSimple *handle;
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->open_handle(NVS_DEFAULT_PART_NAME, "ns_1", NVS_READWRITE, &handle) == ESP_OK);
|
|
||||||
|
|
||||||
TestEnum test_e = TestEnum::FOO;
|
TestEnum test_e = TestEnum::FOO;
|
||||||
TestEnum test_e_read = TestEnum::BEER;
|
TestEnum test_e_read = TestEnum::BEER;
|
||||||
@@ -201,27 +196,25 @@ TEST_CASE("NVSHandleSimple correctly sets/gets int enum with negative values", "
|
|||||||
|
|
||||||
delete handle;
|
delete handle;
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->deinit_partition(NVS_DEFAULT_PART_NAME) == ESP_OK);
|
REQUIRE(nvs_flash_deinit_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("NVSHandleSimple correctly sets/gets uint8_t enum", "[partition_mgr]")
|
TEST_CASE("NVSHandleSimple correctly sets/gets uint8_t enum", "[partition_mgr]")
|
||||||
{
|
{
|
||||||
|
// Positive TC for setting and getting a uint8_t enum using NVSHandleSimple
|
||||||
enum class TestEnum : uint8_t {
|
enum class TestEnum : uint8_t {
|
||||||
FOO,
|
FOO,
|
||||||
BAR
|
BAR
|
||||||
};
|
};
|
||||||
|
|
||||||
PartitionEmulationFixture f(0, 10);
|
// Erase the partition to ensure it is clean
|
||||||
|
REQUIRE(nvs_flash_erase_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
// Init the default partition
|
||||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
REQUIRE(nvs_flash_init_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
TEMPORARILY_DISABLED(f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);)
|
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
nvs::NVSHandleSimple *handle = nullptr;
|
||||||
== ESP_OK);
|
REQUIRE(nvs::NVSPartitionManager::get_instance()->open_handle(TEST_3SEC_PARTITION_NAME, "ns_1", NVS_READWRITE, &handle) == ESP_OK);
|
||||||
|
|
||||||
nvs::NVSHandleSimple *handle;
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->open_handle(NVS_DEFAULT_PART_NAME, "ns_1", NVS_READWRITE, &handle) == ESP_OK);
|
|
||||||
|
|
||||||
TestEnum test_e = TestEnum::BAR;
|
TestEnum test_e = TestEnum::BAR;
|
||||||
TestEnum test_e_read = TestEnum::FOO;
|
TestEnum test_e_read = TestEnum::FOO;
|
||||||
@@ -233,28 +226,26 @@ TEST_CASE("NVSHandleSimple correctly sets/gets uint8_t enum", "[partition_mgr]")
|
|||||||
|
|
||||||
delete handle;
|
delete handle;
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->deinit_partition(NVS_DEFAULT_PART_NAME) == ESP_OK);
|
REQUIRE(nvs_flash_deinit_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("NVSHandleSimple correctly sets/gets char enum", "[partition_mgr]")
|
TEST_CASE("NVSHandleSimple correctly sets/gets char enum", "[partition_mgr]")
|
||||||
{
|
{
|
||||||
|
// Positive TC for setting and getting a char enum using NVSHandleSimple
|
||||||
enum class TestEnum : char {
|
enum class TestEnum : char {
|
||||||
FOO = -1,
|
FOO = -1,
|
||||||
BEER,
|
BEER,
|
||||||
BAR
|
BAR
|
||||||
};
|
};
|
||||||
|
|
||||||
PartitionEmulationFixture f(0, 10);
|
// Erase the partition to ensure it is clean
|
||||||
|
REQUIRE(nvs_flash_erase_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
// Init the default partition
|
||||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
REQUIRE(nvs_flash_init_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
TEMPORARILY_DISABLED(f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);)
|
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
nvs::NVSHandleSimple *handle = nullptr;
|
||||||
== ESP_OK);
|
REQUIRE(nvs::NVSPartitionManager::get_instance()->open_handle(TEST_3SEC_PARTITION_NAME, "ns_1", NVS_READWRITE, &handle) == ESP_OK);
|
||||||
|
|
||||||
nvs::NVSHandleSimple *handle;
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->open_handle(NVS_DEFAULT_PART_NAME, "ns_1", NVS_READWRITE, &handle) == ESP_OK);
|
|
||||||
|
|
||||||
TestEnum test_e = TestEnum::BAR;
|
TestEnum test_e = TestEnum::BAR;
|
||||||
TestEnum test_e_read = TestEnum::FOO;
|
TestEnum test_e_read = TestEnum::FOO;
|
||||||
@@ -266,5 +257,5 @@ TEST_CASE("NVSHandleSimple correctly sets/gets char enum", "[partition_mgr]")
|
|||||||
|
|
||||||
delete handle;
|
delete handle;
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->deinit_partition(NVS_DEFAULT_PART_NAME) == ESP_OK);
|
REQUIRE(nvs_flash_deinit_partition(TEST_3SEC_PARTITION_NAME) == ESP_OK);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,42 +1,89 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
#include "sdkconfig.h"
|
|
||||||
|
#include "sdkconfig.h" // for CONFIG_NVS_BDL_STACK
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
#include "nvs.hpp"
|
#include "nvs_flash.h"
|
||||||
#include "nvs_partition_manager.hpp"
|
#include "nvs_partition_manager.hpp"
|
||||||
#include "nvs_partition.hpp"
|
#include "nvs_partition.hpp"
|
||||||
#include "test_fixtures.hpp"
|
#include "esp_partition.h" // for esp_partition_find_first
|
||||||
#include <string.h>
|
#include "bdl_ramdisk.hpp" // for bdl_ramdisk
|
||||||
#include "esp_partition.h"
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
#define TEST_DEFAULT_PARTITION_NAME "nvs"
|
||||||
|
|
||||||
|
#ifndef CONFIG_NVS_BDL_STACK
|
||||||
TEST_CASE("nvs_flash_init_partition_ptr fails due to nullptr arg", "[nvs_custom_part]")
|
TEST_CASE("nvs_flash_init_partition_ptr fails due to nullptr arg", "[nvs_custom_part]")
|
||||||
{
|
{
|
||||||
uint8_t *p_part_desc_addr_start;
|
// This test checks that nvs_flash_init_partition_ptr fails when passed a nullptr as partition argument.
|
||||||
CHECK(esp_partition_file_mmap((const uint8_t **)&p_part_desc_addr_start) == ESP_OK);
|
|
||||||
|
|
||||||
CHECK(nvs_flash_init_partition_ptr(nullptr) == ESP_ERR_INVALID_ARG);
|
CHECK(nvs_flash_init_partition_ptr(nullptr) == ESP_ERR_INVALID_ARG);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("nvs_flash_init_partition_ptr inits one partition", "[nvs_custom_part]")
|
TEST_CASE("nvs_flash_init_partition_ptr inits one partition", "[nvs_custom_part]")
|
||||||
{
|
{
|
||||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
// This test initializes a partition with a specific name and checks if it is registered in the NVSPartitionManager.
|
||||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
// The test works around the intnernal partition lookup by handing over a partition structure retrieved from esp_partition_find_first.
|
||||||
const uint32_t sec_size = esp_partition_get_main_flash_sector_size();
|
|
||||||
|
|
||||||
uint8_t *p_part_desc_addr_start;
|
// Erase the partition to ensure it is clean
|
||||||
CHECK(esp_partition_file_mmap((const uint8_t **)&p_part_desc_addr_start) == ESP_OK);
|
REQUIRE(nvs_flash_erase_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
esp_partition_t partition = {};
|
const esp_partition_t* partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, TEST_DEFAULT_PARTITION_NAME);
|
||||||
strcpy(partition.label, "test");
|
REQUIRE(partition != nullptr);
|
||||||
partition.address = NVS_FLASH_SECTOR * sec_size;
|
|
||||||
partition.size = NVS_FLASH_SECTOR_COUNT_MIN * sec_size;
|
|
||||||
|
|
||||||
CHECK(nvs_flash_init_partition_ptr(&partition) == ESP_OK);
|
CHECK(nvs_flash_init_partition_ptr(partition) == ESP_OK);
|
||||||
CHECK(nvs::NVSPartitionManager::get_instance()->lookup_storage_from_name("test") != nullptr);
|
CHECK(nvs::NVSPartitionManager::get_instance()->lookup_storage_from_name(TEST_DEFAULT_PARTITION_NAME) != nullptr);
|
||||||
CHECK(nvs::NVSPartitionManager::get_instance()->deinit_partition("test") == ESP_OK);
|
|
||||||
|
REQUIRE(nvs_flash_deinit_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
TEST_CASE("nvs_flash_init_partition_bdl fails due to nullptr arg", "[nvs_custom_part]")
|
||||||
|
{
|
||||||
|
// This test checks that nvs_flash_init_partition_bdl fails when nullptr is provided as a block device argument
|
||||||
|
// or the partition name argument is null.
|
||||||
|
|
||||||
|
// Check nullptr block device
|
||||||
|
CHECK(nvs_flash_init_partition_bdl("NullBDL", nullptr) == ESP_ERR_INVALID_ARG);
|
||||||
|
|
||||||
|
// Check nullptr partition name
|
||||||
|
bdl_ramdisk ramdisk(3 * NVS_CONST_PAGE_SIZE, NVS_CONST_PAGE_SIZE);
|
||||||
|
CHECK(ramdisk.get_handle() != nullptr);
|
||||||
|
CHECK(nvs_flash_init_partition_bdl(nullptr, ramdisk.get_handle()) == ESP_ERR_INVALID_ARG);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("nvs_flash_init_partition_bdl fails due to ineligible block device", "[nvs_custom_part]")
|
||||||
|
{
|
||||||
|
// This test checks that nvs_flash_init_partition_bdl fails when passed an ineligible block device.
|
||||||
|
|
||||||
|
const char* part_name = "BadBDL";
|
||||||
|
bdl_ramdisk ramdisk(3 * NVS_CONST_PAGE_SIZE, NVS_CONST_PAGE_SIZE); // Ramdisk of 3 NVS pages size
|
||||||
|
CHECK(ramdisk.get_handle() != nullptr);
|
||||||
|
|
||||||
|
// Cripple the ramdisk to make it ineligible (erase size not matching NVS requirements)
|
||||||
|
ramdisk.get_handle()->geometry.erase_size = NVS_CONST_PAGE_SIZE - 1;
|
||||||
|
|
||||||
|
CHECK(nvs_flash_init_partition_bdl(part_name, ramdisk.get_handle()) == ESP_ERR_NOT_SUPPORTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("nvs_flash_init_partition_bdl inits externally supplied block device", "[nvs_custom_part]")
|
||||||
|
{
|
||||||
|
// This test initializes NVS on the externally supplied block device with a specific name and checks if
|
||||||
|
// it is registered in the NVSPartitionManager.
|
||||||
|
// The test works around the intnernal partition lookup by handing over a partition structure retrieved from esp_partition_find_first.
|
||||||
|
|
||||||
|
// Erase the partition to ensure it is clean
|
||||||
|
const char* part_name = "GoodBDL";
|
||||||
|
bdl_ramdisk ramdisk(3 * NVS_CONST_PAGE_SIZE, NVS_CONST_PAGE_SIZE); // Ramdisk of 3 NVS pages size
|
||||||
|
CHECK(ramdisk.get_handle() != nullptr);
|
||||||
|
|
||||||
|
CHECK(nvs_flash_init_partition_bdl(part_name, ramdisk.get_handle()) == ESP_OK);
|
||||||
|
CHECK(nvs::NVSPartitionManager::get_instance()->lookup_storage_from_name(part_name) != nullptr);
|
||||||
|
|
||||||
|
REQUIRE(nvs_flash_deinit_partition(part_name) == ESP_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CONFIG_NVS_BDL_STACK
|
||||||
|
|||||||
@@ -1,30 +1,34 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
#include <cstring>
|
#include "nvs_flash.h"
|
||||||
#include "nvs_storage.hpp"
|
#include "nvs_storage.hpp"
|
||||||
#include "nvs_partition_manager.hpp"
|
#include "nvs_partition_manager.hpp"
|
||||||
#include "test_fixtures.hpp"
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
#define TEST_DEFAULT_PARTITION_NAME "nvs"
|
||||||
|
|
||||||
TEST_CASE("Storage iterator recognizes blob with VerOffset::VER_1_OFFSET", "[nvs_storage]")
|
TEST_CASE("Storage iterator recognizes blob with VerOffset::VER_1_OFFSET", "[nvs_storage]")
|
||||||
{
|
{
|
||||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
// Positive TC for Storage iterator recognizing a blob with VerOffset::VER_1_OFFSET
|
||||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
|
||||||
PartitionEmulationFixture f(0, 10, "test");
|
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
// Erase the partition before testing
|
||||||
== ESP_OK);
|
REQUIRE(nvs_flash_erase_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
|
// Init the default partition
|
||||||
|
REQUIRE(nvs_flash_init_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
uint8_t blob [] = {0x0, 0x1, 0x2, 0x3};
|
uint8_t blob [] = {0x0, 0x1, 0x2, 0x3};
|
||||||
uint8_t blob_new [] = {0x3, 0x2, 0x1, 0x0};
|
uint8_t blob_new [] = {0x3, 0x2, 0x1, 0x0};
|
||||||
nvs::Storage *storage = nvs::NVSPartitionManager::get_instance()->lookup_storage_from_name("test");
|
nvs::Storage *storage = nvs::NVSPartitionManager::get_instance()->lookup_storage_from_name(TEST_DEFAULT_PARTITION_NAME);
|
||||||
uint8_t ns_index;
|
uint8_t ns_index;
|
||||||
|
|
||||||
|
REQUIRE(storage != nullptr);
|
||||||
storage->createOrOpenNamespace("test_ns", true, ns_index);
|
storage->createOrOpenNamespace("test_ns", true, ns_index);
|
||||||
|
|
||||||
CHECK(storage->writeItem(ns_index, nvs::ItemType::BLOB, "test_blob", blob, sizeof(blob)) == ESP_OK);
|
CHECK(storage->writeItem(ns_index, nvs::ItemType::BLOB, "test_blob", blob, sizeof(blob)) == ESP_OK);
|
||||||
@@ -43,5 +47,5 @@ TEST_CASE("Storage iterator recognizes blob with VerOffset::VER_1_OFFSET", "[nvs
|
|||||||
CHECK(string(it.entry_info.key) == string("test_blob"));
|
CHECK(string(it.entry_info.key) == string("test_blob"));
|
||||||
CHECK(it.entry_info.type == NVS_TYPE_BLOB);
|
CHECK(it.entry_info.type == NVS_TYPE_BLOB);
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->deinit_partition("test") == ESP_OK);
|
REQUIRE(nvs_flash_deinit_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,70 +1,86 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
#include <catch2/catch_test_macros.hpp>
|
|
||||||
#include <algorithm>
|
#include <catch2/catch_test_macros.hpp> // for Catch2 test macros
|
||||||
#include <cstring>
|
#include "nvs_handle_simple.hpp" // for NVSHandleSimple class
|
||||||
#include "nvs_handle_simple.hpp"
|
#include "nvs_partition_manager.hpp" // for NVSPartitionManager class
|
||||||
#include "nvs_partition_manager.hpp"
|
#include "test_fixtures.hpp" // for test fixtures
|
||||||
#include "nvs_test_api.h"
|
|
||||||
#include "test_fixtures.hpp"
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
#define TEST_DEFAULT_PARTITION_NAME "nvs"
|
||||||
|
#define TEST_SECONDARY_PARTITION_NAME "nvs_sec"
|
||||||
|
|
||||||
TEST_CASE("Partition manager initializes storage", "[partition_mgr]")
|
TEST_CASE("Partition manager initializes storage", "[partition_mgr]")
|
||||||
{
|
{
|
||||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
// Positive TC for partition manager initializing storage
|
||||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
// This test initializes a partition with a specific name and checks if it is registered in the NVSPartitionManager.
|
||||||
PartitionEmulationFixture f(0, 10, "test");
|
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK);
|
// Erase the partition to ensure it is clean
|
||||||
CHECK(nvs::NVSPartitionManager::get_instance()->lookup_storage_from_name("test") != nullptr);
|
// We cannot use nvs_flash_erase_partition here because it is actually using the NVSPartitionManager we want to test.
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->deinit_partition(f.part()->get_partition_name()) == ESP_OK);
|
REQUIRE(NVSPartitionTestHelper::erase_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
|
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
CHECK(nvs::NVSPartitionManager::get_instance()->lookup_storage_from_name(TEST_DEFAULT_PARTITION_NAME) != nullptr);
|
||||||
|
REQUIRE(nvs::NVSPartitionManager::get_instance()->deinit_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Partition manager de-initializes storage", "[partition_mgr]")
|
TEST_CASE("Partition manager de-initializes storage", "[partition_mgr]")
|
||||||
{
|
{
|
||||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
// Positive TC for partition manager de-initializing storage
|
||||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
// This test initializes a partition with a specific name and checks if it is registered in the NVSPartitionManager.
|
||||||
PartitionEmulationFixture f(0, 10, "test");
|
// After de-initialization, the storage should no longer be found
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK);
|
// Erase the partition to ensure it is clean
|
||||||
CHECK(nvs::NVSPartitionManager::get_instance()->lookup_storage_from_name("test") != nullptr);
|
// We cannot use nvs_flash_erase_partition here because it is actually using the NVSPartitionManager we want to test.
|
||||||
CHECK(nvs::NVSPartitionManager::get_instance()->deinit_partition("test") == ESP_OK);
|
REQUIRE(NVSPartitionTestHelper::erase_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
CHECK(nvs::NVSPartitionManager::get_instance()->lookup_storage_from_name("test") == nullptr);
|
|
||||||
|
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
CHECK(nvs::NVSPartitionManager::get_instance()->lookup_storage_from_name(TEST_DEFAULT_PARTITION_NAME) != nullptr);
|
||||||
|
CHECK(nvs::NVSPartitionManager::get_instance()->deinit_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
CHECK(nvs::NVSPartitionManager::get_instance()->lookup_storage_from_name(TEST_DEFAULT_PARTITION_NAME) == nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Partition manager open fails on null handle", "[partition_mgr]")
|
TEST_CASE("Partition manager open fails on null handle", "[partition_mgr]")
|
||||||
{
|
{
|
||||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
// Negative TC for partition manager open_handle failing on null handle pointer
|
||||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
// This test initializes a partition with a specific name.
|
||||||
PartitionEmulationFixture f(0, 10, "test");
|
// The handle shouldn't be null, so the open_handle should return ESP_ERR_INVALID_ARG
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
// Erase the partition to ensure it is clean
|
||||||
== ESP_OK);
|
// We cannot use nvs_flash_erase_partition here because it is actually using the NVSPartitionManager we want to test.
|
||||||
|
REQUIRE(NVSPartitionTestHelper::erase_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
CHECK(nvs::NVSPartitionManager::get_instance()->open_handle("test", "ns_1", NVS_READWRITE, nullptr)
|
// Init the default partition
|
||||||
|
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
|
CHECK(nvs::NVSPartitionManager::get_instance()->open_handle(TEST_DEFAULT_PARTITION_NAME, "ns_1", NVS_READWRITE, nullptr)
|
||||||
== ESP_ERR_INVALID_ARG);
|
== ESP_ERR_INVALID_ARG);
|
||||||
|
|
||||||
nvs::NVSPartitionManager::get_instance()->deinit_partition("test");
|
REQUIRE(nvs::NVSPartitionManager::get_instance()->deinit_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Partition manager invalidates handle on partition de-init", "[partition_mgr]")
|
TEST_CASE("Partition manager invalidates handle on partition de-init", "[partition_mgr]")
|
||||||
{
|
{
|
||||||
const uint32_t NVS_FLASH_SECTOR = 6;
|
// Positive TC for partition manager invalidating handle on partition de-init
|
||||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
// This test initializes a partition with a specific name and checks if it is registered in the NVSPartitionManager.
|
||||||
PartitionEmulationFixture f(0, 10, "test");
|
// After de-initialization, the handle should be invalidated
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
|
// Erase the partition to ensure it is clean
|
||||||
== ESP_OK);
|
// We cannot use nvs_flash_erase_partition here because it is actually using the NVSPartitionManager we want to test.
|
||||||
|
REQUIRE(NVSPartitionTestHelper::erase_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
nvs::NVSHandleSimple *handle;
|
// Init the default partition
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->open_handle("test", "ns_1", NVS_READWRITE, &handle) == ESP_OK);
|
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
|
nvs::NVSHandleSimple *handle = nullptr;
|
||||||
|
REQUIRE(nvs::NVSPartitionManager::get_instance()->open_handle(TEST_DEFAULT_PARTITION_NAME, "ns_1", NVS_READWRITE, &handle) == ESP_OK);
|
||||||
CHECK(handle->erase_all() == ESP_OK);
|
CHECK(handle->erase_all() == ESP_OK);
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->deinit_partition("test") == ESP_OK);
|
REQUIRE(nvs::NVSPartitionManager::get_instance()->deinit_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
|
||||||
CHECK(handle->erase_all() == ESP_ERR_NVS_INVALID_HANDLE);
|
CHECK(handle->erase_all() == ESP_ERR_NVS_INVALID_HANDLE);
|
||||||
|
|
||||||
@@ -73,37 +89,31 @@ TEST_CASE("Partition manager invalidates handle on partition de-init", "[partiti
|
|||||||
|
|
||||||
TEST_CASE("Partition manager initializes multiple partitions", "[partition_mgr]")
|
TEST_CASE("Partition manager initializes multiple partitions", "[partition_mgr]")
|
||||||
{
|
{
|
||||||
const uint32_t NVS_FLASH_SECTOR_BEGIN1 = 0;
|
// Positive TC for partition manager initializing multiple partitions
|
||||||
const uint32_t NVS_FLASH_SECTOR_SIZE1 = 3;
|
// This test initializes two partitions with specific names and checks if they are registered in the NVSPartitionManager.
|
||||||
const char* NVS_FLASH_PARTITION1 = "test1";
|
// After de-initialization, both partitions shouldn't be found
|
||||||
const uint32_t NVS_FLASH_SECTOR_BEGIN2 = 3;
|
|
||||||
const uint32_t NVS_FLASH_SECTOR_SIZE2 = 3;
|
|
||||||
const char* NVS_FLASH_PARTITION2 = "test2";
|
|
||||||
|
|
||||||
PartitionEmulationFixture2 f(NVS_FLASH_SECTOR_BEGIN1,
|
// Erase the partitions to ensure they are clean
|
||||||
NVS_FLASH_SECTOR_SIZE1,
|
// We cannot use nvs_flash_erase_partition here because it is actually using the NVSPartitionManager we want to test.
|
||||||
NVS_FLASH_PARTITION1,
|
REQUIRE(NVSPartitionTestHelper::erase_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
NVS_FLASH_SECTOR_BEGIN2,
|
REQUIRE(NVSPartitionTestHelper::erase_partition(TEST_SECONDARY_PARTITION_NAME) == ESP_OK);
|
||||||
NVS_FLASH_SECTOR_SIZE2,
|
|
||||||
NVS_FLASH_PARTITION2
|
|
||||||
);
|
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(),
|
// Init the default partition
|
||||||
NVS_FLASH_SECTOR_BEGIN1,
|
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
NVS_FLASH_SECTOR_SIZE1)
|
|
||||||
== ESP_OK);
|
|
||||||
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(f.part2(),
|
// Init the alternative partition
|
||||||
NVS_FLASH_SECTOR_BEGIN2,
|
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_partition(TEST_SECONDARY_PARTITION_NAME) == ESP_OK);
|
||||||
NVS_FLASH_SECTOR_SIZE2)
|
|
||||||
== ESP_OK);
|
|
||||||
|
|
||||||
nvs::Storage *storage1 = nvs::NVSPartitionManager::get_instance()->lookup_storage_from_name(NVS_FLASH_PARTITION1);
|
// Check if both partitions are registered
|
||||||
|
nvs::Storage *storage1 = nvs::NVSPartitionManager::get_instance()->lookup_storage_from_name(TEST_DEFAULT_PARTITION_NAME);
|
||||||
REQUIRE(storage1 != nullptr);
|
REQUIRE(storage1 != nullptr);
|
||||||
nvs::Storage *storage2 = nvs::NVSPartitionManager::get_instance()->lookup_storage_from_name(NVS_FLASH_PARTITION2);
|
nvs::Storage *storage2 = nvs::NVSPartitionManager::get_instance()->lookup_storage_from_name(TEST_SECONDARY_PARTITION_NAME);
|
||||||
REQUIRE(storage2 != nullptr);
|
REQUIRE(storage2 != nullptr);
|
||||||
|
|
||||||
|
// Check if the two storages are different
|
||||||
CHECK(storage1 != storage2);
|
CHECK(storage1 != storage2);
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->deinit_partition(NVS_FLASH_PARTITION1) == ESP_OK);
|
|
||||||
REQUIRE(nvs::NVSPartitionManager::get_instance()->deinit_partition(NVS_FLASH_PARTITION2) == ESP_OK);
|
// De-initialize both partitions
|
||||||
|
REQUIRE(nvs::NVSPartitionManager::get_instance()->deinit_partition(TEST_DEFAULT_PARTITION_NAME) == ESP_OK);
|
||||||
|
REQUIRE(nvs::NVSPartitionManager::get_instance()->deinit_partition(TEST_SECONDARY_PARTITION_NAME) == ESP_OK);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Name, Type, SubType, Offset, Size, Flags
|
||||||
|
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
|
||||||
|
nvs, data, nvs, , 0xa000,
|
||||||
|
nvs_sec, data, nvs, , 0xa000,
|
||||||
|
nvs_3sec, data, nvs, , 0x3000,
|
||||||
|
phy_init, data, phy, , 0x1000,
|
||||||
|
factory, app, factory, , 1M,
|
||||||
|
@@ -11,6 +11,7 @@ from pytest_embedded_idf.utils import idf_parametrize
|
|||||||
[
|
[
|
||||||
'default_set_key',
|
'default_set_key',
|
||||||
'legacy_set_key',
|
'legacy_set_key',
|
||||||
|
'esp_blockdev',
|
||||||
],
|
],
|
||||||
indirect=True,
|
indirect=True,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# Configuration enabling internal storage via esp_blockdev instead of direct call to esp_partition nvs_api
|
||||||
|
CONFIG_NVS_BDL_STACK=y
|
||||||
@@ -2,7 +2,7 @@ CONFIG_IDF_TARGET="linux"
|
|||||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||||
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n
|
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n
|
||||||
CONFIG_ESP_PARTITION_ENABLE_STATS=y
|
CONFIG_ESP_PARTITION_ENABLE_STATS=y
|
||||||
CONFIG_PARTITION_TABLE_SINGLE_APP=y
|
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_nvs_host_test.csv"
|
||||||
CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv"
|
CONFIG_PARTITION_TABLE_FILENAME="partitions_nvs_host_test.csv"
|
||||||
CONFIG_PARTITION_TABLE_OFFSET=0x8000
|
CONFIG_PARTITION_TABLE_OFFSET=0x8000
|
||||||
|
|||||||
@@ -43,7 +43,8 @@ public:
|
|||||||
esp_partition.erase_size = ESP_PARTITION_EMULATED_SECTOR_SIZE;
|
esp_partition.erase_size = ESP_PARTITION_EMULATED_SECTOR_SIZE;
|
||||||
esp_partition.type = ESP_PARTITION_TYPE_DATA;
|
esp_partition.type = ESP_PARTITION_TYPE_DATA;
|
||||||
esp_partition.subtype = ESP_PARTITION_SUBTYPE_DATA_NVS;
|
esp_partition.subtype = ESP_PARTITION_SUBTYPE_DATA_NVS;
|
||||||
strncpy(esp_partition.label, partition_name, PART_NAME_MAX_SIZE);
|
strncpy(esp_partition.label, partition_name, NVS_PART_NAME_MAX_SIZE);
|
||||||
|
esp_partition.label[NVS_PART_NAME_MAX_SIZE] = 0; // ensure null termination
|
||||||
}
|
}
|
||||||
|
|
||||||
~PartitionEmulationFixture()
|
~PartitionEmulationFixture()
|
||||||
|
|||||||
@@ -174,8 +174,8 @@ bool NVSPartition::is_bdl_nvs_compliant(const char* label, const esp_blockdev_ha
|
|||||||
is_compliant = false;
|
is_compliant = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(bdl->geometry.erase_size % NVS_CONST_PAGE_SIZE != 0) {
|
if(NVS_CONST_PAGE_SIZE % bdl->geometry.erase_size != 0) {
|
||||||
ESP_LOGV(TAG, "Block device erase size is not a multiple of %d, it is %zu", NVS_CONST_PAGE_SIZE, bdl->geometry.erase_size);
|
ESP_LOGV(TAG, "Block device erase size %zu does not allow erasing pages of size %d.", bdl->geometry.erase_size, NVS_CONST_PAGE_SIZE);
|
||||||
is_compliant = false;
|
is_compliant = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,13 @@ def test_nvs_flash(dut: IdfDut) -> None:
|
|||||||
dut.run_all_single_board_cases(group='!nvs_encr_hmac', timeout=120)
|
dut.run_all_single_board_cases(group='!nvs_encr_hmac', timeout=120)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.generic
|
||||||
|
@pytest.mark.parametrize('config', ['blockdev'], indirect=True)
|
||||||
|
@idf_parametrize('target', ['esp32', 'esp32c3'], indirect=['target'])
|
||||||
|
def test_nvs_flash_blockdev(dut: IdfDut) -> None:
|
||||||
|
dut.run_all_single_board_cases(group='!nvs_encr_hmac', timeout=120)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.nvs_encr_hmac
|
@pytest.mark.nvs_encr_hmac
|
||||||
@pytest.mark.parametrize('config', ['nvs_encr_hmac_esp32c3'], indirect=True)
|
@pytest.mark.parametrize('config', ['nvs_encr_hmac_esp32c3'], indirect=True)
|
||||||
@idf_parametrize('target', ['esp32c3'], indirect=['target'])
|
@idf_parametrize('target', ['esp32c3'], indirect=['target'])
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# Configuration enabling internal storage via esp_blockdev instead of direct call to esp_partition nvs_api
|
||||||
|
CONFIG_NVS_BDL_STACK=y
|
||||||
Reference in New Issue
Block a user