gapk/tests/procqueue/pq_test.c

374 lines
8.9 KiB
C

/*
* This file is part of GAPK (GSM Audio Pocket Knife).
*
* (C) 2017 by Vadim Yanitskiy <axilirator@gmail.com>
*
* GAPK is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GAPK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GAPK. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <talloc.h>
#include <assert.h>
#include <osmocom/gapk/procqueue.h>
#include <osmocom/gapk/common.h>
/**
* This test is intended to validate the processing queue
* management API. Moreover, the talloc debugging API is
* used to ensure that there are no memory leaks.
*
* First, four processing queues are being allocated. One
* of them is empty, while others have different count of
* items. Then the human-readable description is being
* generated for all of them. And finally, the processing
* and exit callback are being tested.
*
* During the test execution, the talloc NULL-context
* tracking feature is enabled, allowing to observe every
* memory allocation within the libosmogapk, and to detect
* memory leaks.
*/
static void talloc_ctx_walk_cb(const void *chunk, int depth,
int max_depth, int is_ref, void *data)
{
const char *chunk_name = talloc_get_name(chunk);
int spaces_cnt;
/* Hierarchical spacing */
for (spaces_cnt = 0; spaces_cnt < depth; spaces_cnt++)
printf(" ");
/* Chunk info */
printf("chunk %s: depth=%d\n", chunk_name, depth);
}
static int q3_i0_proc(void *state, uint8_t *out, const uint8_t *in,
unsigned int in_len)
{
int i;
printf("Incoming data: ");
for (i = 0; i < 10; i++) {
printf("%d ", i);
out[i] = i;
}
printf("\n");
return 0;
}
static int q3_i1_proc(void *state, uint8_t *out, const uint8_t *in,
unsigned int in_len)
{
int i;
for (i = 0; i < 10; i++)
out[i] = in[i] % 2;
return 0;
}
static int q3_i2_proc(void *state, uint8_t *out, const uint8_t *in,
unsigned int in_len)
{
int i;
printf("Outgoing data: ");
for (i = 0; i < 10; i++)
printf("%d ", in[i]);
printf("\n");
return 0;
}
static void q3_exit(void *state)
{
struct osmo_gapk_pq_item *item;
/* Make sure the item's state is passed correctly */
assert(state != NULL);
item = (struct osmo_gapk_pq_item *) state;
printf("Calling exit callback for '%s/%s'\n",
item->cat_name, item->sub_name);
}
int main(int argc, char **argv)
{
/* Enable tracking the use of NULL memory contexts */
talloc_enable_null_tracking();
/**
* 1. Processing queue allocation test
*/
struct osmo_gapk_pq *q0, *q1, *q2, *q3;
printf("Processing queue allocation test:\n");
/* Allocate four queues */
q0 = osmo_gapk_pq_create(NULL);
q1 = osmo_gapk_pq_create("q1");
q2 = osmo_gapk_pq_create("q2");
q3 = osmo_gapk_pq_create("q3");
/* Make sure all queues are allocated */
assert(q0 != NULL);
assert(q1 != NULL);
assert(q2 != NULL);
assert(q3 != NULL);
/* Print talloc memory hierarchy */
talloc_report_depth_cb(NULL, 0, 10, &talloc_ctx_walk_cb, NULL);
printf("\n");
/**
* 2. Item allocation test
*/
struct osmo_gapk_pq_item *q3_i0, *q3_i1, *q3_i2;
struct osmo_gapk_pq_item *q2_i0, *q2_i1;
struct osmo_gapk_pq_item *q1_i0;
printf("Item allocation test:\n");
/* Make sure there are no items */
assert(q0->n_items == 0);
assert(q1->n_items == 0);
assert(q2->n_items == 0);
assert(q3->n_items == 0);
/* Allocate items */
q3_i0 = osmo_gapk_pq_add_item(q3);
q3_i1 = osmo_gapk_pq_add_item(q3);
q3_i2 = osmo_gapk_pq_add_item(q3);
q2_i0 = osmo_gapk_pq_add_item(q2);
q2_i1 = osmo_gapk_pq_add_item(q2);
q1_i0 = osmo_gapk_pq_add_item(q1);
/* Make sure all items are allocated */
assert(q3_i0 != NULL);
assert(q3_i1 != NULL);
assert(q3_i2 != NULL);
assert(q2_i0 != NULL);
assert(q2_i1 != NULL);
assert(q1_i0 != NULL);
/* Check item count */
assert(q0->n_items == 0);
assert(q1->n_items == 1);
assert(q2->n_items == 2);
assert(q3->n_items == 3);
/* Print talloc memory hierarchy */
talloc_report_depth_cb(NULL, 0, 10, &talloc_ctx_walk_cb, NULL);
printf("\n");
/**
* 3. Items persistence test
*/
struct osmo_gapk_pq_item *item;
/* Make sure that q0 is empty, others are not */
assert(llist_empty(&q0->items) == 1);
assert(llist_empty(&q1->items) == 0);
assert(llist_empty(&q2->items) == 0);
assert(llist_empty(&q3->items) == 0);
/* A single item must be the first and the last in a queue */
item = llist_first_entry(&q1->items, struct osmo_gapk_pq_item, list);
assert(item == q1_i0);
item = llist_last_entry(&q1->items, struct osmo_gapk_pq_item, list);
assert(item == q1_i0);
/* Two items: one is the first, second is the last */
item = llist_first_entry(&q2->items, struct osmo_gapk_pq_item, list);
assert(item == q2_i0);
item = llist_last_entry(&q2->items, struct osmo_gapk_pq_item, list);
assert(item == q2_i1);
/* Three items: one is the first, third is the last */
item = llist_first_entry(&q3->items, struct osmo_gapk_pq_item, list);
assert(item == q3_i0);
assert(item != q3_i1);
item = llist_last_entry(&q3->items, struct osmo_gapk_pq_item, list);
assert(item == q3_i2);
assert(item != q3_i1);
/**
* 4. Queue I/O data lengths check
*/
q3_i0->len_in = 10;
q3_i0->len_out = 20;
q3_i1->len_in = 20;
q3_i1->len_out = 30;
q3_i2->len_in = 30;
q3_i2->len_out = 10;
/* Normal case */
assert(osmo_gapk_pq_check(q3, 0) == 0);
/* Abnormal case (I/O length mismatch) */
q3_i0->len_out = 10;
assert(osmo_gapk_pq_check(q3, 0) != 0);
q3_i0->len_out = 20;
/* Check queue in strict mode (requires src -> ... -> sink) */
q3_i0->type = OSMO_GAPK_ITEM_TYPE_SOURCE;
q3_i1->type = OSMO_GAPK_ITEM_TYPE_PROC;
q3_i2->type = OSMO_GAPK_ITEM_TYPE_SINK;
/* Normal case (src -> proc -> sink) */
assert(osmo_gapk_pq_check(q3, 1) == 0);
/* Abnormal case (proc -> proc -> sink) */
q3_i0->type = OSMO_GAPK_ITEM_TYPE_PROC;
assert(osmo_gapk_pq_check(q3, 1) != 0);
q3_i0->type = OSMO_GAPK_ITEM_TYPE_SOURCE;
/**
* 5. Buffer allocation test
*/
printf("Queue preparation test:\n");
/* Prepare the queue */
assert(osmo_gapk_pq_prepare(q3) == 0);
/* Make sure buffers were allocated */
assert(q3_i0->buf != NULL);
assert(q3_i1->buf != NULL);
/* Currently, we don't allocate buffers for sinks */
assert(q3_i2->buf == NULL);
/* Compare required vs allocated buffer sizes */
assert(talloc_total_size(q3_i0->buf) == q3_i0->len_out);
assert(talloc_total_size(q3_i1->buf) == q3_i1->len_out);
/* Print talloc memory hierarchy */
talloc_report_depth_cb(NULL, 0, 10, &talloc_ctx_walk_cb, NULL);
printf("\n");
/**
* 6. Queue description test
*/
char *queue_desc;
printf("Queue description test:\n");
/* An empty queue doesn't have description */
queue_desc = osmo_gapk_pq_describe(q0);
assert(queue_desc == NULL);
/* Fill in some data */
q3_i0->cat_name = OSMO_GAPK_CAT_NAME_SOURCE;
q3_i0->sub_name = "file";
q3_i1->cat_name = OSMO_GAPK_CAT_NAME_PROC;
q3_i1->sub_name = "dummy";
q3_i2->cat_name = OSMO_GAPK_CAT_NAME_SINK;
q3_i2->sub_name = "alsa";
q2_i0->cat_name = OSMO_GAPK_CAT_NAME_SOURCE;
q2_i0->sub_name = "dummy";
q2_i1->cat_name = OSMO_GAPK_CAT_NAME_SINK;
q2_i1->sub_name = "dummy";
q1_i0->cat_name = "dummy";
q1_i0->sub_name = "dummy";
queue_desc = osmo_gapk_pq_describe(q3);
assert(queue_desc != NULL);
printf("Queue q3 description: %s\n", queue_desc);
talloc_free(queue_desc);
queue_desc = osmo_gapk_pq_describe(q2);
assert(queue_desc != NULL);
printf("Queue q2 description: %s\n", queue_desc);
talloc_free(queue_desc);
queue_desc = osmo_gapk_pq_describe(q1);
assert(queue_desc != NULL);
printf("Queue q1 description: %s\n\n", queue_desc);
talloc_free(queue_desc);
/**
* 7. Queue execution test
*/
printf("Processing queue execution test:\n");
/* Make sure there are no callbacks by default */
assert(q3_i0->proc == NULL);
assert(q3_i0->wait == NULL);
assert(q3_i0->exit == NULL);
assert(q3_i1->proc == NULL);
assert(q3_i1->wait == NULL);
assert(q3_i1->exit == NULL);
assert(q3_i2->proc == NULL);
assert(q3_i2->wait == NULL);
assert(q3_i2->exit == NULL);
q3_i0->proc = &q3_i0_proc;
q3_i1->proc = &q3_i1_proc;
q3_i2->proc = &q3_i2_proc;
assert(osmo_gapk_pq_execute(q3) == 0);
printf("\n");
/**
* 8. Exit callback & deallocation tests
*/
printf("Processing queue exit callback test:\n");
q3_i0->state = q3_i0;
q3_i1->state = q3_i1;
q3_i2->state = q3_i2;
q3_i0->exit = &q3_exit;
q3_i1->exit = &q3_exit;
q3_i2->exit = &q3_exit;
osmo_gapk_pq_destroy(q0);
osmo_gapk_pq_destroy(q1);
osmo_gapk_pq_destroy(q2);
osmo_gapk_pq_destroy(q3);
printf("\n");
/**
* 9. Memory leak detection test
*/
printf("Processing queue deallocation test:\n");
talloc_report_depth_cb(NULL, 0, 10, &talloc_ctx_walk_cb, NULL);
return 0;
}