per Intel policy to include file commit date using git cmd below. The policy does not apply to non-Intel (C) notices. git log --follow -C90% --format=%ad --date default <file> | tail -1 and then pull just the 4 digit year from the result. Intel copyrights were not added to files where Intel either had no contribution ot the contribution lacked substance (ie license header updates, formatting changes, etc). Contribution date used "--follow -C95%" to get the most accurate date. Note that several files in this patch didn't end the license/(c) block with a blank comment line so these were added as the vast majority of files do have this last blank line. Simply there for consistency. Signed-off-by: paul luse <paul.e.luse@intel.com> Change-Id: Id5b7ce4f658fe87132f14139ead58d6e285c04d4 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15192 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Community-CI: Mellanox Build Bot
1111 lines
26 KiB
C
1111 lines
26 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright (C) 2022 Intel Corporation.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
#include <sys/queue.h>
|
|
|
|
#include "spdk/stdinc.h"
|
|
|
|
#include "spdk_cunit.h"
|
|
#include "common/lib/test_env.c"
|
|
|
|
#include "ftl/mngt/ftl_mngt.c"
|
|
|
|
#define CALLER_CB_RET_VALUE 999
|
|
|
|
/* list for structure with results of tests from callbacks */
|
|
struct entry {
|
|
int data;
|
|
TAILQ_ENTRY(entry) entries;
|
|
};
|
|
|
|
TAILQ_HEAD(listhead, entry) g_head;
|
|
|
|
struct thread_send_msg_container {
|
|
spdk_msg_fn fn;
|
|
void *ctx;
|
|
} g_thread_send_msg_container;
|
|
|
|
struct spdk_ftl_dev g_dev;
|
|
|
|
int
|
|
spdk_thread_send_msg(const struct spdk_thread *thread, spdk_msg_fn fn, void *ctx)
|
|
{
|
|
g_thread_send_msg_container.fn = fn;
|
|
g_thread_send_msg_container.ctx = ctx;
|
|
return 0;
|
|
}
|
|
|
|
struct spdk_thread *
|
|
spdk_get_thread(void)
|
|
{
|
|
struct spdk_thread *thd = (struct spdk_thread *)0x1;
|
|
return thd;
|
|
}
|
|
|
|
static int
|
|
setup_test_list(void)
|
|
{
|
|
TAILQ_INIT(&g_head);
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
check_list_empty(void)
|
|
{
|
|
CU_ASSERT_TRUE(TAILQ_EMPTY(&g_head));
|
|
}
|
|
|
|
static void
|
|
add_elem_to_test_list(int data)
|
|
{
|
|
struct entry *en = calloc(1, sizeof(*en));
|
|
SPDK_CU_ASSERT_FATAL(en != NULL);
|
|
en->data = data;
|
|
TAILQ_INSERT_TAIL(&g_head, en, entries);
|
|
}
|
|
|
|
static void
|
|
check_elem_on_list_and_remove(int compared_elem)
|
|
{
|
|
struct entry *en = TAILQ_FIRST(&g_head);
|
|
if (en != NULL) {
|
|
CU_ASSERT_EQUAL(en->data, compared_elem);
|
|
TAILQ_REMOVE(&g_head, en, entries);
|
|
free(en);
|
|
} else {
|
|
CU_FAIL("not null value was expected");
|
|
}
|
|
}
|
|
|
|
static void
|
|
fn_finish(struct spdk_ftl_dev *dev, void *ctx, int status)
|
|
{
|
|
add_elem_to_test_list(CALLER_CB_RET_VALUE);
|
|
g_thread_send_msg_container.fn = NULL;
|
|
g_thread_send_msg_container.ctx = NULL;
|
|
}
|
|
|
|
typedef int (*ftl_execute_fn)(struct spdk_ftl_dev *dev,
|
|
const struct ftl_mngt_process_desc *process,
|
|
ftl_mngt_completion cb, void *cb_cntx);
|
|
|
|
static void
|
|
run_ftl_mngt_with_cb_cntx(ftl_execute_fn exec_fn,
|
|
const struct ftl_mngt_process_desc *process, void *cb_cntx)
|
|
{
|
|
int result = exec_fn(&g_dev, process, fn_finish, cb_cntx);
|
|
CU_ASSERT_EQUAL(result, 0);
|
|
while (g_thread_send_msg_container.fn != NULL) {
|
|
g_thread_send_msg_container.fn(g_thread_send_msg_container.ctx);
|
|
}
|
|
}
|
|
|
|
static void
|
|
run_ftl_mngt(ftl_execute_fn exec_fn,
|
|
const struct ftl_mngt_process_desc *process)
|
|
{
|
|
run_ftl_mngt_with_cb_cntx(exec_fn, process, NULL);
|
|
}
|
|
|
|
/*-
|
|
* test 1
|
|
* tests simple invoking next steps
|
|
* it is shown if ftl_mngt_process_execute and ftl_mngt_process_rollback invoke functions in proper order
|
|
* (functions call only ftl_mngt_next_step)
|
|
*/
|
|
|
|
static void
|
|
fn_1_1_action(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(1);
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
|
|
static void
|
|
fn_1_1_cleanup(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(-1);
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
|
|
static void
|
|
fn_1_2_action(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(2);
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
|
|
static void
|
|
fn_1_3_action(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(3);
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
|
|
static void
|
|
fn_1_3_cleanup(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(-3);
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
|
|
static struct ftl_mngt_process_desc pdesc_test_1 = {
|
|
.name = "process 1",
|
|
.steps = {
|
|
{
|
|
.name = "step 1",
|
|
.action = fn_1_1_action,
|
|
.cleanup = fn_1_1_cleanup
|
|
},
|
|
{
|
|
.name = "step 2",
|
|
.action = fn_1_2_action
|
|
},
|
|
{
|
|
.name = "step 3",
|
|
.action = fn_1_3_action,
|
|
.cleanup = fn_1_3_cleanup
|
|
},
|
|
{}
|
|
}
|
|
};
|
|
|
|
static void
|
|
test_next_step(void)
|
|
{
|
|
run_ftl_mngt(ftl_mngt_process_execute, &pdesc_test_1);
|
|
|
|
/* check proper order of action functions */
|
|
for (int i = 1; i <= 3; i++) {
|
|
check_elem_on_list_and_remove(i);
|
|
}
|
|
|
|
/* check if caller callback was invoked */
|
|
check_elem_on_list_and_remove(CALLER_CB_RET_VALUE);
|
|
|
|
run_ftl_mngt(ftl_mngt_process_rollback, &pdesc_test_1);
|
|
|
|
/* Check proper order of cleanup functions.
|
|
* Cleanup functions add to list opposite values to action functions.
|
|
* Cleanup functions are invoked in reverse order,
|
|
* moreover action 2 does not have cleanup,
|
|
* so expected values are -3, then -1 */
|
|
check_elem_on_list_and_remove(-3);
|
|
check_elem_on_list_and_remove(-1);
|
|
|
|
/* check if caller callback was invoked */
|
|
check_elem_on_list_and_remove(CALLER_CB_RET_VALUE);
|
|
|
|
check_list_empty();
|
|
}
|
|
|
|
/*-
|
|
* test 2
|
|
* tests action and cleanup function which invoke
|
|
* ftl_mngt_continue_step function
|
|
*/
|
|
|
|
static void
|
|
fn_2_common_part(struct ftl_mngt_process *mngt, int elem)
|
|
{
|
|
struct entry *en = TAILQ_LAST(&g_head, listhead);
|
|
|
|
if (en == NULL || en->data != elem) {
|
|
/* if function was invoked 1st time, make it once again */
|
|
add_elem_to_test_list(elem);
|
|
ftl_mngt_continue_step(mngt);
|
|
} else {
|
|
/* otherwise go to the next function */
|
|
add_elem_to_test_list(elem);
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
}
|
|
|
|
static void
|
|
fn_2_1_action(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
fn_2_common_part(mngt, 1);
|
|
}
|
|
|
|
static void
|
|
fn_2_1_cleanup(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
fn_2_common_part(mngt, -1);
|
|
}
|
|
|
|
static void
|
|
fn_2_2_action(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
fn_2_common_part(mngt, 2);
|
|
}
|
|
|
|
static void
|
|
fn_2_2_cleanup(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
fn_2_common_part(mngt, -2);
|
|
}
|
|
|
|
static struct ftl_mngt_process_desc pdesc_test_2 = {
|
|
.name = "process 2",
|
|
.steps = {
|
|
{
|
|
.name = "step 1",
|
|
.action = fn_2_1_action,
|
|
.cleanup = fn_2_1_cleanup
|
|
},
|
|
{
|
|
.name = "step 2",
|
|
.action = fn_2_2_action,
|
|
.cleanup = fn_2_2_cleanup
|
|
},
|
|
{}
|
|
}
|
|
};
|
|
|
|
static void
|
|
test_continue_step(void)
|
|
{
|
|
run_ftl_mngt(ftl_mngt_process_execute, &pdesc_test_2);
|
|
|
|
/* check proper order of action functions */
|
|
check_elem_on_list_and_remove(1);
|
|
check_elem_on_list_and_remove(1);
|
|
check_elem_on_list_and_remove(2);
|
|
check_elem_on_list_and_remove(2);
|
|
|
|
/* check if caller callback was invoked */
|
|
check_elem_on_list_and_remove(CALLER_CB_RET_VALUE);
|
|
|
|
run_ftl_mngt(ftl_mngt_process_rollback, &pdesc_test_2);
|
|
|
|
/* check proper order of action functions */
|
|
check_elem_on_list_and_remove(-2);
|
|
check_elem_on_list_and_remove(-2);
|
|
check_elem_on_list_and_remove(-1);
|
|
check_elem_on_list_and_remove(-1);
|
|
|
|
/* check if caller callback was invoked */
|
|
check_elem_on_list_and_remove(CALLER_CB_RET_VALUE);
|
|
|
|
check_list_empty();
|
|
}
|
|
|
|
/*-
|
|
* test 3
|
|
* tests ftl_mngt_alloc_step_cntx and all ftl_mngt_get functions
|
|
*/
|
|
|
|
const int PROCESS_CNTX_TEST_VAL_0 = 21;
|
|
const int PROCESS_CNTX_TEST_VAL_1 = 37;
|
|
const int STEP_CNTX_TEST_VAL = 1;
|
|
|
|
static void
|
|
put_on_list(void)
|
|
{
|
|
struct entry *en = calloc(1, sizeof(*en));
|
|
SPDK_CU_ASSERT_FATAL(en != NULL);
|
|
TAILQ_INSERT_TAIL(&g_head, en, entries);
|
|
}
|
|
|
|
static bool
|
|
check_if_list_empty_and_clean(void)
|
|
{
|
|
struct entry *en = TAILQ_FIRST(&g_head);
|
|
if (en == NULL) {
|
|
return true;
|
|
} else {
|
|
TAILQ_REMOVE(&g_head, en, entries);
|
|
free(en);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static void
|
|
fn_3_1_action(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
int *step_cntx_ptr, *process_cntx_ptr;
|
|
char *caller_cntx_ptr;
|
|
int status;
|
|
|
|
step_cntx_ptr = ftl_mngt_get_step_ctx(mngt);
|
|
if (check_if_list_empty_and_clean()) {
|
|
/* In 1st run of this function test list is empty
|
|
* and 'if' is true, this part of function is done.
|
|
* That 'if' part ends with ftl_mngt_continue_step,
|
|
* so function will be called once again.
|
|
* Element is added to the test list
|
|
* to invoke 'else' in second run */
|
|
put_on_list();
|
|
/* this step descriptor does not locate any context
|
|
* at the beginning,
|
|
* so pointer should contain NULL */
|
|
CU_ASSERT_PTR_NULL(step_cntx_ptr);
|
|
|
|
status = ftl_mngt_alloc_step_ctx(mngt, sizeof(*step_cntx_ptr));
|
|
SPDK_CU_ASSERT_FATAL(status == 0);
|
|
step_cntx_ptr = ftl_mngt_get_step_ctx(mngt);
|
|
/* now pointer should point to allocated context */
|
|
CU_ASSERT_PTR_NOT_NULL(step_cntx_ptr);
|
|
|
|
/* this value should be retrieved in second run of function
|
|
* (in 'else' part) */
|
|
*step_cntx_ptr = STEP_CNTX_TEST_VAL;
|
|
|
|
ftl_mngt_continue_step(mngt);
|
|
} else {
|
|
/* In second run retrieved pointer is not empty.
|
|
* Moreover it should contain value allocated for this step
|
|
* in previous run of function */
|
|
CU_ASSERT_PTR_NOT_NULL(step_cntx_ptr);
|
|
CU_ASSERT_EQUAL(*step_cntx_ptr, STEP_CNTX_TEST_VAL);
|
|
|
|
/* check getting device */
|
|
CU_ASSERT_EQUAL(ftl_mngt_get_dev(mngt), dev);
|
|
CU_ASSERT_EQUAL(ftl_mngt_get_dev(mngt), &g_dev);
|
|
|
|
/* tests for process context */
|
|
process_cntx_ptr = ftl_mngt_get_process_ctx(mngt);
|
|
|
|
/* 1st get of process context, should be clear ('0' values) */
|
|
CU_ASSERT_EQUAL(process_cntx_ptr[0], 0);
|
|
CU_ASSERT_EQUAL(process_cntx_ptr[1], 0);
|
|
|
|
/* Random values put in process context.
|
|
* Should be retrieved in the next function
|
|
* (it is common space for the entire process) */
|
|
process_cntx_ptr[0] = PROCESS_CNTX_TEST_VAL_0;
|
|
process_cntx_ptr[1] = PROCESS_CNTX_TEST_VAL_1;
|
|
|
|
/* tests for caller context */
|
|
caller_cntx_ptr = ftl_mngt_get_caller_ctx(mngt);
|
|
|
|
/* check previously located values */
|
|
CU_ASSERT_EQUAL(caller_cntx_ptr[0], 'd');
|
|
CU_ASSERT_EQUAL(caller_cntx_ptr[1], 'a');
|
|
CU_ASSERT_EQUAL(caller_cntx_ptr[2], 'j');
|
|
|
|
/* insert new */
|
|
caller_cntx_ptr[0] = ' ';
|
|
caller_cntx_ptr[1] = 'k';
|
|
caller_cntx_ptr[2] = 'a';
|
|
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
}
|
|
|
|
static void
|
|
fn_3_2_action(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
int *step_cntx_ptr, *process_cntx_ptr;
|
|
char *caller_cntx_ptr;
|
|
int status;
|
|
|
|
step_cntx_ptr = ftl_mngt_get_step_ctx(mngt);
|
|
/* context of this step descriptor is never empty
|
|
* so pointer cannot contain NULL */
|
|
CU_ASSERT_PTR_NOT_NULL(step_cntx_ptr);
|
|
|
|
if (check_if_list_empty_and_clean()) {
|
|
/* In 1st run of this function test list is empty
|
|
* and 'if' is true, this part of function is done.
|
|
* That 'if' part ends with ftl_mngt_continue_step,
|
|
* so function will be called once again.
|
|
* Element is added to the test list
|
|
* to invoke 'else' in second run */
|
|
put_on_list();
|
|
|
|
/* check getting device */
|
|
CU_ASSERT_EQUAL(ftl_mngt_get_dev(mngt), dev);
|
|
CU_ASSERT_EQUAL(ftl_mngt_get_dev(mngt), &g_dev);
|
|
|
|
/* tests for process context */
|
|
process_cntx_ptr = ftl_mngt_get_process_ctx(mngt);
|
|
|
|
/* check if it is possible to retrieve values located
|
|
* in process context by previous function */
|
|
CU_ASSERT_EQUAL(process_cntx_ptr[0], PROCESS_CNTX_TEST_VAL_0);
|
|
CU_ASSERT_EQUAL(process_cntx_ptr[1], PROCESS_CNTX_TEST_VAL_1);
|
|
|
|
/* tests for caller context */
|
|
caller_cntx_ptr = ftl_mngt_get_caller_ctx(mngt);
|
|
|
|
/* check previously located values */
|
|
CU_ASSERT_EQUAL(caller_cntx_ptr[0], ' ');
|
|
CU_ASSERT_EQUAL(caller_cntx_ptr[1], 'k');
|
|
CU_ASSERT_EQUAL(caller_cntx_ptr[2], 'a');
|
|
|
|
/* insert new */
|
|
caller_cntx_ptr[0] = 'm';
|
|
caller_cntx_ptr[1] = 'i';
|
|
caller_cntx_ptr[2] = 'e';
|
|
|
|
/* first run of step so reserved step context
|
|
* was never used before and should contain 0 */
|
|
CU_ASSERT_EQUAL(*step_cntx_ptr, 0);
|
|
|
|
/* this value should be retrieved in second run of function
|
|
* (in 'else' part) */
|
|
*step_cntx_ptr = STEP_CNTX_TEST_VAL;
|
|
|
|
ftl_mngt_continue_step(mngt);
|
|
} else {
|
|
/* In second run retrieved pointer should contain value
|
|
* allocated for this step in previous run of function */
|
|
CU_ASSERT_EQUAL(*step_cntx_ptr, STEP_CNTX_TEST_VAL);
|
|
|
|
status = ftl_mngt_alloc_step_ctx(mngt, sizeof(*step_cntx_ptr));
|
|
SPDK_CU_ASSERT_FATAL(status == 0);
|
|
step_cntx_ptr = ftl_mngt_get_step_ctx(mngt);
|
|
|
|
/* now pointer should point to newly allocated context
|
|
* and be cleaned up (should contain '0') */
|
|
CU_ASSERT_PTR_NOT_NULL(step_cntx_ptr);
|
|
CU_ASSERT_EQUAL(*step_cntx_ptr, 0);
|
|
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
}
|
|
|
|
static void
|
|
fn_3_2_cleanup(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
int *step_cntx_ptr, *process_cntx_ptr;
|
|
char *caller_cntx_ptr;
|
|
int status;
|
|
|
|
step_cntx_ptr = ftl_mngt_get_step_ctx(mngt);
|
|
/* context of this step descriptor is never empty
|
|
* so pointer cannot contain NULL */
|
|
CU_ASSERT_PTR_NOT_NULL(step_cntx_ptr);
|
|
|
|
if (check_if_list_empty_and_clean()) {
|
|
/* In 1st run of this function test list is empty
|
|
* and 'if' is true, this part of function is done.
|
|
* That 'if' part ends with ftl_mngt_continue_step,
|
|
* so function will be called once again.
|
|
* Element is added to the test list
|
|
* to invoke 'else' in second run */
|
|
put_on_list();
|
|
|
|
/* first run of step so reserved step context
|
|
* was never used before and should contain 0 */
|
|
CU_ASSERT_EQUAL(*step_cntx_ptr, 0);
|
|
|
|
/* this value should be retrieved in second run of function
|
|
* (in 'else' part) */
|
|
*step_cntx_ptr = STEP_CNTX_TEST_VAL;
|
|
|
|
ftl_mngt_continue_step(mngt);
|
|
} else {
|
|
/* In second run retrieved pointer should contain value
|
|
* allocated for this step in previous run of function */
|
|
CU_ASSERT_EQUAL(*step_cntx_ptr, STEP_CNTX_TEST_VAL);
|
|
|
|
status = ftl_mngt_alloc_step_ctx(mngt, sizeof(*step_cntx_ptr));
|
|
SPDK_CU_ASSERT_FATAL(status == 0);
|
|
step_cntx_ptr = ftl_mngt_get_step_ctx(mngt);
|
|
|
|
/* now pointer should point to newly allocated context
|
|
* and be cleaned up (should contain '0') */
|
|
CU_ASSERT_PTR_NOT_NULL(step_cntx_ptr);
|
|
CU_ASSERT_EQUAL(*step_cntx_ptr, 0);
|
|
|
|
/* check getting device */
|
|
CU_ASSERT_EQUAL(ftl_mngt_get_dev(mngt), dev);
|
|
CU_ASSERT_EQUAL(ftl_mngt_get_dev(mngt), &g_dev);
|
|
|
|
/* tests for process context */
|
|
process_cntx_ptr = ftl_mngt_get_process_ctx(mngt);
|
|
|
|
/* 1st get of process context, should be clear ('0' values) */
|
|
CU_ASSERT_EQUAL(process_cntx_ptr[0], 0);
|
|
CU_ASSERT_EQUAL(process_cntx_ptr[1], 0);
|
|
|
|
/* Random values put in process context.
|
|
* Should be retrieved in the next function
|
|
* (it is common space for the entire process) */
|
|
process_cntx_ptr[0] = PROCESS_CNTX_TEST_VAL_0;
|
|
process_cntx_ptr[1] = PROCESS_CNTX_TEST_VAL_1;
|
|
|
|
/* tests for caller context */
|
|
caller_cntx_ptr = ftl_mngt_get_caller_ctx(mngt);
|
|
|
|
/* check previously located values */
|
|
CU_ASSERT_EQUAL(caller_cntx_ptr[0], 'm');
|
|
CU_ASSERT_EQUAL(caller_cntx_ptr[1], 'i');
|
|
CU_ASSERT_EQUAL(caller_cntx_ptr[2], 'e');
|
|
|
|
/* insert new */
|
|
caller_cntx_ptr[0] = 'n';
|
|
caller_cntx_ptr[1] = 'i';
|
|
caller_cntx_ptr[2] = 'a';
|
|
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
}
|
|
|
|
static void
|
|
fn_3_1_cleanup(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
int *step_cntx_ptr, *process_cntx_ptr;
|
|
char *caller_cntx_ptr;
|
|
int status;
|
|
|
|
step_cntx_ptr = ftl_mngt_get_step_ctx(mngt);
|
|
if (check_if_list_empty_and_clean()) {
|
|
/* In 1st run of this function test list is empty
|
|
* and 'if' is true, this part of function is done.
|
|
* That 'if' part ends with ftl_mngt_continue_step,
|
|
* so function will be called once again.
|
|
* Element is added to the test list
|
|
* to invoke 'else' in second run */
|
|
put_on_list();
|
|
/* this step descriptor does not locate any context
|
|
* at the beginning,
|
|
* so pointer should contain NULL */
|
|
CU_ASSERT_PTR_NULL(step_cntx_ptr);
|
|
|
|
/* check getting device */
|
|
CU_ASSERT_EQUAL(ftl_mngt_get_dev(mngt), dev);
|
|
CU_ASSERT_EQUAL(ftl_mngt_get_dev(mngt), &g_dev);
|
|
|
|
/* tests for process context */
|
|
process_cntx_ptr = ftl_mngt_get_process_ctx(mngt);
|
|
|
|
/* check if it is possible to retrieve values located
|
|
* in process context by previous function */
|
|
CU_ASSERT_EQUAL(process_cntx_ptr[0], PROCESS_CNTX_TEST_VAL_0);
|
|
CU_ASSERT_EQUAL(process_cntx_ptr[1], PROCESS_CNTX_TEST_VAL_1);
|
|
|
|
/* tests for caller context */
|
|
caller_cntx_ptr = ftl_mngt_get_caller_ctx(mngt);
|
|
|
|
/* check previously located values */
|
|
CU_ASSERT_EQUAL(caller_cntx_ptr[0], 'n');
|
|
CU_ASSERT_EQUAL(caller_cntx_ptr[1], 'i');
|
|
CU_ASSERT_EQUAL(caller_cntx_ptr[2], 'a');
|
|
|
|
/* insert new */
|
|
caller_cntx_ptr[0] = '!';
|
|
caller_cntx_ptr[1] = '!';
|
|
caller_cntx_ptr[2] = '!';
|
|
|
|
status = ftl_mngt_alloc_step_ctx(mngt, sizeof(*step_cntx_ptr));
|
|
SPDK_CU_ASSERT_FATAL(status == 0);
|
|
step_cntx_ptr = ftl_mngt_get_step_ctx(mngt);
|
|
/* now pointer should point to allocated context */
|
|
CU_ASSERT_PTR_NOT_NULL(step_cntx_ptr);
|
|
|
|
/* this value should be retrieved in second run of function
|
|
* (in 'else' part) */
|
|
*step_cntx_ptr = STEP_CNTX_TEST_VAL;
|
|
|
|
ftl_mngt_continue_step(mngt);
|
|
} else {
|
|
/* In second run retrieved pointer is not empty.
|
|
* Moreover it should contain value allocated for this step
|
|
* in previous run of function */
|
|
CU_ASSERT_PTR_NOT_NULL(step_cntx_ptr);
|
|
CU_ASSERT_EQUAL(*step_cntx_ptr, STEP_CNTX_TEST_VAL);
|
|
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
}
|
|
|
|
static struct ftl_mngt_process_desc pdesc_test_3 = {
|
|
.name = "process 3",
|
|
.ctx_size = 2 * sizeof(int),
|
|
.steps = {
|
|
{
|
|
.name = "step 1",
|
|
.action = fn_3_1_action,
|
|
.cleanup = fn_3_1_cleanup
|
|
},
|
|
{
|
|
.name = "step 2",
|
|
.ctx_size = sizeof(int),
|
|
.action = fn_3_2_action,
|
|
.cleanup = fn_3_2_cleanup
|
|
},
|
|
{}
|
|
}
|
|
};
|
|
|
|
static void
|
|
test_get_func_and_step_cntx_alloc(void)
|
|
{
|
|
char cb_cntx[4] = "daj";
|
|
|
|
run_ftl_mngt_with_cb_cntx(ftl_mngt_process_execute, &pdesc_test_3, cb_cntx);
|
|
|
|
/* check if caller callback was invoked */
|
|
check_elem_on_list_and_remove(CALLER_CB_RET_VALUE);
|
|
|
|
/* check if steps changed cb_cntx correctly */
|
|
CU_ASSERT_EQUAL(cb_cntx[0], 'm');
|
|
CU_ASSERT_EQUAL(cb_cntx[1], 'i');
|
|
CU_ASSERT_EQUAL(cb_cntx[2], 'e');
|
|
|
|
run_ftl_mngt_with_cb_cntx(ftl_mngt_process_rollback, &pdesc_test_3, cb_cntx);
|
|
|
|
/* check if caller callback was invoked */
|
|
check_elem_on_list_and_remove(CALLER_CB_RET_VALUE);
|
|
|
|
/* check if steps changed cb_cntx correctly */
|
|
CU_ASSERT_EQUAL(cb_cntx[0], '!');
|
|
CU_ASSERT_EQUAL(cb_cntx[1], '!');
|
|
CU_ASSERT_EQUAL(cb_cntx[2], '!');
|
|
|
|
check_list_empty();
|
|
}
|
|
|
|
|
|
|
|
/*-
|
|
* test 4
|
|
* tests ftl_mngt_fail_step function
|
|
*
|
|
* In that test one of the action functions fails (third one).
|
|
* Because of that expected result (saved on the test result list)
|
|
* are numbers of the next action function up to failing function.
|
|
* After that cleanup functions are invoked in reversed order.
|
|
*/
|
|
|
|
static void
|
|
fn_4_1_action(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(1);
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
|
|
static void
|
|
fn_4_1_cleanup(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(-1);
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
|
|
static void
|
|
fn_4_2_action(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(2);
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
|
|
static void
|
|
fn_4_2_cleanup(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(-2);
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
|
|
static void
|
|
fn_4_3_action(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(3);
|
|
/* this action fails, so cleanup should begin now */
|
|
ftl_mngt_fail_step(mngt);
|
|
}
|
|
|
|
static void
|
|
fn_4_3_cleanup(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(-3);
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
|
|
static void
|
|
fn_4_4_action(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
CU_FAIL("failure cannot start another action");
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
|
|
static struct ftl_mngt_process_desc pdesc_test_4 = {
|
|
.name = "process 4",
|
|
.steps = {
|
|
{
|
|
.name = "step 1",
|
|
.action = fn_4_1_action,
|
|
.cleanup = fn_4_1_cleanup
|
|
},
|
|
{
|
|
.name = "step 2",
|
|
.action = fn_4_2_action,
|
|
.cleanup = fn_4_2_cleanup
|
|
},
|
|
{
|
|
.name = "step 3",
|
|
.action = fn_4_3_action,
|
|
.cleanup = fn_4_3_cleanup
|
|
},
|
|
{
|
|
.name = "step 2",
|
|
.action = fn_4_4_action
|
|
},
|
|
{}
|
|
}
|
|
};
|
|
|
|
static void
|
|
test_fail_step(void)
|
|
{
|
|
run_ftl_mngt(ftl_mngt_process_execute, &pdesc_test_4);
|
|
|
|
/* check proper order of action functions */
|
|
for (int i = 1; i <= 3; i++) {
|
|
check_elem_on_list_and_remove(i);
|
|
}
|
|
|
|
/* 3rd action function fails, so now should be
|
|
* cleanup functions in reverse order */
|
|
for (int i = 3; i > 0; i--) {
|
|
check_elem_on_list_and_remove(-i);
|
|
}
|
|
|
|
/* check if caller callback was invoked */
|
|
check_elem_on_list_and_remove(CALLER_CB_RET_VALUE);
|
|
|
|
check_list_empty();
|
|
}
|
|
|
|
/*-
|
|
* test 5
|
|
* tests ftl_mngt_call_process and ftl_mngt_call_process_rollback functions
|
|
* tests only proper flow without failures
|
|
*/
|
|
|
|
static void
|
|
fn_5_2_1_action(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(21);
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
|
|
static void
|
|
fn_5_2_1_cleanup(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(-21);
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
|
|
static void
|
|
fn_5_2_2_action(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(22);
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
|
|
static void
|
|
fn_5_2_2_cleanup(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(-22);
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
|
|
static struct ftl_mngt_process_desc pdesc_test_5_2 = {
|
|
.name = "process nested inside step 2 from process 5",
|
|
.steps = {
|
|
{
|
|
.name = "step 2_1",
|
|
.action = fn_5_2_1_action,
|
|
.cleanup = fn_5_2_1_cleanup
|
|
},
|
|
{
|
|
.name = "step 2_2",
|
|
.action = fn_5_2_2_action,
|
|
.cleanup = fn_5_2_2_cleanup
|
|
},
|
|
{}
|
|
}
|
|
};
|
|
|
|
static void
|
|
fn_5_3_1_action(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(31);
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
|
|
static void
|
|
fn_5_3_1_cleanup(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(-31);
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
|
|
static void
|
|
fn_5_3_2_action(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(32);
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
|
|
static void
|
|
fn_5_3_2_cleanup(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(-32);
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
|
|
static struct ftl_mngt_process_desc pdesc_test_5_3 = {
|
|
.name = "process nested inside step 2 from process 5",
|
|
.steps = {
|
|
{
|
|
.name = "step 3_1",
|
|
.action = fn_5_3_1_action,
|
|
.cleanup = fn_5_3_1_cleanup
|
|
},
|
|
{
|
|
.name = "step 3_2",
|
|
.action = fn_5_3_2_action,
|
|
.cleanup = fn_5_3_2_cleanup
|
|
},
|
|
{}
|
|
}
|
|
};
|
|
|
|
static void
|
|
fn_5_1_action(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(1);
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
|
|
static void
|
|
fn_5_1_cleanup(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(-1);
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
|
|
static void
|
|
fn_5_2_action(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(2);
|
|
ftl_mngt_call_process(mngt, &pdesc_test_5_2);
|
|
}
|
|
|
|
static void
|
|
fn_5_2_cleanup(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(-2);
|
|
ftl_mngt_call_process_rollback(mngt, &pdesc_test_5_2);
|
|
}
|
|
|
|
static void
|
|
fn_5_3_action(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(3);
|
|
ftl_mngt_call_process_rollback(mngt, &pdesc_test_5_3);
|
|
}
|
|
|
|
static void
|
|
fn_5_3_cleanup(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(-3);
|
|
ftl_mngt_call_process(mngt, &pdesc_test_5_3);
|
|
}
|
|
|
|
static struct ftl_mngt_process_desc pdesc_test_5 = {
|
|
.name = "process 5 main",
|
|
.steps = {
|
|
{
|
|
.name = "step 1",
|
|
.action = fn_5_1_action,
|
|
.cleanup = fn_5_1_cleanup
|
|
},
|
|
{
|
|
.name = "step 2",
|
|
.action = fn_5_2_action,
|
|
.cleanup = fn_5_2_cleanup
|
|
},
|
|
{
|
|
.name = "step 3",
|
|
.action = fn_5_3_action,
|
|
.cleanup = fn_5_3_cleanup
|
|
},
|
|
{}
|
|
}
|
|
};
|
|
|
|
static void
|
|
test_mngt_call_and_call_rollback(void)
|
|
{
|
|
run_ftl_mngt(ftl_mngt_process_execute, &pdesc_test_5);
|
|
|
|
check_elem_on_list_and_remove(1);
|
|
check_elem_on_list_and_remove(2);
|
|
check_elem_on_list_and_remove(21);
|
|
check_elem_on_list_and_remove(22);
|
|
check_elem_on_list_and_remove(3);
|
|
check_elem_on_list_and_remove(-32);
|
|
check_elem_on_list_and_remove(-31);
|
|
|
|
/* check if caller callback was invoked */
|
|
check_elem_on_list_and_remove(CALLER_CB_RET_VALUE);
|
|
|
|
run_ftl_mngt(ftl_mngt_process_rollback, &pdesc_test_5);
|
|
|
|
check_elem_on_list_and_remove(-3);
|
|
check_elem_on_list_and_remove(31);
|
|
check_elem_on_list_and_remove(32);
|
|
check_elem_on_list_and_remove(-2);
|
|
check_elem_on_list_and_remove(-22);
|
|
check_elem_on_list_and_remove(-21);
|
|
check_elem_on_list_and_remove(-1);
|
|
|
|
/* check if caller callback was invoked */
|
|
check_elem_on_list_and_remove(CALLER_CB_RET_VALUE);
|
|
|
|
check_list_empty();
|
|
}
|
|
|
|
/*
|
|
* test 6
|
|
* tests failure inside nested process
|
|
*/
|
|
|
|
static void
|
|
fn_6_2_1_action(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(21);
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
|
|
static void
|
|
fn_6_2_1_cleanup(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(-21);
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
|
|
static void
|
|
fn_6_2_2_action(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(22);
|
|
/* this action fails, so cleanup should begin now */
|
|
ftl_mngt_fail_step(mngt);
|
|
}
|
|
|
|
static void
|
|
fn_6_2_3_action(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
CU_FAIL("failure cannot start another action");
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
|
|
static struct ftl_mngt_process_desc pdesc_test_6_2 = {
|
|
.name = "process nested inside step 2 from process 6",
|
|
.steps = {
|
|
{
|
|
.name = "step 6_1",
|
|
.action = fn_6_2_1_action,
|
|
.cleanup = fn_6_2_1_cleanup
|
|
},
|
|
{
|
|
.name = "step 6_2",
|
|
.action = fn_6_2_2_action
|
|
},
|
|
{
|
|
.name = "step 6_3",
|
|
.action = fn_6_2_3_action
|
|
},
|
|
{}
|
|
}
|
|
};
|
|
|
|
static void
|
|
fn_6_1_action(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(1);
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
|
|
static void
|
|
fn_6_2_action(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(2);
|
|
ftl_mngt_call_process(mngt, &pdesc_test_6_2);
|
|
}
|
|
|
|
static void
|
|
fn_6_2_cleanup(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
add_elem_to_test_list(-2);
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
|
|
static void
|
|
fn_6_3_action(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
|
{
|
|
CU_FAIL("failure cannot start another action");
|
|
ftl_mngt_next_step(mngt);
|
|
}
|
|
|
|
static struct ftl_mngt_process_desc pdesc_test_6 = {
|
|
.name = "process 6 main",
|
|
.steps = {
|
|
{
|
|
.name = "step 1",
|
|
.action = fn_6_1_action
|
|
},
|
|
{
|
|
.name = "step 2",
|
|
.action = fn_6_2_action,
|
|
.cleanup = fn_6_2_cleanup
|
|
},
|
|
{
|
|
.name = "step 3",
|
|
.action = fn_6_3_action
|
|
},
|
|
{}
|
|
}
|
|
};
|
|
|
|
static void
|
|
test_nested_process_failure(void)
|
|
{
|
|
run_ftl_mngt(ftl_mngt_process_execute, &pdesc_test_6);
|
|
|
|
check_elem_on_list_and_remove(1);
|
|
check_elem_on_list_and_remove(2);
|
|
check_elem_on_list_and_remove(21);
|
|
check_elem_on_list_and_remove(22);
|
|
check_elem_on_list_and_remove(-21);
|
|
check_elem_on_list_and_remove(-2);
|
|
|
|
/* check if caller callback was invoked */
|
|
check_elem_on_list_and_remove(CALLER_CB_RET_VALUE);
|
|
|
|
check_list_empty();
|
|
}
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
CU_pSuite suite = NULL;
|
|
unsigned int num_failures;
|
|
|
|
CU_set_error_action(CUEA_ABORT);
|
|
CU_initialize_registry();
|
|
|
|
suite = CU_add_suite("ftl_mngt", setup_test_list, NULL);
|
|
|
|
CU_ADD_TEST(suite, test_next_step);
|
|
CU_ADD_TEST(suite, test_continue_step);
|
|
CU_ADD_TEST(suite, test_get_func_and_step_cntx_alloc);
|
|
CU_ADD_TEST(suite, test_fail_step);
|
|
CU_ADD_TEST(suite, test_mngt_call_and_call_rollback);
|
|
CU_ADD_TEST(suite, test_nested_process_failure);
|
|
|
|
CU_basic_set_mode(CU_BRM_VERBOSE);
|
|
CU_basic_run_tests();
|
|
num_failures = CU_get_number_of_failures();
|
|
CU_cleanup_registry();
|
|
|
|
return num_failures;
|
|
}
|