kopia lustrzana https://github.com/espressif/esp-idf
758 wiersze
29 KiB
C
758 wiersze
29 KiB
C
/*
|
|
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Linux host partition API test
|
|
*/
|
|
|
|
#include <string.h>
|
|
#if __has_include(<bsd/string.h>)
|
|
#include <bsd/string.h>
|
|
#endif
|
|
#include <unistd.h>
|
|
#include <sys/time.h>
|
|
#include "esp_err.h"
|
|
#include "esp_partition.h"
|
|
#include "esp_private/partition_linux.h"
|
|
#include "unity.h"
|
|
#include "unity_fixture.h"
|
|
#include "esp_log.h"
|
|
|
|
const char *TAG = "partition_api_test";
|
|
|
|
/* generate timestamp-based filename in /tmp dir */
|
|
static void partition_test_get_unique_filename(char *filename, size_t len)
|
|
{
|
|
struct timeval tv;
|
|
gettimeofday(&tv, NULL);
|
|
long long int nanotimestamp = tv.tv_sec * 1000000000 + tv.tv_usec;
|
|
snprintf(filename, len, "/tmp/espparttest%lld", nanotimestamp);
|
|
}
|
|
|
|
TEST_GROUP(partition_api);
|
|
|
|
TEST_SETUP(partition_api)
|
|
{
|
|
}
|
|
|
|
TEST_TEAR_DOWN(partition_api)
|
|
{
|
|
}
|
|
|
|
TEST(partition_api, test_partition_find_basic)
|
|
{
|
|
esp_partition_iterator_t iter = esp_partition_find(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage");
|
|
TEST_ASSERT_NOT_NULL(iter);
|
|
|
|
const esp_partition_t *part = esp_partition_get(iter);
|
|
TEST_ASSERT_NOT_NULL(part);
|
|
|
|
esp_partition_iterator_release(iter);
|
|
}
|
|
|
|
TEST(partition_api, test_partition_find_app)
|
|
{
|
|
esp_partition_iterator_t iter = esp_partition_find(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, NULL);
|
|
TEST_ASSERT_NOT_NULL(iter);
|
|
size_t counter = 0;
|
|
|
|
while (iter != NULL) {
|
|
const esp_partition_t *part_data = esp_partition_get(iter);
|
|
counter++;
|
|
TEST_ASSERT_NOT_NULL(part_data);
|
|
iter = esp_partition_next(iter);
|
|
}
|
|
esp_partition_iterator_release(iter);
|
|
}
|
|
|
|
TEST(partition_api, test_partition_find_data)
|
|
{
|
|
esp_partition_iterator_t iter = esp_partition_find(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, NULL);
|
|
TEST_ASSERT_NOT_NULL(iter);
|
|
size_t counter = 0;
|
|
|
|
while (iter != NULL) {
|
|
const esp_partition_t *part_data = esp_partition_get(iter);
|
|
counter++;
|
|
TEST_ASSERT_NOT_NULL(part_data);
|
|
iter = esp_partition_next(iter);
|
|
}
|
|
esp_partition_iterator_release(iter);
|
|
}
|
|
|
|
TEST(partition_api, test_partition_find_first)
|
|
{
|
|
const esp_partition_t *partition_app = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, NULL);
|
|
TEST_ASSERT_NOT_NULL(partition_app);
|
|
|
|
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);
|
|
}
|
|
|
|
TEST(partition_api, test_partition_ops)
|
|
{
|
|
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);
|
|
|
|
uint8_t buff[] = "ABCDEFGHIJKLMNOP";
|
|
size_t bufsize = sizeof(buff);
|
|
size_t off = 0x100;
|
|
|
|
// esp_partition_write/raw
|
|
esp_err_t err = esp_partition_write(partition_data, off, (const void *)buff, bufsize);
|
|
TEST_ESP_OK(err);
|
|
|
|
// esp_partition_read/raw
|
|
uint8_t buffout[32] = {0};
|
|
err = esp_partition_read(partition_data, off, (void *)buffout, bufsize);
|
|
TEST_ESP_OK(err);
|
|
|
|
// esp_partition_erase_range
|
|
uint8_t buferase[bufsize];
|
|
memset(buferase, 0xFF, bufsize);
|
|
memset(buffout, 0, sizeof(buffout));
|
|
size_t sector_off = 0; //erase works per whole sector - offset must be aligned to 4kB boundaries
|
|
|
|
err = esp_partition_erase_range(partition_data, sector_off, partition_data->erase_size);
|
|
assert(esp_partition_read(partition_data, off, (void *)buffout, bufsize) == ESP_OK);
|
|
TEST_ESP_OK(err);
|
|
TEST_ASSERT_EQUAL(0, memcmp(buffout, buferase, bufsize));
|
|
|
|
// esp_partition_verify (partition_data)
|
|
const esp_partition_t *verified_partition = esp_partition_verify(partition_data);
|
|
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);
|
|
}
|
|
|
|
TEST(partition_api, test_partition_mmap_diff_size)
|
|
{
|
|
// Scenario: default temporary flash file, explicitly specified size and file with partition table
|
|
// Check the size of "storage" partition. Should be 6M = 6*1024*1024
|
|
|
|
// unmap file to have correct initial conditions, regardless of result
|
|
esp_partition_file_munmap();
|
|
|
|
// get and initialize the control structure for file mmap
|
|
esp_partition_file_mmap_ctrl_t *p_file_mmap_ctrl = esp_partition_get_file_mmap_ctrl_input();
|
|
TEST_ASSERT_NOT_NULL(p_file_mmap_ctrl);
|
|
|
|
memset(p_file_mmap_ctrl, 0, sizeof(*p_file_mmap_ctrl));
|
|
p_file_mmap_ctrl->flash_file_size = 0x800000; // 8MB
|
|
strlcpy(p_file_mmap_ctrl->partition_file_name, "./build/partition_table/partition-table_8M.bin", sizeof(p_file_mmap_ctrl->partition_file_name));
|
|
|
|
// esp_partition_find_first calls the esp_partition_file_mmap in the background
|
|
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);
|
|
|
|
// Check partition size
|
|
size_t exp_size = 0x600000; // 6MB
|
|
size_t act_size = partition_data->size;
|
|
TEST_ASSERT_EQUAL(exp_size, act_size);
|
|
|
|
// cleanup after test
|
|
esp_partition_file_munmap();
|
|
}
|
|
|
|
TEST(partition_api, test_partition_mmap_reopen)
|
|
{
|
|
// Scenario: default temporary flash file, write some data
|
|
// Remember name of temporary file, reset remove flag, unmmap file.
|
|
// Set file name from previous step, mmap file, read and compare data
|
|
|
|
// unmap file to have correct initial conditions, regardless of result
|
|
esp_partition_file_munmap();
|
|
|
|
// get and initialize the control structure for file mmap
|
|
esp_partition_file_mmap_ctrl_t *p_file_mmap_ctrl_input = esp_partition_get_file_mmap_ctrl_input();
|
|
TEST_ASSERT_NOT_NULL(p_file_mmap_ctrl_input);
|
|
|
|
memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input));
|
|
|
|
// esp_partition_find_first calls the esp_partition_file_mmap in the background
|
|
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);
|
|
|
|
const char *test_string = "Is HAL6000 an IBM6000 ?";
|
|
size_t test_string_len = strlen(test_string) + 1;
|
|
|
|
// write test string
|
|
esp_err_t err = esp_partition_write(partition_data, 0, test_string, test_string_len);
|
|
TEST_ESP_OK(err);
|
|
|
|
// remember memory mapped file name
|
|
esp_partition_file_mmap_ctrl_t *p_file_mmap_ctrl_act = esp_partition_get_file_mmap_ctrl_act();
|
|
TEST_ASSERT_NOT_NULL(p_file_mmap_ctrl_act);
|
|
|
|
char generated_file_name[PATH_MAX];
|
|
strlcpy(generated_file_name, p_file_mmap_ctrl_act->flash_file_name, sizeof(generated_file_name));
|
|
|
|
// ensure remove flag is not set
|
|
p_file_mmap_ctrl_input->remove_dump = false;
|
|
|
|
// unmap
|
|
err = esp_partition_file_munmap();
|
|
TEST_ESP_OK(err);
|
|
|
|
// initialize control struct with memory mapped file name
|
|
memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input));
|
|
strlcpy(p_file_mmap_ctrl_input->flash_file_name, generated_file_name, sizeof(p_file_mmap_ctrl_input->flash_file_name));
|
|
|
|
// get partiton
|
|
partition_data = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage");
|
|
TEST_ASSERT_NOT_NULL(partition_data);
|
|
|
|
// read verify string
|
|
char *verify_string = malloc(test_string_len);
|
|
err = esp_partition_read(partition_data, 0, verify_string, test_string_len);
|
|
TEST_ESP_OK(err);
|
|
|
|
// compare strings
|
|
bool strings_equal = (strncmp(test_string, verify_string, test_string_len) == 0);
|
|
TEST_ASSERT_EQUAL(strings_equal, true);
|
|
|
|
free(verify_string);
|
|
|
|
// cleanup after test
|
|
esp_partition_file_munmap();
|
|
}
|
|
|
|
/* Positive TC to prove temporary file removal after file unmap.
|
|
* Error is reported during subsequent attempt to map already removed file.
|
|
* This error proves that file was removed after unmap as requested.
|
|
*/
|
|
TEST(partition_api, test_partition_mmap_remove)
|
|
{
|
|
// Scenario: default temporary flash file, write some data
|
|
// Remember name of temporary file, set remove flag, unmmap file.
|
|
// Set file name from previous step, try to get partition "storage", should fail with NULL returned
|
|
|
|
// unmap file to have correct initial conditions, regardless of result
|
|
esp_partition_file_munmap();
|
|
|
|
// get and initialize the control structure for file mmap
|
|
esp_partition_file_mmap_ctrl_t *p_file_mmap_ctrl_input = esp_partition_get_file_mmap_ctrl_input();
|
|
TEST_ASSERT_NOT_NULL(p_file_mmap_ctrl_input);
|
|
|
|
memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input));
|
|
|
|
// esp_partition_find_first calls the esp_partition_file_mmap in the background
|
|
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);
|
|
|
|
const char *test_string = "This text should dismiss after esp_partition_file_munmap";
|
|
size_t test_string_len = strlen(test_string) + 1;
|
|
|
|
// write test string
|
|
esp_err_t err = esp_partition_write(partition_data, 0, test_string, test_string_len);
|
|
TEST_ESP_OK(err);
|
|
|
|
// remember memory mapped file name
|
|
esp_partition_file_mmap_ctrl_t *p_file_mmap_ctrl_act = esp_partition_get_file_mmap_ctrl_act();
|
|
TEST_ASSERT_NOT_NULL(p_file_mmap_ctrl_act);
|
|
|
|
char generated_file_name[PATH_MAX];
|
|
strlcpy(generated_file_name, p_file_mmap_ctrl_act->flash_file_name, sizeof(generated_file_name));
|
|
|
|
// ensure remove flag is set
|
|
p_file_mmap_ctrl_input->remove_dump = true;
|
|
|
|
// unmap
|
|
err = esp_partition_file_munmap();
|
|
TEST_ESP_OK(err);
|
|
|
|
// initialize control struct with memory mapped file name
|
|
memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input));
|
|
strlcpy(p_file_mmap_ctrl_input->flash_file_name, generated_file_name, sizeof(p_file_mmap_ctrl_input->flash_file_name));
|
|
|
|
// get partiton, should fail with NULL returned
|
|
partition_data = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage");
|
|
TEST_ASSERT_EQUAL(NULL, partition_data);
|
|
|
|
// cleanup after test
|
|
esp_partition_file_munmap();
|
|
memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input));
|
|
}
|
|
|
|
/* Negative TC to ensure mmap setup is consistent prior call to mmap.
|
|
* Configuration specifies both flash file name to be mapped and its size.
|
|
* This is invalid combination as size is determined by the file itself.
|
|
*/
|
|
TEST(partition_api, test_partition_mmap_name_size)
|
|
{
|
|
// Negative Scenario: conflicting settings - flash_file_name together with one or both of flash_file_size, partition_file_name
|
|
// esp_partition_file_mmap should return ESP_ERR_INVALID_ARG
|
|
|
|
// unmap file to have correct initial conditions, regardless of result
|
|
esp_partition_file_munmap();
|
|
|
|
// get and initialize the control structure for file mmap
|
|
esp_partition_file_mmap_ctrl_t *p_file_mmap_ctrl_input = esp_partition_get_file_mmap_ctrl_input();
|
|
TEST_ASSERT_NOT_NULL(p_file_mmap_ctrl_input);
|
|
|
|
memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input));
|
|
const char *flash_file_name = "/tmp/xyz";
|
|
strlcpy(p_file_mmap_ctrl_input->flash_file_name, flash_file_name, sizeof(p_file_mmap_ctrl_input->flash_file_name));
|
|
p_file_mmap_ctrl_input->flash_file_size = 1; // anything different from 0
|
|
|
|
const uint8_t *p_mem_block = NULL;
|
|
esp_err_t err = esp_partition_file_mmap(&p_mem_block);
|
|
|
|
// expected result is invalid argument
|
|
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, err);
|
|
|
|
// cleanup after test
|
|
esp_partition_file_munmap();
|
|
memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input));
|
|
}
|
|
|
|
/* Negative TC to ensure mmap setup checks presence of partition file name (partition table binary file)
|
|
* if flash size parameter was specified.
|
|
* This test case specifies just flash file size but omits partition table binary file name.
|
|
*/
|
|
TEST(partition_api, test_partition_mmap_size_no_partition)
|
|
{
|
|
// Negative Scenario: conflicting settings - flash_file_name empty, flash_file_size set and partition_file_name not set
|
|
// esp_partition_file_mmap should return ESP_ERR_INVALID_ARG
|
|
|
|
// unmap file to have correct initial conditions, regardless of result
|
|
esp_partition_file_munmap();
|
|
|
|
// get and initialize the control structure for file mmap
|
|
esp_partition_file_mmap_ctrl_t *p_file_mmap_ctrl_input = esp_partition_get_file_mmap_ctrl_input();
|
|
TEST_ASSERT_NOT_NULL(p_file_mmap_ctrl_input);
|
|
|
|
memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input));
|
|
p_file_mmap_ctrl_input->flash_file_size = 1; // anything different from 0
|
|
|
|
const uint8_t *p_mem_block = NULL;
|
|
esp_err_t err = esp_partition_file_mmap(&p_mem_block);
|
|
|
|
// expected result is invalid argument
|
|
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, err);
|
|
|
|
// cleanup after test
|
|
esp_partition_file_munmap();
|
|
memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input));
|
|
}
|
|
|
|
/* Negative TC to ensure mmap setup checks presence of flash size parameter if partition file name (partition table binary file) was specified.
|
|
* This test case specifies just partition table binary file name but omits flash file size.
|
|
*/
|
|
TEST(partition_api, test_partition_mmap_no_size_partition)
|
|
{
|
|
// Negative Scenario: conflicting settings - flash_file_name empty, flash_file_size not set and partition_file_name set
|
|
// esp_partition_file_mmap should return ESP_ERR_INVALID_ARG
|
|
|
|
// unmap file to have correct initial conditions, regardless of result
|
|
esp_partition_file_munmap();
|
|
|
|
// get and initialize the control structure for file mmap
|
|
esp_partition_file_mmap_ctrl_t *p_file_mmap_ctrl_input = esp_partition_get_file_mmap_ctrl_input();
|
|
TEST_ASSERT_NOT_NULL(p_file_mmap_ctrl_input);
|
|
|
|
memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input));
|
|
const char *partition_file_name = "/tmp/xyz.bin";
|
|
strlcpy(p_file_mmap_ctrl_input->partition_file_name, partition_file_name, sizeof(p_file_mmap_ctrl_input->partition_file_name));
|
|
|
|
const uint8_t *p_mem_block = NULL;
|
|
esp_err_t err = esp_partition_file_mmap(&p_mem_block);
|
|
|
|
// expected result is invalid argument
|
|
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, err);
|
|
|
|
// cleanup after test
|
|
esp_partition_file_munmap();
|
|
memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input));
|
|
}
|
|
|
|
/* Negative TC to ensure missing flash file to be mapped is reported with correct error code.
|
|
*/
|
|
TEST(partition_api, test_partition_mmap_ffile_nf)
|
|
{
|
|
// Negative Scenario: specified flash_file_name file not found
|
|
// esp_partition_file_mmap should return ESP_ERR_NOT_FOUND
|
|
|
|
// unmap file to have correct initial conditions, regardless of result
|
|
esp_partition_file_munmap();
|
|
|
|
// get and initialize the control structure for file mmap
|
|
esp_partition_file_mmap_ctrl_t *p_file_mmap_ctrl_input = esp_partition_get_file_mmap_ctrl_input();
|
|
TEST_ASSERT_NOT_NULL(p_file_mmap_ctrl_input);
|
|
|
|
memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input));
|
|
|
|
// timestamp-based unique filename, the file is very unlikely to exist => no extra check
|
|
char flash_file_name[40] = {0};
|
|
partition_test_get_unique_filename(flash_file_name, sizeof(flash_file_name));
|
|
|
|
strlcpy(p_file_mmap_ctrl_input->flash_file_name, flash_file_name, sizeof(p_file_mmap_ctrl_input->flash_file_name));
|
|
|
|
const uint8_t *p_mem_block = NULL;
|
|
esp_err_t err = esp_partition_file_mmap(&p_mem_block);
|
|
|
|
// expected result is file not found
|
|
TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, err);
|
|
|
|
// cleanup after test
|
|
esp_partition_file_munmap();
|
|
memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input));
|
|
}
|
|
|
|
/* Negative TC to ensure missing binary partition file to be loaded is reported with correct error code.
|
|
*/
|
|
TEST(partition_api, test_partition_mmap_pfile_nf)
|
|
{
|
|
// Negative Scenario: specified partition_file_name file not found
|
|
// esp_partition_file_mmap should return ESP_ERR_NOT_FOUND
|
|
|
|
// unmap file to have correct initial conditions, regardless of result
|
|
esp_partition_file_munmap();
|
|
|
|
// get and initialize the control structure for file mmap
|
|
esp_partition_file_mmap_ctrl_t *p_file_mmap_ctrl_input = esp_partition_get_file_mmap_ctrl_input();
|
|
TEST_ASSERT_NOT_NULL(p_file_mmap_ctrl_input);
|
|
|
|
memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input));
|
|
|
|
// timestamp-based unique filename, the file is very unlikely to exist => no extra check
|
|
char partition_file_name[40] = {0};
|
|
partition_test_get_unique_filename(partition_file_name, sizeof(partition_file_name));
|
|
|
|
strlcpy(p_file_mmap_ctrl_input->partition_file_name, partition_file_name, sizeof(p_file_mmap_ctrl_input->partition_file_name));
|
|
p_file_mmap_ctrl_input->flash_file_size = 0x10000; // any non zero value to pass validation
|
|
|
|
const uint8_t *p_mem_block = NULL;
|
|
esp_err_t err = esp_partition_file_mmap(&p_mem_block);
|
|
|
|
// expected result is file not found
|
|
TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, err);
|
|
|
|
// cleanup after test
|
|
esp_partition_file_munmap();
|
|
memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input));
|
|
}
|
|
|
|
/* Negative TC to check that requested size of emulated flash is at least so big to be able to load binary partition table.
|
|
* Too small emulated flash size is introduced and respective error code is evaluated after mmap call.
|
|
*/
|
|
TEST(partition_api, test_partition_mmap_size_too_small)
|
|
{
|
|
// Negative Scenario: specified flash file size too small to hold at least partition table at default offset
|
|
// esp_partition_file_mmap should return ESP_ERR_INVALID_SIZE
|
|
|
|
// unmap file to have correct initial conditions, regardless of result
|
|
esp_partition_file_munmap();
|
|
|
|
// get and initialize the control structure for file mmap
|
|
esp_partition_file_mmap_ctrl_t *p_file_mmap_ctrl_input = esp_partition_get_file_mmap_ctrl_input();
|
|
TEST_ASSERT_NOT_NULL(p_file_mmap_ctrl_input);
|
|
|
|
memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input));
|
|
|
|
// set valid partition table name and very small flash size
|
|
strlcpy(p_file_mmap_ctrl_input->partition_file_name, "./build/partition_table/partition-table.bin", sizeof(p_file_mmap_ctrl_input->partition_file_name));
|
|
p_file_mmap_ctrl_input->flash_file_size = 1;
|
|
|
|
const uint8_t *p_mem_block = NULL;
|
|
esp_err_t err = esp_partition_file_mmap(&p_mem_block);
|
|
|
|
// expected result is invalid argument
|
|
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_SIZE, err);
|
|
|
|
// cleanup after test
|
|
esp_partition_file_munmap();
|
|
memset(p_file_mmap_ctrl_input, 0, sizeof(*p_file_mmap_ctrl_input));
|
|
}
|
|
|
|
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;
|
|
size_t sector_erase_count_size;
|
|
} t_stats;
|
|
|
|
void init_stats(t_stats *p_stats)
|
|
{
|
|
memset(p_stats, 0, sizeof(t_stats));
|
|
p_stats->sector_erase_count_size = esp_partition_get_file_mmap_ctrl_act()->flash_file_size / ESP_PARTITION_EMULATED_SECTOR_SIZE;
|
|
p_stats->sector_erase_count = calloc(p_stats->sector_erase_count_size, sizeof(size_t));
|
|
}
|
|
|
|
void dispose_stats(t_stats *p_stats)
|
|
{
|
|
if (p_stats->sector_erase_count != NULL) {
|
|
free(p_stats->sector_erase_count);
|
|
}
|
|
}
|
|
|
|
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 < p_stats->sector_erase_count_size; 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 < p_initial_stats->sector_erase_count_size; 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;
|
|
|
|
init_stats(&initial_stats);
|
|
init_stats(&final_stats);
|
|
init_stats(&zero_stats);
|
|
|
|
// 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;
|
|
init_stats(&expected_difference_stats);
|
|
|
|
expected_difference_stats.read_ops = 1;
|
|
expected_difference_stats.write_ops = 1;
|
|
expected_difference_stats.erase_ops = erase_ops;
|
|
expected_difference_stats.read_bytes = size;
|
|
expected_difference_stats.write_bytes = size;
|
|
expected_difference_stats.total_time = SIZE_MAX;
|
|
for (size_t i = 0; i < expected_difference_stats.sector_erase_count_size; 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 symanically allocated space
|
|
dispose_stats(&initial_stats);
|
|
dispose_stats(&final_stats);
|
|
dispose_stats(&zero_stats);
|
|
dispose_stats(&expected_difference_stats);
|
|
free(test_data_ptr);
|
|
}
|
|
|
|
TEST(partition_api, test_partition_power_off_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);
|
|
|
|
// --- power-off off ---
|
|
// ensure power-off emulation is off
|
|
esp_partition_fail_after(SIZE_MAX, 0);
|
|
|
|
// 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);
|
|
|
|
// --- power-off on, write ---
|
|
// ensure power-off emulation is on, below the limit for size
|
|
// esp_partition_write consumes one power off failure cycle per 4 bytes written
|
|
esp_partition_fail_after(size / 4 - 1, ESP_PARTITION_FAIL_AFTER_MODE_BOTH);
|
|
|
|
// write data - should fail
|
|
err = esp_partition_write(partition_data, offset, test_data_ptr, size);
|
|
TEST_ASSERT_EQUAL(ESP_FAIL, err);
|
|
|
|
// --- power-off on, erase has just enough power off failure cycles available---
|
|
// ensure power-off emulation is on, at the limit for size
|
|
// esp_partition_erase_range consumes one power-off emulation cycle per one virtual sector erased
|
|
esp_partition_fail_after(size / ESP_PARTITION_EMULATED_SECTOR_SIZE, ESP_PARTITION_FAIL_AFTER_MODE_BOTH);
|
|
|
|
// write data - should be ok
|
|
err = esp_partition_erase_range(partition_data, offset, size);
|
|
TEST_ASSERT_EQUAL(ESP_OK, err);
|
|
|
|
// --- power-off on, erase has one cycle less than required---
|
|
// ensure power-off emulation is on, below the limit for size
|
|
// esp_partition_erase_range consumes one power-off emulation cycle per one virtual sector erased
|
|
esp_partition_fail_after(size / ESP_PARTITION_EMULATED_SECTOR_SIZE - 1, ESP_PARTITION_FAIL_AFTER_MODE_BOTH);
|
|
|
|
// write data - should fail
|
|
err = esp_partition_erase_range(partition_data, offset, size);
|
|
TEST_ASSERT_EQUAL(ESP_FAIL, err);
|
|
|
|
// ---cleanup ---
|
|
// disable power-off emulation
|
|
esp_partition_fail_after(SIZE_MAX, 0);
|
|
free(test_data_ptr);
|
|
}
|
|
|
|
TEST_GROUP_RUNNER(partition_api)
|
|
{
|
|
RUN_TEST_CASE(partition_api, test_partition_find_basic);
|
|
RUN_TEST_CASE(partition_api, test_partition_find_app);
|
|
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_mmap_diff_size);
|
|
RUN_TEST_CASE(partition_api, test_partition_mmap_reopen);
|
|
RUN_TEST_CASE(partition_api, test_partition_mmap_remove);
|
|
RUN_TEST_CASE(partition_api, test_partition_mmap_name_size);
|
|
RUN_TEST_CASE(partition_api, test_partition_mmap_size_no_partition);
|
|
RUN_TEST_CASE(partition_api, test_partition_mmap_no_size_partition);
|
|
RUN_TEST_CASE(partition_api, test_partition_mmap_ffile_nf);
|
|
RUN_TEST_CASE(partition_api, test_partition_mmap_pfile_nf);
|
|
RUN_TEST_CASE(partition_api, test_partition_mmap_size_too_small);
|
|
RUN_TEST_CASE(partition_api, test_partition_stats);
|
|
RUN_TEST_CASE(partition_api, test_partition_power_off_emulation);
|
|
}
|
|
|
|
static void run_all_tests(void)
|
|
{
|
|
RUN_TEST_GROUP(partition_api);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
UNITY_MAIN_FUNC(run_all_tests);
|
|
return 0;
|
|
}
|