From: Ivan Grokhotkov Date: Mon, 10 Apr 2017 14:07:10 +0000 (+0800) Subject: wear_levelling: add unit test sub-component X-Git-Tag: v2.1-rc1~161^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=36241493447cc71aaf76ca4b62124dafe60dedc2;p=esp-idf wear_levelling: add unit test sub-component --- diff --git a/components/wear_levelling/test/component.mk b/components/wear_levelling/test/component.mk new file mode 100644 index 0000000000..ce464a212a --- /dev/null +++ b/components/wear_levelling/test/component.mk @@ -0,0 +1 @@ +COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive diff --git a/components/wear_levelling/test/test_wl.c b/components/wear_levelling/test/test_wl.c new file mode 100644 index 0000000000..b34d8a86ee --- /dev/null +++ b/components/wear_levelling/test/test_wl.c @@ -0,0 +1,151 @@ +#include +#include "unity.h" +#include "wear_levelling.h" +#include "test_utils.h" +#include "freertos/FreeRTOS.h" +#include "freertos/portable.h" +#include "freertos/task.h" +#include "freertos/semphr.h" + +TEST_CASE("wl_unmount doesn't leak memory", "[wear_levelling]") +{ + const esp_partition_t *partition = get_test_data_partition(); + wl_handle_t handle; + // dummy unmount is needed to initialize static lock in WL + wl_unmount(WL_INVALID_HANDLE); + size_t size_before = xPortGetFreeHeapSize(); + TEST_ESP_OK(wl_mount(partition, &handle)); + wl_unmount(handle); + size_t size_after = xPortGetFreeHeapSize(); + TEST_ASSERT_EQUAL_UINT32(size_before, size_after); +} + +TEST_CASE("wl_mount check partition parameters", "[wear_levelling][ignore]") +{ + const esp_partition_t *test_partition = get_test_data_partition(); + esp_partition_t fake_partition; + memcpy(&fake_partition, test_partition, sizeof(fake_partition)); + wl_handle_t handle; + size_t size_before, size_after; + + // test small partition + fake_partition.size = SPI_FLASH_SEC_SIZE; + size_before = xPortGetFreeHeapSize(); + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, wl_mount(&fake_partition, &handle)); + size_after = xPortGetFreeHeapSize(); + TEST_ASSERT_EQUAL_HEX32(size_before, size_after); + // currently this test leaks memory + + // test slightly bigger partition + fake_partition.size = SPI_FLASH_SEC_SIZE * 3; + size_before = xPortGetFreeHeapSize(); + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, wl_mount(&fake_partition, &handle)); + size_after = xPortGetFreeHeapSize(); + TEST_ASSERT_EQUAL_HEX32(size_before, size_after); + // currently this test hangs +} + +typedef struct { + size_t offset; + bool write; + size_t word_count; + int seed; + SemaphoreHandle_t done; + int result; + wl_handle_t handle; +} read_write_test_arg_t; + +#define READ_WRITE_TEST_ARG_INIT(offset_, seed_, handle_) \ + { \ + .offset = offset_, \ + .seed = seed_, \ + .word_count = 1024, \ + .write = true, \ + .done = xSemaphoreCreateBinary(), \ + .handle = handle_ \ + } + +static void read_write_task(void* param) +{ + read_write_test_arg_t* args = (read_write_test_arg_t*) param; + esp_err_t err; + srand(args->seed); + for (size_t i = 0; i < args->word_count; ++i) { + uint32_t val = rand(); + if (args->write) { + err = wl_write(args->handle, args->offset + i * sizeof(val), &val, sizeof(val)); + if (err != ESP_OK) { + args->result = err; + goto done; + } + } else { + uint32_t rval; + err = wl_read(args->handle, args->offset + i * sizeof(rval), &rval, sizeof(rval)); + if (err != ESP_OK || rval != val) { + ets_printf("E: i=%d, cnt=%d rval=%d val=%d\n\n", i, args->word_count, rval, val); + args->result = ESP_FAIL; + goto done; + } + } + } + args->result = ESP_OK; + +done: + xSemaphoreGive(args->done); + vTaskDelay(1); + vTaskDelete(NULL); +} + +TEST_CASE("multiple tasks can access wl handle simultaneously", "[wear_levelling]") +{ + const esp_partition_t *partition = get_test_data_partition(); + wl_handle_t handle; + TEST_ESP_OK(wl_mount(partition, &handle)); + + size_t sector_size = wl_sector_size(handle); + TEST_ESP_OK(wl_erase_range(handle, 0, sector_size * 4)); + read_write_test_arg_t args1 = READ_WRITE_TEST_ARG_INIT(0, 1, handle); + read_write_test_arg_t args2 = READ_WRITE_TEST_ARG_INIT(sector_size, 2, handle); + const size_t stack_size = 4096; + + printf("writing 1 and 2\n"); + xTaskCreatePinnedToCore(&read_write_task, "rw1", stack_size, &args1, 3, NULL, 0); + xTaskCreatePinnedToCore(&read_write_task, "rw2", stack_size, &args2, 3, NULL, 1); + + xSemaphoreTake(args1.done, portMAX_DELAY); + printf("f1 done\n"); + TEST_ASSERT_EQUAL(ESP_OK, args1.result); + xSemaphoreTake(args2.done, portMAX_DELAY); + printf("f2 done\n"); + TEST_ASSERT_EQUAL(ESP_OK, args2.result); + + args1.write = false; + args2.write = false; + read_write_test_arg_t args3 = READ_WRITE_TEST_ARG_INIT(2 * sector_size, 3, handle); + read_write_test_arg_t args4 = READ_WRITE_TEST_ARG_INIT(3 * sector_size, 4, handle); + + printf("reading 1 and 2, writing 3 and 4\n"); + xTaskCreatePinnedToCore(&read_write_task, "rw3", stack_size, &args3, 3, NULL, 1); + xTaskCreatePinnedToCore(&read_write_task, "rw4", stack_size, &args4, 3, NULL, 0); + xTaskCreatePinnedToCore(&read_write_task, "rw1", stack_size, &args1, 3, NULL, 0); + xTaskCreatePinnedToCore(&read_write_task, "rw2", stack_size, &args2, 3, NULL, 1); + + xSemaphoreTake(args1.done, portMAX_DELAY); + printf("f1 done\n"); + TEST_ASSERT_EQUAL(ESP_OK, args1.result); + xSemaphoreTake(args2.done, portMAX_DELAY); + printf("f2 done\n"); + TEST_ASSERT_EQUAL(ESP_OK, args2.result); + xSemaphoreTake(args3.done, portMAX_DELAY); + printf("f3 done\n"); + TEST_ASSERT_EQUAL(ESP_OK, args3.result); + xSemaphoreTake(args4.done, portMAX_DELAY); + printf("f4 done\n"); + TEST_ASSERT_EQUAL(ESP_OK, args4.result); + + vSemaphoreDelete(args1.done); + vSemaphoreDelete(args2.done); + vSemaphoreDelete(args3.done); + vSemaphoreDelete(args4.done); + wl_unmount(handle); +}