remove(nvs_flash/test_nvs_host): Old make based host tests removed after complete migration

This commit is contained in:
radek.tandler 2023-12-11 18:24:43 +01:00
parent ffdf59a898
commit 6a23790608
19 changed files with 51 additions and 2458 deletions

View File

@ -34,22 +34,16 @@ check_public_headers:
- IDF_TARGET=esp32p4 python tools/ci/check_public_headers.py --jobs 4 --prefix riscv32-esp-elf-
- IDF_TARGET=esp32c61 python tools/ci/check_public_headers.py --jobs 4 --prefix riscv32-esp-elf-
test_nvs_on_host:
extends: .host_test_template
script:
- cd components/nvs_flash/test_nvs_host
- make test
test_nvs_coverage:
extends:
- .host_test_template
- .rules:labels:nvs_coverage
artifacts:
paths:
- components/nvs_flash/test_nvs_host/coverage_report
- components/nvs_flash/host_test/nvs_host_test/coverage_report
script:
- cd components/nvs_flash/test_nvs_host
- make coverage_report
- cd components/nvs_flash/host_test/nvs_host_test
- idf.py build coverage
# the 'long' host tests take approx 11 hours on our current runners. Adding some margin here for possible CPU contention
timeout: 18 hours

View File

@ -5,4 +5,19 @@ set(COMPONENTS main)
# This test app doesn't require FreeRTOS, using mock instead
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/mocks/freertos/")
idf_build_set_property(COMPILE_DEFINITIONS "NO_DEBUG_STORAGE" APPEND)
project(nvs_host_test)
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/coverage_report/index.html"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
COMMAND gcovr --root $ENV{IDF_PATH}/components/nvs_flash --html-details
--exclude ${CMAKE_CURRENT_SOURCE_DIR}/managed_components/*
-o ${CMAKE_CURRENT_BINARY_DIR}/coverage_report/index.html ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generate coverage report"
)
add_custom_target(coverage
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
DEPENDS "coverage_report/index.html"
)

View File

@ -1,2 +1,31 @@
| Supported Targets | Linux |
| ----------------- | ----- |
# To build
Navigate to the host test folder and run the IDF build command for linux target
```
cd $IDF_PATH
. ./export.sh
cd components/nvs_flash/host_test/nvs_host_test
idf.py --preview set-target linux
idf.py build
```
# To run tests locally
Navigate to the IDF root directory and run the binary from there. This ensures all calls to relative paths from test cases are resolved correctly.
This is limitation of ci pipeline as it was not possible to specify the working directory of the host tests.
```
cd $IDF_PATH
./components/nvs_flash/host_test/nvs_host_test/build/nvs_host_test.elf
```
# To create coverage report
After running the tests, the coverage report can be generated following way.
```
cd components/nvs_flash/host_test/nvs_host_test
idf.py build coverage
open ./build/coverage_report/index.html
```

View File

@ -12,6 +12,9 @@ idf_component_register(SRCS "test_nvs.cpp"
REQUIRES nvs_flash
PRIV_REQUIRES spi_flash)
target_compile_options(${COMPONENT_LIB} PUBLIC --coverage)
target_link_libraries(${COMPONENT_LIB} PUBLIC --coverage)
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
target_compile_options(${COMPONENT_LIB} PRIVATE -std=gnu++20)
endif()

View File

@ -3742,7 +3742,7 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit
}
}
TEST_CASE("nvs multiple write with same key but different types", "[nvs][xxx]")
TEST_CASE("nvs multiple write with same key but different types", "[nvs]")
{
PartitionEmulationFixture f(0, 10);

View File

@ -1,113 +0,0 @@
TEST_PROGRAM=test_nvs
all: $(TEST_PROGRAM)
SOURCE_FILES = \
$(addprefix ../src/, \
nvs_types.cpp \
nvs_api.cpp \
nvs_page.cpp \
nvs_pagemanager.cpp \
nvs_storage.cpp \
nvs_item_hash_list.cpp \
nvs_handle_simple.cpp \
nvs_handle_locked.cpp \
nvs_partition_manager.cpp \
nvs_partition.cpp \
nvs_encrypted_partition.cpp \
nvs_cxx_api.cpp \
nvs_platform.cpp \
) \
spi_flash_emulation.cpp \
test_compressed_enum_table.cpp \
test_spi_flash_emulation.cpp \
test_intrusive_list.cpp \
test_nvs.cpp \
test_nvs_partition.cpp \
test_partition_manager.cpp \
test_partition_linux.cpp \
main.cpp
SOURCE_FILES_C = ../../esp_rom/linux/esp_rom_crc.c esp_err_check_mock.c
ifeq ($(shell $(CC) -v 2>&1 | grep -c "clang version"), 1)
COMPILER := clang
else
COMPILER := gcc
endif
CPPFLAGS += -I../private_include -I../include -I../src -I../../heap/include -I../../esp_rom/include -I../../esp_rom/include/linux -I../../esp_rom/linux/include/linux -I../../log/include -I./ -I../../esp_common/include -I../../esp32/include -I ../../mbedtls/mbedtls/include -I ../../spi_flash/include -I ../../esp_partition/include -I ../../hal/include -I ../../xtensa/include -I ../../soc/linux/include -I ../../../tools/catch -fprofile-arcs -ftest-coverage -g2 -ggdb
CFLAGS += -fprofile-arcs -ftest-coverage -DLINUX_TARGET -DLINUX_HOST_LEGACY_TEST
CXXFLAGS += -std=c++11 -Wall -Werror -DLINUX_TARGET -DLINUX_HOST_LEGACY_TEST
LDFLAGS += -lstdc++ -Wall -fprofile-arcs -ftest-coverage
ifeq ($(shell uname -s),Linux)
LDFLAGS += -lbsd
endif
ifeq ($(COMPILER),clang)
CFLAGS += -fsanitize=address
CXXFLAGS += -fsanitize=address
LDFLAGS += -fsanitize=address
endif
OBJ_FILES = $(SOURCE_FILES:.cpp=.o)
OBJ_FILES_C = $(SOURCE_FILES_C:.c=.o)
COVERAGE_FILES = $(OBJ_FILES:.o=.gc*)
MBEDTLS_LIB := ../../mbedtls/mbedtls/library/libmbedcrypto.a
$(OBJ_FILES): %.o: %.cpp
$(OBJ_FILES_C): %.c: %.c
$(MBEDTLS_LIB):
$(MAKE) -C ../../mbedtls/mbedtls/ lib
$(TEST_PROGRAM): $(OBJ_FILES) $(OBJ_FILES_C) $(MBEDTLS_LIB) | clean-coverage
g++ -o $@ $^ $(LDFLAGS)
$(OUTPUT_DIR):
mkdir -p $(OUTPUT_DIR)
test: $(TEST_PROGRAM)
./$(TEST_PROGRAM) -d yes exclude:[long]
long-test: $(TEST_PROGRAM)
./$(TEST_PROGRAM) -d yes
$(COVERAGE_FILES): $(TEST_PROGRAM) long-test
coverage.info: $(COVERAGE_FILES)
find ../src/ -name "*.gcno" -exec gcov -r -pb {} +
lcov --capture --directory ../src --no-external --output-file coverage.info
coverage_report: coverage.info
genhtml coverage.info --output-directory coverage_report
@echo "Coverage report is in coverage_report/index.html"
clean-coverage:
rm -f $(COVERAGE_FILES) *.gcov
rm -rf coverage_report/
rm -f coverage.info
clean: clean-coverage
$(MAKE) -C ../../mbedtls/mbedtls/ clean
rm -f $(OBJ_FILES) $(OBJ_FILES_C) $(TEST_PROGRAM)
rm -f ../nvs_partition_generator/partition_single_page.bin
rm -f ../nvs_partition_generator/partition_multipage_blob.bin
rm -f ../nvs_partition_generator/partition_encrypted.bin
rm -f ../nvs_partition_generator/partition_encrypted_hmac.bin
rm -f ../nvs_partition_generator/partition_encrypted_using_keygen.bin
rm -f ../nvs_partition_generator/partition_encrypted_using_keyfile.bin
rm -f ../nvs_partition_generator/partition_encrypted_using_keygen_hmac.bin
rm -f ../nvs_partition_generator/partition_decrypted.bin
rm -f ../nvs_partition_generator/partition_decrypted_hmac.bin
rm -f ../nvs_partition_generator/partition_encoded.bin
rm -f ../nvs_partition_generator/Test-1-partition-encrypted-hmac.bin
rm -f ../nvs_partition_generator/Test-1-partition-encrypted.bin
rm -f ../nvs_partition_generator/Test-1-partition.bin
rm -f ../../../tools/mass_mfg/samples/sample_values_multipage_blob_created.csv
rm -f ../../../tools/mass_mfg/samples/sample_values_singlepage_blob_created.csv
.PHONY: clean clean-coverage all test long-test

View File

@ -1,22 +0,0 @@
# Build
```bash
make -j 6
```
# Run
* Run particular test case:
```bash
./test_nvs "<particular test case>"
```
* Run all quick tests:
```bash
./test_nvs -d yes exclude:[long]
```
* Run all tests (takes several hours)
```bash
./test_nvs -d yes
```

View File

@ -1,2 +0,0 @@
#define CATCH_CONFIG_MAIN
#include "catch.hpp"

View File

@ -1,6 +0,0 @@
#define CONFIG_NVS_ENCRYPTION 1
#define CONFIG_LOG_DEFAULT_LEVEL 3
#define CONFIG_LOG_MAXIMUM_LEVEL 3
#define CONFIG_LOG_TIMESTAMP_SOURCE_RTOS 1
#define CONFIG_IDF_TARGET_LINUX 1
#define CONFIG_NVS_ASSERT_ERROR_CHECK 1

View File

@ -1,133 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_partition.h"
#include "spi_flash_emulation.h"
#include "spi_flash_mmap.h"
static SpiFlashEmulator* s_emulator = nullptr;
void spi_flash_emulator_set(SpiFlashEmulator* e)
{
s_emulator = e;
}
esp_err_t esp_partition_erase_range(const esp_partition_t* partition,
size_t offset, size_t size)
{
if (!s_emulator) {
return ESP_ERR_FLASH_OP_TIMEOUT;
}
const uint32_t sec_size = esp_partition_get_main_flash_sector_size();
if (size % sec_size != 0) {
return ESP_ERR_INVALID_SIZE;
}
if (offset % sec_size != 0) {
return ESP_ERR_INVALID_ARG;
}
size_t start_sector = offset / sec_size;
size_t num_sectors = size / sec_size;
for (size_t sector = start_sector; sector < (start_sector + num_sectors); sector++) {
if (!s_emulator->erase(sector)) {
return ESP_ERR_FLASH_OP_FAIL;
}
}
return ESP_OK;
}
esp_err_t esp_partition_read(const esp_partition_t* partition,
size_t src_offset, void* dst, size_t size)
{
if (!s_emulator) {
return ESP_ERR_FLASH_OP_TIMEOUT;
}
if (!s_emulator->read(reinterpret_cast<uint32_t*>(dst), src_offset, size)) {
return ESP_ERR_FLASH_OP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_partition_read_raw(const esp_partition_t* partition,
size_t src_offset, void* dst, size_t size)
{
if (!s_emulator) {
return ESP_ERR_FLASH_OP_TIMEOUT;
}
if (!s_emulator->read(reinterpret_cast<uint32_t*>(dst), src_offset, size)) {
return ESP_ERR_FLASH_OP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_partition_write(const esp_partition_t* partition,
size_t dst_offset, const void* src, size_t size)
{
if (!s_emulator) {
return ESP_ERR_FLASH_OP_TIMEOUT;
}
if (!s_emulator->write(dst_offset, reinterpret_cast<const uint32_t*>(src), size)) {
return ESP_ERR_FLASH_OP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_partition_write_raw(const esp_partition_t* partition,
size_t dst_offset, const void* src, size_t size)
{
if (!s_emulator) {
return ESP_ERR_FLASH_OP_TIMEOUT;
}
if (!s_emulator->write(dst_offset, reinterpret_cast<const uint32_t*>(src), size)) {
return ESP_ERR_FLASH_OP_FAIL;
}
return ESP_OK;
}
// timing data for ESP8266, 160MHz CPU frequency, 80MHz flash frequency
// all values in microseconds
// values are for block sizes starting at 4 bytes and going up to 4096 bytes
static size_t readTimes[] = {7, 5, 6, 7, 11, 18, 32, 60, 118, 231, 459};
static size_t writeTimes[] = {19, 23, 35, 57, 106, 205, 417, 814, 1622, 3200, 6367};
static size_t blockEraseTime = 37142;
static size_t timeInterp(uint32_t bytes, size_t* lut)
{
const int lut_size = sizeof(readTimes)/sizeof(readTimes[0]);
int lz = __builtin_clz(bytes / 4);
int log_size = 32 - lz;
size_t x2 = 1 << (log_size + 2);
size_t y2 = lut[std::min(log_size, lut_size - 1)];
size_t x1 = 1 << (log_size + 1);
size_t y1 = lut[log_size - 1];
return (bytes - x1) * (y2 - y1) / (x2 - x1) + y1;
}
size_t SpiFlashEmulator::getReadOpTime(uint32_t bytes)
{
return timeInterp(bytes, readTimes);
}
size_t SpiFlashEmulator::getWriteOpTime(uint32_t bytes)
{
return timeInterp(bytes, writeTimes);
}
size_t SpiFlashEmulator::getEraseOpTime()
{
return blockEraseTime;
}

View File

@ -1,245 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef spi_flash_emulation_h
#define spi_flash_emulation_h
#include <vector>
#include <cassert>
#include <algorithm>
#include <random>
#include "esp_partition.h"
#include "catch.hpp"
class SpiFlashEmulator;
void spi_flash_emulator_set(SpiFlashEmulator*);
class SpiFlashEmulator
{
public:
SpiFlashEmulator(size_t sectorCount) : mUpperSectorBound(sectorCount)
{
const uint32_t sec_size = esp_partition_get_main_flash_sector_size();
mData.resize(sectorCount * sec_size / 4, 0xffffffff);
mEraseCnt.resize(sectorCount);
spi_flash_emulator_set(this);
}
SpiFlashEmulator(const char *filename)
{
load(filename);
const uint32_t sec_size = esp_partition_get_main_flash_sector_size();
// At least one page should be free, hence we create mData of size of 2 sectors.
mData.resize(mData.size() + sec_size / 4, 0xffffffff);
mUpperSectorBound = mData.size() * 4 / sec_size;
spi_flash_emulator_set(this);
}
~SpiFlashEmulator()
{
spi_flash_emulator_set(nullptr);
}
bool read(uint32_t* dest, size_t srcAddr, size_t size) const
{
if (srcAddr % 4 != 0 ||
size % 4 != 0 ||
srcAddr + size > mData.size() * 4) {
return false;
}
copy(begin(mData) + srcAddr / 4, begin(mData) + (srcAddr + size) / 4, dest);
++mReadOps;
mReadBytes += size;
mTotalTime += getReadOpTime(static_cast<uint32_t>(size));
return true;
}
bool write(size_t dstAddr, const uint32_t* src, size_t size)
{
const uint32_t sec_size = esp_partition_get_main_flash_sector_size();
uint32_t sectorNumber = dstAddr/sec_size;
if (sectorNumber < mLowerSectorBound || sectorNumber >= mUpperSectorBound) {
WARN("invalid flash operation detected: erase sector=" << sectorNumber);
return false;
}
if (dstAddr % 4 != 0 ||
size % 4 != 0 ||
dstAddr + size > mData.size() * 4) {
return false;
}
for (size_t i = 0; i < size / 4; ++i) {
if (mFailCountdown != SIZE_MAX && mFailCountdown-- == 0) {
return false;
}
uint32_t sv = src[i];
size_t pos = dstAddr / 4 + i;
uint32_t& dv = mData[pos];
if (((~dv) & sv) != 0) { // are we trying to set some 0 bits to 1?
WARN("invalid flash operation detected: dst=" << dstAddr << " size=" << size << " i=" << i);
return false;
}
dv = sv;
}
++mWriteOps;
mWriteBytes += size;
mTotalTime += getWriteOpTime(static_cast<uint32_t>(size));
return true;
}
bool erase(size_t sectorNumber)
{
const uint32_t sec_size = esp_partition_get_main_flash_sector_size();
size_t offset = sectorNumber * sec_size / 4;
if (offset > mData.size()) {
return false;
}
if (sectorNumber < mLowerSectorBound || sectorNumber >= mUpperSectorBound) {
WARN("invalid flash operation detected: erase sector=" << sectorNumber);
return false;
}
if (mFailCountdown != SIZE_MAX && mFailCountdown-- == 0) {
return false;
}
std::fill_n(begin(mData) + offset, sec_size / 4, 0xffffffff);
++mEraseOps;
mEraseCnt[sectorNumber]++;
mTotalTime += getEraseOpTime();
return true;
}
void randomize(uint32_t seed)
{
std::random_device rd;
std::mt19937 gen(rd());
gen.seed(seed);
std::generate_n(mData.data(), mData.size(), gen);
}
size_t size() const
{
return mData.size() * 4;
}
const uint32_t* words() const
{
return mData.data();
}
const uint8_t* bytes() const
{
return reinterpret_cast<const uint8_t*>(mData.data());
}
void load(const char* filename)
{
const uint32_t sector_size = esp_partition_get_main_flash_sector_size();
size_t sec_size = sector_size;
FILE* f = fopen(filename, "rb");
fseek(f, 0, SEEK_END);
off_t size = ftell(f);
assert(size % sec_size == 0);
mData.resize(size / sizeof(uint32_t));
fseek(f, 0, SEEK_SET);
auto s = fread(mData.data(), sec_size, size / sec_size, f);
assert(s == static_cast<size_t>(size / sec_size));
fclose(f);
}
void save(const char* filename)
{
const uint32_t sector_size = esp_partition_get_main_flash_sector_size();
size_t sec_size = sector_size;
FILE* f = fopen(filename, "wb");
auto n_sectors = mData.size() * sizeof(uint32_t) / sec_size;
auto s = fwrite(mData.data(), sec_size, n_sectors, f);
assert(s == n_sectors);
fclose(f);
}
void clearStats()
{
mReadBytes = 0;
mWriteBytes = 0;
mEraseOps = 0;
mReadOps = 0;
mWriteOps = 0;
mTotalTime = 0;
}
size_t getReadOps() const
{
return mReadOps;
}
size_t getWriteOps() const
{
return mWriteOps;
}
size_t getEraseOps() const
{
return mEraseOps;
}
size_t getReadBytes() const
{
return mReadBytes;
}
size_t getWriteBytes() const
{
return mWriteBytes;
}
size_t getTotalTime() const
{
return mTotalTime;
}
void setBounds(uint32_t lowerSector, uint32_t upperSector) {
mLowerSectorBound = lowerSector;
mUpperSectorBound = upperSector;
}
void failAfter(uint32_t count) {
mFailCountdown = count;
}
size_t getSectorEraseCount(uint32_t sector) const {
return mEraseCnt[sector];
}
protected:
static size_t getReadOpTime(uint32_t bytes);
static size_t getWriteOpTime(uint32_t bytes);
static size_t getEraseOpTime();
std::vector<uint32_t> mData;
std::vector<uint32_t> mEraseCnt;
mutable size_t mReadOps = 0;
mutable size_t mWriteOps = 0;
mutable size_t mReadBytes = 0;
mutable size_t mWriteBytes = 0;
mutable size_t mEraseOps = 0;
mutable size_t mTotalTime = 0;
size_t mLowerSectorBound = 0;
size_t mUpperSectorBound = 0;
size_t mFailCountdown = SIZE_MAX;
};
#endif /* spi_flash_emulation_h */

View File

@ -1,48 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "catch.hpp"
#include "compressed_enum_table.hpp"
#include <cstring>
TEST_CASE("test if CompressedEnumTable works as expected", "[enumtable]")
{
enum class TEnum1 : uint32_t {
ZERO = 0,
ONE = 1,
TWO = 2,
THREE = 3,
};
CompressedEnumTable<TEnum1, 2, 252> table;
memset(table.data(), 0xff, table.byteSize());
TEnum1 tmp;
for (size_t i = 0; i < table.count(); ++i) {
CHECK(table.get(i, &tmp) == ESP_OK);
CHECK(tmp == TEnum1::THREE);
}
CHECK(table.set(0, TEnum1::ONE) == ESP_OK);
CHECK(table.set(1, TEnum1::TWO) == ESP_OK);
CHECK(table.set(2, TEnum1::ZERO) == ESP_OK);
CHECK(table.set(3, TEnum1::ONE) == ESP_OK);
CHECK(table.set(4, TEnum1::TWO) == ESP_OK);
CHECK(table.set(5, TEnum1::ZERO) == ESP_OK);
CHECK(table.set(6, TEnum1::ONE) == ESP_OK);
CHECK(table.set(7, TEnum1::TWO) == ESP_OK);
CHECK(table.set(8, TEnum1::ZERO) == ESP_OK);
CHECK(table.set(9, TEnum1::ZERO) == ESP_OK);
CHECK(table.set(10, TEnum1::ONE) == ESP_OK);
CHECK(table.set(11, TEnum1::TWO) == ESP_OK);
// table.set(12, ...
CHECK(table.set(13, TEnum1::ZERO) == ESP_OK);
CHECK(table.set(14, TEnum1::ONE) == ESP_OK);
CHECK(table.set(15, TEnum1::TWO) == ESP_OK);
// b10010011100100001001001001001001
// h 9 3 9 0 9 2 4 9
CHECK(table.data()[0] == 0x93909249);
}

View File

@ -1,152 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "nvs_partition.hpp"
#include "nvs_encrypted_partition.hpp"
#include "spi_flash_emulation.h"
#include "spi_flash_mmap.h"
#include "nvs.h"
class PartitionEmulation : public nvs::Partition {
public:
PartitionEmulation(SpiFlashEmulator *spi_flash_emulator,
uint32_t address,
uint32_t size,
const char *partition_name = NVS_DEFAULT_PART_NAME)
: partition_name(partition_name), flash_emu(spi_flash_emulator), address(address), size(size)
{
assert(partition_name);
assert(flash_emu);
assert(size);
readonly = false;
}
const char *get_partition_name() override
{
return partition_name;
}
esp_err_t read_raw(size_t src_offset, void* dst, size_t size) override
{
if (!flash_emu->read(reinterpret_cast<uint32_t*>(dst), src_offset, size)) {
return ESP_ERR_FLASH_OP_FAIL;
}
return ESP_OK;
}
esp_err_t read(size_t src_offset, void* dst, size_t size) override
{
if (!flash_emu->read(reinterpret_cast<uint32_t*>(dst), src_offset, size)) {
return ESP_ERR_FLASH_OP_FAIL;
}
return ESP_OK;
}
esp_err_t write_raw(size_t dst_offset, const void* src, size_t size) override
{
if (!flash_emu->write(dst_offset, reinterpret_cast<const uint32_t*>(src), size)) {
return ESP_ERR_FLASH_OP_FAIL;
}
return ESP_OK;
}
esp_err_t write(size_t dst_offset, const void* src, size_t size) override
{
if (!flash_emu->write(dst_offset, reinterpret_cast<const uint32_t*>(src), size)) {
return ESP_ERR_FLASH_OP_FAIL;
}
return ESP_OK;
}
esp_err_t erase_range(size_t dst_offset, size_t size) override
{
const uint32_t sec_size = esp_partition_get_main_flash_sector_size();
if (size % sec_size != 0) {
return ESP_ERR_INVALID_SIZE;
}
if (dst_offset % sec_size != 0) {
return ESP_ERR_INVALID_ARG;
}
size_t start_sector = dst_offset / sec_size;
size_t num_sectors = size / sec_size;
for (size_t sector = start_sector; sector < (start_sector + num_sectors); sector++) {
if (!flash_emu->erase(sector)) {
return ESP_ERR_FLASH_OP_FAIL;
}
}
return ESP_OK;
}
uint32_t get_address() override
{
return address;
}
uint32_t get_size() override
{
return size;
}
bool get_readonly() override
{
return readonly;
}
private:
const char *partition_name;
SpiFlashEmulator *flash_emu;
uint32_t address;
uint32_t size;
bool readonly;
};
struct PartitionEmulationFixture {
PartitionEmulationFixture(uint32_t start_sector = 0,
uint32_t sector_size = 1,
const char *partition_name = NVS_DEFAULT_PART_NAME)
: emu(start_sector + sector_size),
part(&emu, start_sector * esp_partition_get_main_flash_sector_size(), sector_size * esp_partition_get_main_flash_sector_size(), partition_name) {
}
~PartitionEmulationFixture() { }
SpiFlashEmulator emu;
PartitionEmulation part;
};
struct EncryptedPartitionFixture {
EncryptedPartitionFixture(nvs_sec_cfg_t *cfg,
uint32_t start_sector = 0,
uint32_t sector_size = 1,
const char *partition_name = NVS_DEFAULT_PART_NAME)
: esp_partition(), emu(start_sector + sector_size),
part(&esp_partition) {
const uint32_t sec_size = esp_partition_get_main_flash_sector_size();
esp_partition.address = start_sector * sec_size;
esp_partition.size = sector_size * sec_size;
strncpy(esp_partition.label, partition_name, PART_NAME_MAX_SIZE);
assert(part.init(cfg) == ESP_OK);
}
~EncryptedPartitionFixture() { }
esp_partition_t esp_partition;
SpiFlashEmulator emu;
nvs::NVSEncryptedPartition part;
};

View File

@ -1,212 +0,0 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "catch.hpp"
#include <algorithm>
#include <cstring>
#include "intrusive_list.h"
struct TestNode : public intrusive_list_node<TestNode> {
TestNode(const char* name_ = "", int num_ = 0) : num(num_)
{
strncpy(name, name_, sizeof(name) - 1);
name[sizeof(name) - 1] = 0;
}
char name[32];
int num;
};
typedef intrusive_list<TestNode> TestList;
TEST_CASE("can add items to the list", "[list]")
{
TestList list;
TestNode n1("one", 1);
TestNode n2("two", 2);
TestNode n3("three", 3);
list.push_back(&n1);
REQUIRE(list.begin()->num == 1);
REQUIRE(list.front().num == 1);
REQUIRE(list.back().num == 1);
list.push_front(&n2);
REQUIRE(list.begin()->num == 2);
REQUIRE(list.front().num == 2);
REQUIRE(list.back().num == 1);
list.insert(list.begin(), &n3);
REQUIRE(list.begin()->num == 3);
REQUIRE(list.front().num == 3);
REQUIRE(list.back().num == 1);
auto second = ++list.begin();
REQUIRE(second->num == 2);
second++;
REQUIRE(second->num == 1);
}
TEST_CASE("can iterate over items", "[list]")
{
TestList list;
TestNode n1("one", 1);
TestNode n2("two", 2);
TestNode n3("three", 3);
list.push_back(&n1);
list.push_back(&n2);
list.push_back(&n3);
int val = 1;
for (auto it = std::begin(list); it != std::end(list); ++it) {
REQUIRE(it->num == val);
++val;
}
}
TEST_CASE("iterator's prefix and postfix increments and decrements behave as expected", "[list]")
{
TestList list;
TestNode n1("one", 1);
TestNode n2("two", 2);
TestNode n3("three", 3);
list.push_back(&n1);
list.push_back(&n2);
list.push_back(&n3);
auto it = std::begin(list);
REQUIRE((++it)->num == 2);
REQUIRE(it++->num == 2);
REQUIRE((--it)->num == 2);
REQUIRE(it--->num == 2);
}
TEST_CASE("can pop_front from the list", "[list]")
{
TestList list;
TestNode n1("one", 1);
TestNode n2("two", 2);
TestNode n3("three", 3);
list.push_back(&n1);
list.push_back(&n2);
list.push_back(&n3);
list.pop_front();
list.pop_front();
list.pop_front();
REQUIRE(std::begin(list) == std::end(list));
}
TEST_CASE("can erase first item in the list", "[list]")
{
TestList list;
TestNode n1("one", 1);
TestNode n2("two", 2);
TestNode n3("three", 3);
list.push_back(&n1);
list.push_back(&n2);
list.push_back(&n3);
list.erase(std::begin(list));
REQUIRE(list.front().num == 2);
REQUIRE(list.back().num == 3);
}
TEST_CASE("can erase last item in the list", "[list]")
{
TestList list;
TestNode n1("one", 1);
TestNode n2("two", 2);
TestNode n3("three", 3);
list.push_back(&n1);
list.push_back(&n2);
list.push_back(&n3);
list.erase(&list.back());
REQUIRE(list.front().num == 1);
REQUIRE(list.back().num == 2);
}
TEST_CASE("can erase item in the middle of the list", "[list]")
{
TestList list;
TestNode n1("one", 1);
TestNode n2("two", 2);
TestNode n3("three", 3);
list.push_back(&n1);
list.push_back(&n2);
list.push_back(&n3);
list.erase(++std::begin(list));
REQUIRE(list.front().num == 1);
REQUIRE(list.back().num == 3);
}
TEST_CASE("can erase all items in the list", "[list]")
{
TestList list;
TestNode n1("one", 1);
TestNode n2("two", 2);
TestNode n3("three", 3);
list.push_back(&n1);
list.push_back(&n2);
list.push_back(&n3);
list.erase(std::begin(list));
list.erase(std::begin(list));
list.erase(std::begin(list));
REQUIRE(std::begin(list) == std::end(list));
}
TEST_CASE("can erase all items in the list using clear method", "[list]")
{
TestList list;
TestNode n1("one", 1);
TestNode n2("two", 2);
TestNode n3("three", 3);
TestNode n4("four", 4);
TestNode n5("five", 5);
TestNode n6("six", 6);
list.push_back(&n1);
list.push_back(&n2);
list.insert(++list.begin(), &n3);
list.insert(++list.begin(), &n4);
list.push_front(&n5);
list.insert(list.begin(), &n6);
list.clear();
REQUIRE(std::begin(list) == std::end(list));
}

File diff suppressed because it is too large Load Diff

View File

@ -1,42 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "catch.hpp"
#include <algorithm>
#include <cstring>
#include "nvs_test_api.h"
#include "nvs_handle_simple.hpp"
#include "nvs_partition.hpp"
#include "spi_flash_emulation.h"
#include "test_fixtures.hpp"
#include <iostream>
TEST_CASE("encrypted partition read size must be item size", "[nvs]")
{
char foo [32] = { };
nvs_sec_cfg_t xts_cfg;
for (int count = 0; count < NVS_KEY_SIZE; count++) {
xts_cfg.eky[count] = 0x11;
xts_cfg.tky[count] = 0x22;
}
EncryptedPartitionFixture fix(&xts_cfg);
CHECK(fix.part.read(0, foo, sizeof (foo) - 1) == ESP_ERR_INVALID_SIZE);
}
TEST_CASE("encrypted partition write size must be mod item size", "[nvs]")
{
char foo [64] = { };
nvs_sec_cfg_t xts_cfg;
for (int count = 0; count < NVS_KEY_SIZE; count++) {
xts_cfg.eky[count] = 0x11;
xts_cfg.tky[count] = 0x22;
}
EncryptedPartitionFixture fix(&xts_cfg);
CHECK(fix.part.write(0, foo, sizeof (foo) - 1) == ESP_ERR_INVALID_SIZE);
CHECK(fix.part.write(0, foo, sizeof (foo) / 2) == ESP_OK);
CHECK(fix.part.write(sizeof(foo) / 2, foo, sizeof (foo)) == ESP_OK);
}

View File

@ -1,41 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "catch.hpp"
#include <algorithm>
#include <cstring>
#include "nvs_test_api.h"
#include "nvs_handle_simple.hpp"
#include "nvs_partition_manager.hpp"
#include "spi_flash_emulation.h"
#include "nvs_test_api.h"
#include "test_fixtures.hpp"
#include "esp_partition.h"
/*
TEST_CASE("Partition manager initializes multiple partitions", "[partition_mgr]")
{
const uint32_t NVS_FLASH_SECTOR = 6;
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
SpiFlashEmulator emu(10);
const uint32_t sec_size = esp_partition_get_main_flash_sector_size();
PartitionEmulation part_0(&emu, NVS_FLASH_SECTOR * sec_size, NVS_FLASH_SECTOR_COUNT_MIN * sec_size, "test1");
PartitionEmulation part_1(&emu, NVS_FLASH_SECTOR * sec_size, NVS_FLASH_SECTOR_COUNT_MIN * sec_size, "test2");
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(&part_0, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
== ESP_OK);
// TODO: why does this work, actually? same sectors used as above
REQUIRE(nvs::NVSPartitionManager::get_instance()->init_custom(&part_1, NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)
== ESP_OK);
nvs::Storage *storage1 = nvs::NVSPartitionManager::get_instance()->lookup_storage_from_name("test1");
REQUIRE(storage1 != nullptr);
nvs::Storage *storage2 = nvs::NVSPartitionManager::get_instance()->lookup_storage_from_name("test2");
REQUIRE(storage2 != nullptr);
CHECK(storage1 != storage2);
REQUIRE(nvs::NVSPartitionManager::get_instance()->deinit_partition(part_0.get_partition_name()) == ESP_OK);
REQUIRE(nvs::NVSPartitionManager::get_instance()->deinit_partition(part_1.get_partition_name()) == ESP_OK);
}
*/

View File

@ -1,178 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "catch.hpp"
#include "esp_partition.h"
#include "spi_flash_emulation.h"
#include "spi_flash_mmap.h"
#include <functional>
template <typename Tit>
bool range_empty_n(Tit it_begin, size_t n)
{
return std::all_of(it_begin, it_begin + n, bind(std::equal_to<uint32_t>(), std::placeholders::_1, 0xffffffff));
}
struct FlashEmuFixture {
FlashEmuFixture(size_t sectors) : esp_part(), emu(sectors) { }
esp_partition_t esp_part;
SpiFlashEmulator emu;
};
TEST_CASE("flash starts with all bytes == 0xff", "[spi_flash_emu]")
{
FlashEmuFixture f(4);
uint32_t sec_size = esp_partition_get_main_flash_sector_size();
uint8_t sector[sec_size];
for (int i = 0; i < 4; ++i) {
CHECK(esp_partition_read(&f.esp_part, 0, sector, sizeof(sector)) == ESP_OK);
for (auto v: sector) {
CHECK(v == 0xff);
}
}
}
TEST_CASE("invalid writes are checked", "[spi_flash_emu]")
{
FlashEmuFixture f(1);
uint32_t val = 0;
CHECK(esp_partition_write(&f.esp_part, 0, &val, 4) == ESP_OK);
val = 1;
CHECK(esp_partition_write(&f.esp_part, 0, &val, 4) == ESP_ERR_FLASH_OP_FAIL);
}
TEST_CASE("out of bounds writes fail", "[spi_flash_emu]")
{
FlashEmuFixture f(4);
uint32_t vals[8];
std::fill_n(vals, 8, 0);
CHECK(esp_partition_write(&f.esp_part, 0, &vals, sizeof(vals)) == ESP_OK);
CHECK(esp_partition_write(&f.esp_part, 4*4096 - sizeof(vals), &vals, sizeof(vals)) == ESP_OK);
CHECK(esp_partition_write(&f.esp_part, 4*4096 - sizeof(vals) + 4, &vals, sizeof(vals)) == ESP_ERR_FLASH_OP_FAIL);
}
TEST_CASE("after erase the sector is set to 0xff", "[spi_flash_emu]")
{
FlashEmuFixture f(4);
uint32_t val1 = 0xab00cd12;
CHECK(esp_partition_write(&f.esp_part, 0, &val1, sizeof(val1)) == ESP_OK);
uint32_t val2 = 0x5678efab;
CHECK(esp_partition_write(&f.esp_part, 4096 - 4, &val2, sizeof(val2)) == ESP_OK);
CHECK(f.emu.words()[0] == val1);
CHECK(range_empty_n(f.emu.words() + 1, 4096 / 4 - 2));
CHECK(f.emu.words()[4096 / 4 - 1] == val2);
uint32_t sec_size = esp_partition_get_main_flash_sector_size();
CHECK(esp_partition_erase_range(&f.esp_part, 0, sec_size) == ESP_OK);
CHECK(f.emu.words()[0] == 0xffffffff);
CHECK(range_empty_n(f.emu.words() + 1, 4096 / 4 - 2));
CHECK(f.emu.words()[4096 / 4 - 1] == 0xffffffff);
}
TEST_CASE("EMU raw read function works", "[spi_flash_emu]")
{
FlashEmuFixture f(4);
uint32_t value = 0xdeadbeef;
uint32_t read_value = 0;
CHECK(esp_partition_write(&f.esp_part, 0, &value, sizeof(value)) == ESP_OK);
CHECK(esp_partition_read_raw(&f.esp_part, 0, &read_value, sizeof(read_value)) == ESP_OK);
CHECK(read_value == 0xdeadbeef);
}
TEST_CASE("EMU raw write function works", "[spi_flash_emu]")
{
FlashEmuFixture f(4);
uint32_t value = 0xdeadbeef;
uint32_t read_value = 0;
CHECK(esp_partition_write_raw(&f.esp_part, 0, &value, sizeof(value)) == ESP_OK);
CHECK(esp_partition_read(&f.esp_part, 0, &read_value, sizeof(read_value)) == ESP_OK);
CHECK(read_value == 0xdeadbeef);
}
TEST_CASE("read/write/erase operation times are calculated correctly", "[spi_flash_emu]")
{
FlashEmuFixture f(1);
uint8_t data[512];
esp_partition_read(&f.esp_part, 0, data, 4);
CHECK(f.emu.getTotalTime() == 7);
CHECK(f.emu.getReadOps() == 1);
CHECK(f.emu.getReadBytes() == 4);
f.emu.clearStats();
esp_partition_read(&f.esp_part, 0, data, 8);
CHECK(f.emu.getTotalTime() == 5);
CHECK(f.emu.getReadOps() == 1);
CHECK(f.emu.getReadBytes() == 8);
f.emu.clearStats();
esp_partition_read(&f.esp_part, 0, data, 16);
CHECK(f.emu.getTotalTime() == 6);
CHECK(f.emu.getReadOps() == 1);
CHECK(f.emu.getReadBytes() == 16);
f.emu.clearStats();
esp_partition_read(&f.esp_part, 0, data, 128);
CHECK(f.emu.getTotalTime() == 18);
CHECK(f.emu.getReadOps() == 1);
CHECK(f.emu.getReadBytes() == 128);
f.emu.clearStats();
esp_partition_read(&f.esp_part, 0, data, 256);
CHECK(f.emu.getTotalTime() == 32);
f.emu.clearStats();
esp_partition_read(&f.esp_part, 0, data, (128+256)/2);
CHECK(f.emu.getTotalTime() == (18+32)/2);
f.emu.clearStats();
esp_partition_write(&f.esp_part, 0, data, 4);
CHECK(f.emu.getTotalTime() == 19);
CHECK(f.emu.getWriteOps() == 1);
CHECK(f.emu.getWriteBytes() == 4);
f.emu.clearStats();
CHECK(f.emu.getWriteOps() == 0);
CHECK(f.emu.getWriteBytes() == 0);
esp_partition_write(&f.esp_part, 0, data, 8);
CHECK(f.emu.getTotalTime() == 23);
f.emu.clearStats();
esp_partition_write(&f.esp_part, 0, data, 16);
CHECK(f.emu.getTotalTime() == 35);
CHECK(f.emu.getWriteOps() == 1);
CHECK(f.emu.getWriteBytes() == 16);
f.emu.clearStats();
esp_partition_write(&f.esp_part, 0, data, 128);
CHECK(f.emu.getTotalTime() == 205);
f.emu.clearStats();
esp_partition_write(&f.esp_part, 0, data, 256);
CHECK(f.emu.getTotalTime() == 417);
f.emu.clearStats();
esp_partition_write(&f.esp_part, 0, data, (128+256)/2);
CHECK(f.emu.getTotalTime() == (205+417)/2);
f.emu.clearStats();
const uint32_t sec_size = esp_partition_get_main_flash_sector_size();
esp_partition_erase_range(&f.esp_part, 0, sec_size);
CHECK(f.emu.getEraseOps() == 1);
CHECK(f.emu.getTotalTime() == 37142);
}
TEST_CASE("data is randomized predictably", "[spi_flash_emu]")
{
SpiFlashEmulator emu1(3);
emu1.randomize(0x12345678);
SpiFlashEmulator emu2(3);
emu2.randomize(0x12345678);
CHECK(std::equal(emu1.bytes(), emu1.bytes() + emu1.size(), emu2.bytes()));
}

View File

@ -499,9 +499,6 @@ components/nvs_flash/src/nvs_pagemanager.hpp
components/nvs_flash/src/nvs_partition_lookup.cpp
components/nvs_flash/src/nvs_partition_lookup.hpp
components/nvs_flash/src/nvs_test_api.h
components/nvs_flash/test_nvs_host/main.cpp
components/nvs_flash/test_nvs_host/sdkconfig.h
components/nvs_flash/test_nvs_host/test_intrusive_list.cpp
components/protocomm/include/transports/protocomm_console.h
components/protocomm/include/transports/protocomm_httpd.h
components/riscv/include/riscv/csr.h