Skip to content

Commit

Permalink
Merge branch 'test-update'
Browse files Browse the repository at this point in the history
Add new unit tests for various command-level functions.  These are just
to check as many code as possible with sanitizers to verify there no
obvious bugs nor resource leaks.  So output is redirected to /dev/null.

  $ make ASAN=1 unittest TESTARG=command
    TEST     test_unit
  Running 8 test cases
  ======================
  [001] dump_command1                 : PASS
  [002] dump_command2                 : PASS
  [003] graph_command                 : PASS
  [004] info_command                  : PASS
  [005] replay_command                : PASS
  [006] report_command1               : PASS
  [007] report_command2               : PASS
  [008] tui_command                   : PASS

  unit test stats
  ====================
    8 ran successfully
    0 failed
    0 skipped
    0 signal caught
    0 unknown result

Signed-off-by: Namhyung Kim <namhyung@gmail.com>
  • Loading branch information
namhyung committed Oct 22, 2023
2 parents ce3aeba + b1f8ae0 commit ef81b79
Show file tree
Hide file tree
Showing 8 changed files with 444 additions and 7 deletions.
65 changes: 65 additions & 0 deletions cmds/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -1810,3 +1810,68 @@ int command_dump(int argc, char *argv[], struct uftrace_opts *opts)

return ret;
}

#ifdef UNIT_TEST
TEST_CASE(dump_command1)
{
struct uftrace_opts opts = {
.dirname = "dump-file-test",
.exename = read_exename(),
.max_stack = 10,
.depth = OPT_DEPTH_DEFAULT,
};
struct uftrace_data handle;
struct uftrace_raw_dump dump = {
.ops = {
.header = dump_raw_header,
.task_start = dump_raw_task_start,
.inverted_time = dump_raw_inverted_time,
.task_rstack = dump_raw_task_rstack,
.task_event = dump_raw_task_event,
.kernel_start = dump_raw_kernel_start,
.cpu_start = dump_raw_cpu_start,
.kernel_func = dump_raw_kernel_rstack,
.kernel_event = dump_raw_kernel_event,
.lost = dump_raw_kernel_lost,
.perf_start = dump_raw_perf_start,
.perf_event = dump_raw_perf_event,
},
};

TEST_EQ(prepare_test_data(&opts, &handle), 0);

pr_dbg("dump each file contents\n");
do_dump_file(&dump.ops, &opts, &handle);

release_test_data(&opts, &handle);
return TEST_OK;
}

TEST_CASE(dump_command2)
{
struct uftrace_opts opts = {
.dirname = "dump-replay-test",
.exename = read_exename(),
.max_stack = 10,
.depth = OPT_DEPTH_DEFAULT,
};
struct uftrace_data handle;
struct uftrace_raw_dump dump = {
.ops = {
.header = dump_chrome_header,
.task_rstack = dump_chrome_task_rstack,
.kernel_func = dump_chrome_kernel_rstack,
.perf_event = dump_chrome_perf_event,
.footer = dump_chrome_footer,
},
};

TEST_EQ(prepare_test_data(&opts, &handle), 0);

pr_dbg("dump contents in time order\n");
do_dump_replay(&dump.ops, &opts, &handle);

release_test_data(&opts, &handle);
return TEST_OK;
}
#endif /* UNIT_TEST */
51 changes: 51 additions & 0 deletions cmds/graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -1030,3 +1030,54 @@ int command_graph(int argc, char *argv[], struct uftrace_opts *opts)

return 0;
}

#ifdef UNIT_TEST
TEST_CASE(graph_command)
{
struct uftrace_opts opts = {
.dirname = "graph-cmd-test",
.exename = read_exename(),
.max_stack = 10,
.depth = OPT_DEPTH_DEFAULT,
};
struct uftrace_data handle;
struct session_graph *graph;
struct graph_backtrace *bt, *btmp;
char *func;
int ret = 0;

func = "_start";
full_graph = true;

TEST_EQ(prepare_test_data(&opts, &handle), 0);

pr_dbg("construct full function graph\n");
build_graph(&opts, &handle, func);

graph = graph_list;
while (graph && !uftrace_done) {
pr_dbg("print graph for %s\n", graph->func);
ret += print_graph(graph, &opts);
graph = graph->next;
}
TEST_NE(ret, 0);

while (graph_list) {
graph = graph_list;
graph_list = graph->next;

pr_dbg("destroy graph for %s\n", graph->func);
free(graph->func);
list_for_each_entry_safe(bt, btmp, &graph->bt_list, list) {
list_del(&bt->list);
free(bt);
}
graph_destroy(&graph->ug);
free(graph);
}
graph_remove_task();

release_test_data(&opts, &handle);
return TEST_OK;
}
#endif /* UNIT_TEST */
29 changes: 29 additions & 0 deletions cmds/info.c
Original file line number Diff line number Diff line change
Expand Up @@ -1269,3 +1269,32 @@ int command_info(int argc, char *argv[], struct uftrace_opts *opts)

return 0;
}

#ifdef UNIT_TEST
TEST_CASE(info_command)
{
struct uftrace_opts opts = {
.dirname = "info-cmd-test",
.exename = read_exename(),
.max_stack = 10,
.depth = OPT_DEPTH_DEFAULT,
};
struct uftrace_data handle;

TEST_EQ(prepare_test_data(&opts, &handle), 0);

pr_dbg("process info section in the data\n");
process_uftrace_info(&handle, &opts, print_info, NULL);

if (handle.hdr.feat_mask & PERF_EVENT) {
if (setup_perf_data(&handle) == 0)
update_perf_task_comm(&handle);
}

pr_dbg("print task info in the data\n");
print_task_info(&handle);

release_test_data(&opts, &handle);
return TEST_OK;
}
#endif /* UNIT_TEST */
74 changes: 74 additions & 0 deletions cmds/replay.c
Original file line number Diff line number Diff line change
Expand Up @@ -1180,3 +1180,77 @@ int command_replay(int argc, char *argv[], struct uftrace_opts *opts)

return ret;
}

#ifdef UNIT_TEST
static const char *record_type_str(struct uftrace_record *rec)
{
switch (rec->type) {
case UFTRACE_ENTRY:
return "ENTRY";
case UFTRACE_EXIT:
return "EXIT";
case UFTRACE_LOST:
return "LOST";
case UFTRACE_EVENT:
return "EVENT";
default:
break;
}
return "UNKNOWN";
}

TEST_CASE(replay_command)
{
struct uftrace_opts opts = {
.dirname = "replay-graph-test",
.exename = read_exename(),
.max_stack = 10,
.depth = OPT_DEPTH_DEFAULT,
};
struct uftrace_data handle;
struct uftrace_task_reader *task;
uint64_t prev_time = 0;

TEST_EQ(prepare_test_data(&opts, &handle), 0);

setup_field(&output_fields, &opts, &setup_default_field, field_table,
ARRAY_SIZE(field_table));
if (peek_rstack(&handle, &task) == 0)
print_header(&output_fields, "#", "FUNCTION", 1, false);
if (!list_empty(&output_fields))
pr_out("\n");

pr_dbg("replay test data in graph format\n");
while (read_rstack(&handle, &task) == 0) {
struct uftrace_record *rstack = task->rstack;
uint64_t curr_time = rstack->time;

if (!fstack_check_opts(task, &opts)) {
pr_dbg("task=%d time=%lu skip\n", task->tid, rstack->time);
continue;
}

pr_dbg("task=%d time=%lu depth=%d type=%s\n", task->tid, rstack->time,
rstack->depth, record_type_str(rstack));

/*
* data sanity check: timestamp should be ordered.
* But print_graph_rstack() may change task->rstack
* during fstack_skip(). So check the timestamp here.
*/
if (curr_time) {
if (prev_time > curr_time)
print_warning(task);
prev_time = rstack->time;
}

/* this will merge adjacent ENTRY and EXIT */
TEST_EQ(print_graph_rstack(&handle, task, &opts), 0);
}

print_remaining_stack(&opts, &handle);

release_test_data(&opts, &handle);
return TEST_OK;
}
#endif /* UNIT_TEST */
51 changes: 51 additions & 0 deletions cmds/report.c
Original file line number Diff line number Diff line change
Expand Up @@ -554,3 +554,54 @@ int command_report(int argc, char *argv[], struct uftrace_opts *opts)

return 0;
}
#ifdef UNIT_TEST
TEST_CASE(report_command1)
{
struct uftrace_opts opts = {
.dirname = "report-func-test",
.exename = read_exename(),
.max_stack = 10,
.depth = OPT_DEPTH_DEFAULT,
};
struct uftrace_data handle;
char *sort_keys;

TEST_EQ(prepare_test_data(&opts, &handle), 0);

pr_dbg("report setup sort key\n");
sort_keys = convert_sort_keys(opts.sort_keys, AVG_TOTAL);
TEST_EQ(report_setup_sort(sort_keys), 1);

pr_dbg("report functions\n");
report_functions(&handle, &opts);

release_test_data(&opts, &handle);
free(sort_keys);
return TEST_OK;
}

TEST_CASE(report_command2)
{
struct uftrace_opts opts = {
.dirname = "report-task-test",
.exename = read_exename(),
.max_stack = 10,
.depth = OPT_DEPTH_DEFAULT,
};
struct uftrace_data handle;
char *sort_keys;

TEST_EQ(prepare_test_data(&opts, &handle), 0);

pr_dbg("report setup sort key\n");
sort_keys = convert_sort_keys("self", AVG_SELF);
TEST_EQ(report_setup_sort(sort_keys), 1);

pr_dbg("report task\n");
report_task(&handle, &opts);

release_test_data(&opts, &handle);
free(sort_keys);
return TEST_OK;
}
#endif /* UNIT_TEST */
35 changes: 35 additions & 0 deletions cmds/tui.c
Original file line number Diff line number Diff line change
Expand Up @@ -3068,6 +3068,41 @@ int command_tui(int argc, char *argv[], struct uftrace_opts *opts)
return 0;
}

#ifdef UNIT_TEST
TEST_CASE(tui_command)
{
struct uftrace_opts opts = {
.dirname = "tui-cmd-test",
.exename = read_exename(),
.max_stack = 10,
.depth = OPT_DEPTH_DEFAULT,
};
struct uftrace_data handle;
struct uftrace_task_reader *task;

TEST_EQ(prepare_test_data(&opts, &handle), 0);

pr_dbg("construct data structure for TUI\n");
tui_setup(&handle, &opts);

while (read_rstack(&handle, &task) == 0) {
struct uftrace_record *rec = task->rstack;

TEST_NE(fstack_check_opts(task, &opts), 0);
TEST_NE(fstack_check_filter(task), 0);
TEST_EQ(build_tui_node(task, rec, &opts), 0);

fstack_check_filter_done(task);
}
add_remaining_node(&opts, &handle);

tui_cleanup();

release_test_data(&opts, &handle);
return TEST_OK;
}
#endif /* UNIT_TEST */

#else /* !HAVE_LIBNCURSES */

#include "uftrace.h"
Expand Down
4 changes: 4 additions & 0 deletions uftrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -647,4 +647,8 @@ struct uftrace_event {
"</body>\n" \
"</html>\n"

/* for unit tests */
int prepare_test_data(struct uftrace_opts *opts, struct uftrace_data *handle);
int release_test_data(struct uftrace_opts *opts, struct uftrace_data *handle);

#endif /* UFTRACE_H */
Loading

0 comments on commit ef81b79

Please sign in to comment.