Merge pull request #9551 from theamirocohen/fix_gen_test_for_flashiap

Modify general blockdevice tests to run all storage components
pull/9581/head
Martin Kojtal 2019-02-01 08:24:09 +01:00 committed by GitHub
commit a0c4646e27
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 264 additions and 73 deletions

View File

@ -25,6 +25,27 @@
#include <inttypes.h>
#include <stdlib.h>
#include "BufferedBlockDevice.h"
#include "BlockDevice.h"
#if COMPONENT_SPIF
#include "SPIFBlockDevice.h"
#endif
#if COMPONENT_QSPIF
#include "QSPIFBlockDevice.h"
#endif
#if COMPONENT_DATAFLASH
#include "DataFlashBlockDevice.h"
#endif
#if COMPONENT_SD
#include "SDBlockDevice.h"
#endif
#if COMPONENT_FLASHIAP
#include "FlashIAPBlockDevice.h"
#endif
using namespace utest::v1;
@ -42,8 +63,122 @@ const struct {
{"total size", &BlockDevice::size},
};
enum bd_type {
spif = 0,
qspif,
dataflash,
sd,
flashiap,
default_bd
};
uint8_t bd_arr[5] = {0};
static uint8_t test_iteration = 0;
static SingletonPtr<PlatformMutex> _mutex;
BlockDevice *block_device = NULL;
#if COMPONENT_FLASHIAP
static inline uint32_t align_up(uint32_t val, uint32_t size)
{
return (((val - 1) / size) + 1) * size;
}
#endif
static BlockDevice *get_bd_instance(uint8_t bd_type)
{
switch (bd_arr[bd_type]) {
case spif: {
#if COMPONENT_SPIF
static SPIFBlockDevice default_bd(
MBED_CONF_SPIF_DRIVER_SPI_MOSI,
MBED_CONF_SPIF_DRIVER_SPI_MISO,
MBED_CONF_SPIF_DRIVER_SPI_CLK,
MBED_CONF_SPIF_DRIVER_SPI_CS,
MBED_CONF_SPIF_DRIVER_SPI_FREQ
);
return &default_bd;
#endif
break;
}
case qspif: {
#if COMPONENT_QSPIF
static QSPIFBlockDevice default_bd(
MBED_CONF_QSPIF_QSPI_IO0,
MBED_CONF_QSPIF_QSPI_IO1,
MBED_CONF_QSPIF_QSPI_IO2,
MBED_CONF_QSPIF_QSPI_IO3,
MBED_CONF_QSPIF_QSPI_SCK,
MBED_CONF_QSPIF_QSPI_CSN,
MBED_CONF_QSPIF_QSPI_POLARITY_MODE,
MBED_CONF_QSPIF_QSPI_FREQ
);
return &default_bd;
#endif
break;
}
case dataflash: {
#if COMPONENT_DATAFLASH
static DataFlashBlockDevice default_bd(
MBED_CONF_DATAFLASH_SPI_MOSI,
MBED_CONF_DATAFLASH_SPI_MISO,
MBED_CONF_DATAFLASH_SPI_CLK,
MBED_CONF_DATAFLASH_SPI_CS
);
return &default_bd;
#endif
break;
}
case sd: {
#if COMPONENT_SD
static SDBlockDevice default_bd(
MBED_CONF_SD_SPI_MOSI,
MBED_CONF_SD_SPI_MISO,
MBED_CONF_SD_SPI_CLK,
MBED_CONF_SD_SPI_CS
);
return &default_bd;
#endif
break;
}
case flashiap: {
#if COMPONENT_FLASHIAP
#if (MBED_CONF_FLASHIAP_BLOCK_DEVICE_SIZE == 0) && (MBED_CONF_FLASHIAP_BLOCK_DEVICE_BASE_ADDRESS == 0xFFFFFFFF)
size_t flash_size;
uint32_t start_address;
uint32_t bottom_address;
mbed::FlashIAP flash;
int ret = flash.init();
if (ret != 0) {
return NULL;
}
//Find the start of first sector after text area
bottom_address = align_up(FLASHIAP_APP_ROM_END_ADDR, flash.get_sector_size(FLASHIAP_APP_ROM_END_ADDR));
start_address = flash.get_flash_start();
flash_size = flash.get_flash_size();
ret = flash.deinit();
static FlashIAPBlockDevice default_bd(bottom_address, start_address + flash_size - bottom_address);
#else
static FlashIAPBlockDevice default_bd;
#endif
return &default_bd;
#endif
break;
}
}
return NULL;
}
// Mutex is protecting rand() per srand for buffer writing and verification.
// Mutex is also protecting printouts for clear logs.
// Mutex is NOT protecting Block Device actions: erase/program/read - which is the purpose of the multithreaded test!
@ -94,16 +229,23 @@ void basic_erase_program_read_test(BlockDevice *block_device, bd_size_t block_si
_mutex->unlock();
}
void test_random_program_read_erase()
void test_init_bd()
{
utest_printf("\nTest Random Program Read Erase Starts..\n");
utest_printf("\nTest Init block device.\n");
BlockDevice *block_device = BlockDevice::get_default_instance();
block_device = get_bd_instance(test_iteration);
TEST_SKIP_UNLESS_MESSAGE(block_device != NULL, "no block device found.");
int err = block_device->init();
TEST_ASSERT_EQUAL(0, err);
}
void test_random_program_read_erase()
{
utest_printf("\nTest Random Program Read Erase Starts..\n");
TEST_SKIP_UNLESS_MESSAGE(block_device != NULL, "no block device found.");
for (unsigned atr = 0; atr < sizeof(ATTRS) / sizeof(ATTRS[0]); atr++) {
static const char *prefixes[] = {"", "k", "M", "G"};
@ -122,6 +264,7 @@ void test_random_program_read_erase()
uint8_t *write_block = new (std::nothrow) uint8_t[block_size];
uint8_t *read_block = new (std::nothrow) uint8_t[block_size];
if (!write_block || !read_block) {
utest_printf("Not enough memory for test\n");
goto end;
@ -131,9 +274,6 @@ void test_random_program_read_erase()
basic_erase_program_read_test(block_device, block_size, write_block, read_block, addrwidth);
}
err = block_device->deinit();
TEST_ASSERT_EQUAL(0, err);
end:
delete[] write_block;
delete[] read_block;
@ -169,17 +309,12 @@ void test_multi_threads()
{
utest_printf("\nTest Multi Threaded Erase/Program/Read Starts..\n");
BlockDevice *block_device = BlockDevice::get_default_instance();
TEST_SKIP_UNLESS_MESSAGE(block_device != NULL, "\nno block device found.\n");
TEST_SKIP_UNLESS_MESSAGE(block_device != NULL, "no block device found.");
char *dummy = new (std::nothrow) char[TEST_NUM_OF_THREADS * OS_STACK_SIZE];
TEST_SKIP_UNLESS_MESSAGE(dummy, "Not enough memory for test.\n");
delete[] dummy;
int err = block_device->init();
TEST_ASSERT_EQUAL(0, err);
for (unsigned atr = 0; atr < sizeof(ATTRS) / sizeof(ATTRS[0]); atr++) {
static const char *prefixes[] = {"", "k", "M", "G"};
for (int i_ind = 3; i_ind >= 0; i_ind--) {
@ -207,9 +342,6 @@ void test_multi_threads()
for (i_ind = 0; i_ind < TEST_NUM_OF_THREADS; i_ind++) {
bd_thread[i_ind].join();
}
err = block_device->deinit();
TEST_ASSERT_EQUAL(0, err);
}
void test_erase_functionality()
@ -222,12 +354,8 @@ void test_erase_functionality()
// 2. Erase selected region
// 3. Read erased region and compare with get_erase_value()
BlockDevice *block_device = BlockDevice::get_default_instance();
TEST_SKIP_UNLESS_MESSAGE(block_device != NULL, "no block device found.");
int err = block_device->init();
TEST_ASSERT_EQUAL(0, err);
// Check erase value
int erase_value_int = block_device->get_erase_value();
utest_printf("block_device->get_erase_value()=%d\n", erase_value_int);
@ -261,7 +389,7 @@ void test_erase_functionality()
// First must Erase given memory region
utest_printf("erasing given memory region\n");
err = block_device->erase(start_address, data_buf_size);
int err = block_device->erase(start_address, data_buf_size);
TEST_ASSERT_EQUAL(0, err);
// Write random data to selected region to make sure data is not accidentally set to "erased" value.
@ -305,16 +433,14 @@ void test_erase_functionality()
free(data_buf);
free(out_data_buf);
// BlockDevice deinitialization
err = block_device->deinit();
TEST_ASSERT_EQUAL(0, err);
}
void test_contiguous_erase_write_read()
{
utest_printf("\nTest Contiguous Erase/Program/Read Starts..\n");
TEST_SKIP_UNLESS_MESSAGE(block_device != NULL, "no block device found.");
// Test flow:
// 1. Erase whole test area
// - Tests contiguous erase
@ -322,13 +448,6 @@ void test_contiguous_erase_write_read()
// - Tests contiguous sector writes
// 3. Return step 2 for whole erase region
BlockDevice *block_device = BlockDevice::get_default_instance();
TEST_SKIP_UNLESS_MESSAGE(block_device != NULL, "no block device found.");
// Initialize BlockDevice
int err = block_device->init();
TEST_ASSERT_EQUAL(0, err);
// Test parameters
bd_size_t erase_size = block_device->get_erase_size();
TEST_ASSERT(erase_size > 0);
@ -378,14 +497,13 @@ void test_contiguous_erase_write_read()
// Allocate write/read buffer
uint8_t *write_read_buf = (uint8_t *)malloc(write_read_buf_size);
if (write_read_buf == NULL) {
block_device->deinit();
TEST_SKIP_MESSAGE("not enough memory for test");
}
utest_printf("write_read_buf_size=%" PRIu64 "\n", (uint64_t)write_read_buf_size);
// Must Erase the whole region first
utest_printf("erasing memory, from 0x%" PRIx64 " of size 0x%" PRIx64 "\n", start_address, contiguous_erase_size);
err = block_device->erase(start_address, contiguous_erase_size);
int err = block_device->erase(start_address, contiguous_erase_size);
TEST_ASSERT_EQUAL(0, err);
// Pre-fill the to-be-erased region. By pre-filling the region,
@ -444,41 +562,29 @@ void test_contiguous_erase_write_read()
}
free(write_read_buf);
// BlockDevice deinitialization
err = block_device->deinit();
TEST_ASSERT_EQUAL(0, err);
}
void test_program_read_small_data_sizes()
{
utest_printf("\nTest program-read small data sizes, from 1 to 7 bytes..\n");
BlockDevice *bd = BlockDevice::get_default_instance();
TEST_SKIP_UNLESS_MESSAGE(block_device != NULL, "no block device found.");
TEST_SKIP_UNLESS_MESSAGE(bd != NULL, "no block device found.");
int err = bd->init();
TEST_ASSERT_EQUAL(0, err);
bd_size_t erase_size = bd->get_erase_size();
bd_size_t program_size = bd->get_program_size();
bd_size_t read_size = bd->get_read_size();
bd_size_t erase_size = block_device->get_erase_size();
bd_size_t program_size = block_device->get_program_size();
bd_size_t read_size = block_device->get_read_size();
TEST_ASSERT(program_size > 0);
err = bd->deinit();
TEST_ASSERT_EQUAL(0, err);
// See that we have enough memory for buffered block device
char *dummy = new (std::nothrow) char[program_size + read_size];
TEST_SKIP_UNLESS_MESSAGE(dummy, "Not enough memory for test.\n");
delete[] dummy;
// use BufferedBlockDevice for better handling of block devices program and read
BufferedBlockDevice *block_device = new BufferedBlockDevice(bd);
BufferedBlockDevice *buff_block_device = new BufferedBlockDevice(block_device);
// BlockDevice initialization
err = block_device->init();
int err = buff_block_device->init();
TEST_ASSERT_EQUAL(0, err);
const char write_buffer[] = "1234567";
@ -488,16 +594,16 @@ void test_program_read_small_data_sizes()
bd_addr_t start_address = 0;
for (int i = 1; i <= 7; i++) {
err = block_device->erase(start_address, erase_size);
err = buff_block_device->erase(start_address, erase_size);
TEST_ASSERT_EQUAL(0, err);
err = block_device->program((const void *)write_buffer, start_address, i);
err = buff_block_device->program((const void *)write_buffer, start_address, i);
TEST_ASSERT_EQUAL(0, err);
err = block_device->sync();
err = buff_block_device->sync();
TEST_ASSERT_EQUAL(0, err);
err = block_device->read(read_buffer, start_address, i);
err = buff_block_device->read(read_buffer, start_address, i);
TEST_ASSERT_EQUAL(0, err);
err = memcmp(write_buffer, read_buffer, i);
@ -505,16 +611,19 @@ void test_program_read_small_data_sizes()
}
// BlockDevice deinitialization
err = block_device->deinit();
err = buff_block_device->deinit();
TEST_ASSERT_EQUAL(0, err);
delete block_device;
delete buff_block_device;
}
void test_get_type_functionality()
{
BlockDevice *block_device = BlockDevice::get_default_instance();
TEST_SKIP_UNLESS_MESSAGE(block_device, "No block device component is defined for this target");
utest_printf("\nTest get blockdevice type..\n");
block_device = BlockDevice::get_default_instance();
TEST_SKIP_UNLESS_MESSAGE(block_device != NULL, "no block device found.");
const char *bd_type = block_device->get_type();
TEST_ASSERT_NOT_EQUAL(0, bd_type);
@ -529,7 +638,20 @@ void test_get_type_functionality()
#elif COMPONET_FLASHIAP
TEST_ASSERT_EQUAL(0, strcmp(bd_type, "FLASHIAP"));
#endif
}
void test_deinit_bd()
{
utest_printf("\nTest deinit block device.\n");
test_iteration++;
TEST_SKIP_UNLESS_MESSAGE(block_device != NULL, "no block device found.");
int err = block_device->deinit();
TEST_ASSERT_EQUAL(0, err);
block_device = NULL;
}
utest::v1::status_t greentea_failure_handler(const Case *const source, const failure_t reason)
@ -538,25 +660,94 @@ utest::v1::status_t greentea_failure_handler(const Case *const source, const fai
return STATUS_CONTINUE;
}
// Test setup
utest::v1::status_t test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(60, "default_auto");
return verbose_test_setup_handler(number_of_cases);
}
typedef struct {
const char *description;
const case_handler_t case_handler;
const case_failure_handler_t failure_handler;
} template_case_t;
Case cases[] = {
Case("Testing BlockDevice erase functionality", test_erase_functionality, greentea_failure_handler),
Case("Testing read write random blocks", test_random_program_read_erase, greentea_failure_handler),
Case("Testing multi threads erase program read", test_multi_threads, greentea_failure_handler),
Case("Testing contiguous erase, write and read", test_contiguous_erase_write_read, greentea_failure_handler),
Case("Testing program read small data sizes", test_program_read_small_data_sizes, greentea_failure_handler),
Case("Testing get type functionality", test_get_type_functionality, greentea_failure_handler)
template_case_t template_cases[] = {
{"Testing Init block device", test_init_bd, greentea_failure_handler},
{"Testing read write random blocks", test_random_program_read_erase, greentea_failure_handler},
{"Testing multi threads erase program read", test_multi_threads, greentea_failure_handler},
{"Testing contiguous erase, write and read", test_contiguous_erase_write_read, greentea_failure_handler},
{"Testing BlockDevice erase functionality", test_erase_functionality, greentea_failure_handler},
{"Testing program read small data sizes", test_program_read_small_data_sizes, greentea_failure_handler},
{"Testing Deinit block device", test_deinit_bd, greentea_failure_handler},
};
Specification specification(test_setup, cases);
template_case_t def_template_case = {"Testing get type functionality", test_get_type_functionality, greentea_failure_handler};
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
return greentea_test_setup_handler(number_of_cases);
}
int get_bd_count()
{
int count = 0;
#if COMPONENT_SPIF
bd_arr[count++] = spif; //0
#endif
#if COMPONENT_QSPIF
bd_arr[count++] = qspif; //1
#endif
#if COMPONENT_DATAFLASH
bd_arr[count++] = dataflash; //2
#endif
#if COMPONENT_SD
bd_arr[count++] = sd; //3
#endif
#if COMPONENT_FLASHIAP
bd_arr[count++] = flashiap; //4
#endif
return count;
}
static const char *prefix[] = {"SPIF ", "QSPIF ", "DATAFLASH ", "SD ", "FLASHIAP ", "DEFAULT "};
int main()
{
GREENTEA_SETUP(3000, "default_auto");
// We want to replicate our test cases to different types
size_t num_cases = sizeof(template_cases) / sizeof(template_case_t);
size_t total_num_cases = 0;
int bd_count = get_bd_count();
void *raw_mem = new (std::nothrow) uint8_t[(bd_count * num_cases + 1) * sizeof(Case)];
Case *cases = static_cast<Case *>(raw_mem);
for (int j = 0; j < bd_count; j++) {
for (size_t i = 0; i < num_cases; i++) {
char desc[128], *desc_ptr;
sprintf(desc, "%s%s", prefix[bd_arr[j]], template_cases[i].description);
desc_ptr = new char[strlen(desc) + 1];
strcpy(desc_ptr, desc);
new (&cases[total_num_cases]) Case((const char *) desc_ptr, template_cases[i].case_handler,
template_cases[i].failure_handler);
total_num_cases++;
}
//Add test_get_type_functionality once, runs on default blockdevice
if (j == bd_count - 1) {
char desc[128], *desc_ptr;
sprintf(desc, "%s%s", prefix[default_bd], def_template_case.description);
desc_ptr = new char[strlen(desc) + 1];
strcpy(desc_ptr, desc);
new (&cases[total_num_cases]) Case((const char *) desc_ptr, def_template_case.case_handler,
def_template_case.failure_handler);
total_num_cases++;
}
}
Specification specification(greentea_test_setup, cases, total_num_cases,
greentea_test_teardown_handler, (test_failure_handler_t)greentea_failure_handler);
return !Harness::run(specification);
}