mirror of
https://github.com/espressif/esp-idf.git
synced 2025-09-25 09:42:35 +00:00
esp_partition/linux target: Add functions supporting host tests
Added statistics and wear simulation functions to support migration of remaining storage related host tests from fixture to linux implementation of esp_partition.
This commit is contained in:
@@ -13,6 +13,9 @@
|
||||
#include "unity.h"
|
||||
#include "unity_fixture.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
const char *TAG = "partition_api_test";
|
||||
|
||||
|
||||
TEST_GROUP(partition_api);
|
||||
|
||||
@@ -108,6 +111,238 @@ TEST(partition_api, test_partition_ops)
|
||||
TEST_ASSERT_NOT_NULL(verified_partition);
|
||||
}
|
||||
|
||||
TEST(partition_api, test_partition_mmap)
|
||||
{
|
||||
const esp_partition_t *partition_data = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage");
|
||||
TEST_ASSERT_NOT_NULL(partition_data);
|
||||
|
||||
esp_partition_mmap_memory_t memory = ESP_PARTITION_MMAP_DATA;
|
||||
void *out_ptr = NULL;
|
||||
esp_partition_mmap_handle_t out_handle = 0;
|
||||
|
||||
// no offset, complete length
|
||||
size_t offset = 0;
|
||||
size_t size = partition_data->size;
|
||||
|
||||
esp_err_t err = esp_partition_mmap(partition_data, offset, size, memory, (const void **) &out_ptr, &out_handle);
|
||||
TEST_ESP_OK(err);
|
||||
TEST_ASSERT_NOT_NULL(out_ptr);
|
||||
esp_partition_munmap(out_handle);
|
||||
|
||||
// offset out of partition size
|
||||
offset = partition_data->size+1;
|
||||
size = 1;
|
||||
|
||||
err = esp_partition_mmap(partition_data, offset, size, memory, (const void **) &out_ptr, &out_handle);
|
||||
TEST_ASSERT_EQUAL(err,ESP_ERR_INVALID_ARG);
|
||||
|
||||
// mapped length beyond partition size
|
||||
offset = 1;
|
||||
size = partition_data->size;
|
||||
|
||||
err = esp_partition_mmap(partition_data, offset, size, memory, (const void **) &out_ptr, &out_handle);
|
||||
TEST_ASSERT_EQUAL(err,ESP_ERR_INVALID_SIZE);
|
||||
}
|
||||
|
||||
#define EMULATED_VIRTUAL_SECTOR_COUNT (ESP_PARTITION_EMULATED_FLASH_SIZE / ESP_PARTITION_EMULATED_SECTOR_SIZE)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t read_ops;
|
||||
size_t write_ops;
|
||||
size_t erase_ops;
|
||||
size_t read_bytes;
|
||||
size_t write_bytes;
|
||||
size_t total_time;
|
||||
size_t sector_erase_count[EMULATED_VIRTUAL_SECTOR_COUNT];
|
||||
} t_stats;
|
||||
|
||||
void print_stats(const t_stats *p_stats)
|
||||
{
|
||||
ESP_LOGI(TAG, "read_ops:%06lu write_ops:%06lu erase_ops:%06lu read_bytes:%06lu write_bytes:%06lu total_time:%06lu\n",
|
||||
p_stats->read_ops,
|
||||
p_stats->write_ops,
|
||||
p_stats->erase_ops,
|
||||
p_stats->read_bytes,
|
||||
p_stats->write_bytes,
|
||||
p_stats->total_time);
|
||||
}
|
||||
|
||||
void read_stats(t_stats *p_stats)
|
||||
{
|
||||
p_stats->read_ops = esp_partition_get_read_ops();
|
||||
p_stats->write_ops = esp_partition_get_write_ops();
|
||||
p_stats->erase_ops = esp_partition_get_erase_ops();
|
||||
p_stats->read_bytes = esp_partition_get_read_bytes();
|
||||
p_stats->write_bytes = esp_partition_get_write_bytes();
|
||||
p_stats->total_time = esp_partition_get_total_time();
|
||||
|
||||
for(size_t i = 0; i < EMULATED_VIRTUAL_SECTOR_COUNT; i++)
|
||||
p_stats->sector_erase_count[i] = esp_partition_get_sector_erase_count(i);
|
||||
}
|
||||
|
||||
// evaluates if final stats differ from initial stats by expected difference stats.
|
||||
// if there is no need to evaluate some stats, set respective expeted difference stats members to SIZE_MAX
|
||||
bool evaluate_stats(const t_stats *p_initial_stats, const t_stats *p_final_stats, const t_stats *p_expected_difference_stats)
|
||||
{
|
||||
if(p_expected_difference_stats->read_ops != SIZE_MAX)
|
||||
TEST_ASSERT_EQUAL(p_initial_stats->read_ops + p_expected_difference_stats->read_ops, p_final_stats->read_ops);
|
||||
if(p_expected_difference_stats->write_ops != SIZE_MAX)
|
||||
TEST_ASSERT_EQUAL(p_initial_stats->write_ops + p_expected_difference_stats->write_ops, p_final_stats->write_ops);
|
||||
if(p_expected_difference_stats->erase_ops != SIZE_MAX)
|
||||
TEST_ASSERT_EQUAL(p_initial_stats->erase_ops + p_expected_difference_stats->erase_ops, p_final_stats->erase_ops);
|
||||
if(p_expected_difference_stats->read_bytes != SIZE_MAX)
|
||||
TEST_ASSERT_EQUAL(p_initial_stats->read_bytes + p_expected_difference_stats->read_bytes, p_final_stats->read_bytes);
|
||||
if(p_expected_difference_stats->write_bytes != SIZE_MAX)
|
||||
TEST_ASSERT_EQUAL(p_initial_stats->write_bytes + p_expected_difference_stats->write_bytes, p_final_stats->write_bytes);
|
||||
if(p_expected_difference_stats->total_time != SIZE_MAX)
|
||||
TEST_ASSERT_EQUAL(p_initial_stats->total_time + p_expected_difference_stats->total_time, p_final_stats->total_time);
|
||||
|
||||
for(size_t i = 0; i < EMULATED_VIRTUAL_SECTOR_COUNT; i++)
|
||||
{
|
||||
if(p_expected_difference_stats->sector_erase_count[i] != SIZE_MAX)
|
||||
{
|
||||
size_t expected_value = p_initial_stats->sector_erase_count[i] + p_expected_difference_stats->sector_erase_count[i];
|
||||
size_t final_value = p_final_stats->sector_erase_count[i];
|
||||
|
||||
TEST_ASSERT_EQUAL(expected_value, final_value);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(partition_api, test_partition_stats)
|
||||
{
|
||||
// get storage partition
|
||||
const esp_partition_t *partition_data = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage");
|
||||
TEST_ASSERT_NOT_NULL(partition_data);
|
||||
|
||||
t_stats initial_stats;
|
||||
t_stats final_stats;
|
||||
t_stats zero_stats = {0};
|
||||
|
||||
// get actual statistics
|
||||
read_stats(&initial_stats);
|
||||
|
||||
// prepare buffer for r/w
|
||||
size_t size = partition_data->size;
|
||||
size_t part_offset = partition_data->address; // this is offset of partition data from flash beginning
|
||||
void *test_data_ptr = malloc(size);
|
||||
TEST_ASSERT_NOT_NULL(test_data_ptr);
|
||||
|
||||
// do some writes
|
||||
memset(test_data_ptr, 0xff, size);
|
||||
esp_err_t err = esp_partition_write(partition_data, 0, test_data_ptr, size);
|
||||
TEST_ESP_OK(err);
|
||||
|
||||
// do some reads
|
||||
err = esp_partition_read(partition_data , 0, test_data_ptr, size);
|
||||
TEST_ESP_OK(err);
|
||||
|
||||
// do erase
|
||||
err = esp_partition_erase_range(partition_data, 0, size);
|
||||
TEST_ESP_OK(err);
|
||||
|
||||
// get actual statistics
|
||||
read_stats(&final_stats);
|
||||
|
||||
// evaluate expected results
|
||||
// erase operations are per virtual sectors touched
|
||||
// erase ops size / sector + (part_offset % sector + size % sector) / sector + 1 if ((part_offset % sector + size % sector) % sector > 0)
|
||||
size_t non_aligned_portions = (part_offset % ESP_PARTITION_EMULATED_SECTOR_SIZE) + (size % ESP_PARTITION_EMULATED_SECTOR_SIZE);
|
||||
size_t erase_ops = size / ESP_PARTITION_EMULATED_SECTOR_SIZE;
|
||||
erase_ops += non_aligned_portions / ESP_PARTITION_EMULATED_SECTOR_SIZE;
|
||||
if((non_aligned_portions % ESP_PARTITION_EMULATED_SECTOR_SIZE) > 0)
|
||||
erase_ops += 1;
|
||||
|
||||
t_stats expected_difference_stats = {
|
||||
.read_ops = 1,
|
||||
.write_ops = 1,
|
||||
.erase_ops = erase_ops,
|
||||
.read_bytes = size,
|
||||
.write_bytes = size,
|
||||
.total_time = SIZE_MAX
|
||||
};
|
||||
for (size_t i = 0; i < EMULATED_VIRTUAL_SECTOR_COUNT; i++)
|
||||
expected_difference_stats.sector_erase_count[i] = SIZE_MAX;
|
||||
|
||||
evaluate_stats(&initial_stats, &final_stats, &expected_difference_stats);
|
||||
|
||||
// clear statistics
|
||||
esp_partition_clear_stats();
|
||||
read_stats(&final_stats);
|
||||
|
||||
// evaluate zero statistics
|
||||
evaluate_stats(&zero_stats, &final_stats, &zero_stats);
|
||||
|
||||
free(test_data_ptr);
|
||||
}
|
||||
|
||||
TEST(partition_api, test_partition_wear_emulation)
|
||||
{
|
||||
const esp_partition_t *partition_data = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage");
|
||||
TEST_ASSERT_NOT_NULL(partition_data);
|
||||
|
||||
// no offset, map whole partition
|
||||
size_t offset = 0;
|
||||
size_t size = partition_data->size;
|
||||
|
||||
// prepare test data block
|
||||
void *test_data_ptr = malloc(size);
|
||||
TEST_ASSERT_NOT_NULL(test_data_ptr);
|
||||
memset(test_data_ptr, 0xff, size);
|
||||
|
||||
// --- wear off ---
|
||||
// ensure wear emulation is off
|
||||
esp_partition_fail_after(SIZE_MAX);
|
||||
|
||||
// erase partition data
|
||||
esp_err_t err = esp_partition_erase_range(partition_data, offset, size);
|
||||
TEST_ESP_OK(err);
|
||||
|
||||
// write data - should pass
|
||||
err = esp_partition_write(partition_data, offset, test_data_ptr, size);
|
||||
TEST_ESP_OK(err);
|
||||
|
||||
// erase partition data
|
||||
err = esp_partition_erase_range(partition_data, offset, size);
|
||||
TEST_ESP_OK(err);
|
||||
|
||||
// --- wear on, write ---
|
||||
// ensure wear emulation is on, below the limit for size
|
||||
// esp_partition_write consumes one wear cycle per 4 bytes written
|
||||
esp_partition_fail_after(size / 4 - 1);
|
||||
|
||||
// write data - should fail
|
||||
err = esp_partition_write(partition_data, offset, test_data_ptr, size);
|
||||
TEST_ASSERT_EQUAL(ESP_FAIL, err);
|
||||
|
||||
// --- wear on, erase has just enough wear cycles available---
|
||||
// ensure wear emulation is on, at the limit for size
|
||||
// esp_partition_erase_range consumes one wear cycle per one virtual sector erased
|
||||
esp_partition_fail_after(size / ESP_PARTITION_EMULATED_SECTOR_SIZE);
|
||||
|
||||
// write data - should be ok
|
||||
err = esp_partition_erase_range(partition_data, offset, size);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, err);
|
||||
|
||||
// --- wear on, erase has one cycle less than required---
|
||||
// ensure wear emulation is on, below the limit for size
|
||||
// esp_partition_erase_range consumes one wear cycle per one virtual sector erased
|
||||
esp_partition_fail_after(size / ESP_PARTITION_EMULATED_SECTOR_SIZE - 1);
|
||||
|
||||
// write data - should fail
|
||||
err = esp_partition_erase_range(partition_data, offset, size);
|
||||
TEST_ASSERT_EQUAL(ESP_FAIL, err);
|
||||
|
||||
// ---cleanup ---
|
||||
// disable wear emulation
|
||||
esp_partition_fail_after(SIZE_MAX);
|
||||
free(test_data_ptr);
|
||||
}
|
||||
|
||||
|
||||
TEST_GROUP_RUNNER(partition_api)
|
||||
{
|
||||
RUN_TEST_CASE(partition_api, test_partition_find_basic);
|
||||
@@ -115,6 +350,9 @@ TEST_GROUP_RUNNER(partition_api)
|
||||
RUN_TEST_CASE(partition_api, test_partition_find_data);
|
||||
RUN_TEST_CASE(partition_api, test_partition_find_first);
|
||||
RUN_TEST_CASE(partition_api, test_partition_ops);
|
||||
RUN_TEST_CASE(partition_api, test_partition_mmap);
|
||||
RUN_TEST_CASE(partition_api, test_partition_stats);
|
||||
RUN_TEST_CASE(partition_api, test_partition_wear_emulation);
|
||||
}
|
||||
|
||||
static void run_all_tests(void)
|
||||
|
@@ -6,3 +6,4 @@ CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partition_table.csv"
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE="4MB"
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_ESP_PARTITION_ENABLE_STATS=y
|
||||
|
Reference in New Issue
Block a user