/* Cesar project {{{ * * Copyright (C) 2007 Spidcom * * <<>> * * }}} */ /** * \file src/test_mfs.c * \brief Test MFS related functions. * \ingroup test */ #include "common/std.h" #include "lib/test.h" #include "lib/rnd.h" #include "lib/blk.h" #include "mac/common/mfs.h" #include "mac/pbproc/pbproc.h" #define NB_ITER 1000 struct test_pbproc_t { uint next_it; int to_take; pb_t *tx_head, *tx_tail; pb_t *free_head, *free_tail; uint tx_seg_nb; lib_rnd_t rnd[1]; }; typedef struct test_pbproc_t test_pbproc_t; struct test_param_t { uint next_it; uint to_take_max; u32 free_r; uint sar_add_min; uint sar_add_max; }; typedef struct test_param_t test_param_t; void test_pbproc_init (test_pbproc_t *ctx) { ctx->next_it = 1; ctx->to_take = 0; ctx->tx_head = ctx->tx_tail = NULL; ctx->free_head = ctx->free_tail = NULL; ctx->tx_seg_nb = 0; lib_rnd_init (ctx->rnd, 4321); } void test_pbproc_check (test_t t, test_pbproc_t *ctx, mfs_tx_t *mfs) { test_within (t); uint ssn = 0; pb_t *p; p = ctx->free_head; test_fail_unless (p); while (1) { if (!mfs->beacon) test_fail_unless (p->header.ssn == ssn++); else { pbproc_tx_beacon_params_t *params = (void *) (p->data + MAC_PB136_BYTES); test_fail_unless (params->bto[0] >= ssn && params->bto[1] == params->bto[0] + 1 && params->bto[2] == params->bto[0] + 2 && params->bto[3] == params->bto[0] + 3 && params->bpsto == NULL); ssn = params->bto[0]; } if (p == ctx->free_tail) break; p = p->next; } test_fail_unless (mfs->pending_seg_nb == 0); if (!mfs->beacon) test_fail_unless (ssn + ctx->tx_seg_nb + ctx->to_take + mfs->seg_nb == mfs->next_ssn); test_verbose_print ("freed: %d, total: %d", ssn, mfs->next_ssn); } void test_pbproc_uninit (test_pbproc_t *ctx) { blk_release_desc_range (&ctx->tx_head->blk, &ctx->tx_tail->blk); blk_release_desc_range (&ctx->free_head->blk, &ctx->free_tail->blk); } void test_pbproc_free (test_pbproc_t *ctx) { if (!ctx->free_head) ctx->free_head = ctx->tx_head; else ctx->free_tail->next = ctx->tx_head; ctx->free_tail = ctx->tx_tail; ctx->tx_head = ctx->tx_tail = NULL; ctx->tx_seg_nb = 0; } void test_pbproc_put_back (test_pbproc_t *ctx, mfs_tx_t *mfs) { ctx->tx_tail->next = mfs->head; if (!mfs->head) mfs->tail = ctx->tx_tail; mfs->head = ctx->tx_head; ctx->tx_head = ctx->tx_tail = NULL; mfs->seg_nb += ctx->tx_seg_nb; ctx->tx_seg_nb = 0; } void test_pbproc_take (test_pbproc_t *ctx, mfs_tx_t *mfs, uint tt) { uint i; for (i = 0; i < tt; i++) { if (!ctx->tx_head) ctx->tx_head = mfs->head; else ctx->tx_tail->next = mfs->head; ctx->tx_tail = mfs->head; if (mfs->head == mfs->tail) { mfs->head = NULL; dbg_invalid_ptr (mfs->tail); } else mfs->head = mfs->head->next; dbg_invalid_ptr (ctx->tx_tail->next); /* simulate next clobber. */ ctx->to_take--; ctx->tx_seg_nb++; } } void test_pbproc_it (test_t t, test_pbproc_t *ctx, mfs_tx_t *mfs, test_param_t *param) { test_within (t); if (!ctx->next_it--) { if (!ctx->to_take && ctx->tx_seg_nb) { if (lib_rnd_flip_coin (ctx->rnd, param->free_r)) test_pbproc_free (ctx); else test_pbproc_put_back (ctx, mfs); } else { if (!ctx->to_take) { /* New transmission. */ ctx->to_take = lib_rnd_uniform (ctx->rnd, param->to_take_max) + 1; if (mfs->seg_nb == -1) ctx->to_take = 0; else if (ctx->to_take > mfs->seg_nb) ctx->to_take = mfs->seg_nb; test_verbose_print ("to take: %d", ctx->to_take); mfs->seg_nb -= ctx->to_take; } if (ctx->to_take) test_pbproc_take (ctx, mfs, lib_rnd_uniform ( ctx->rnd, ctx->to_take) + 1); } ctx->next_it = lib_rnd_uniform (ctx->rnd, param->next_it); } } void mfs_basic_test_case (test_t t) { uint i; lib_rnd_t rnd[1]; test_case_begin (t, "basic"); lib_rnd_init (rnd, 1234); /* Test. */ #define IT() test_pbproc_it (t, &test_pbproc, mfs, ¶m) test_begin (t, "synchronous") { test_param_t param; param.next_it = 5; param.to_take_max = 200; param.free_r = LIB_RND_RATIO (0.7); param.sar_add_min = 1; param.sar_add_max = 30; test_pbproc_t test_pbproc; test_pbproc_init (&test_pbproc); mfs_tx_t *mfs = blk_alloc (); mfs_tx_init (mfs, false, false, 0, 1); mfs->dynamic_cap = true; for (i = 0; i < NB_ITER; i++) { uint add = lib_rnd_uniform (rnd, param.sar_add_max - param.sar_add_min + 1) + param.sar_add_min; test_verbose_print ("add: %d", add); pb_t *tail = pbproc_mfs_extract_tail (mfs); IT (); uint insert = tail ? add - 1 : add; test_verbose_print ("insert: %d", insert); if (insert) { pb_t *sar_head, *sar_tail, *p; sar_head = (pb_t *) blk_alloc_desc_range (insert, (blk_t **) &sar_tail); p = sar_head; do { pb_header_t h; h.ssn = mfs->next_ssn++; h.mfbo = 0; h.vpbf = true; h.mmqf = false; h.mfbf = false; h.opsf = false; h.rsvd = 0; p->header = h; if (p == sar_tail) break; p = p->next; } while (1); pbproc_mfs_insert (mfs, sar_head, sar_tail, insert, 0); IT (); } pbproc_mfs_provide (mfs, add); IT (); } test_pbproc_check (t, &test_pbproc, mfs); if (mfs->head) blk_release_desc_range (&mfs->head->blk, &mfs->tail->blk); blk_release (mfs); test_pbproc_uninit (&test_pbproc); } test_end; test_begin (t, "beacon") { test_param_t param; param.next_it = 2; param.to_take_max = 1; param.free_r = 0xffffffff; test_pbproc_t test_pbproc; test_pbproc_init (&test_pbproc); mfs_tx_t *mfs = blk_alloc (); mfs_tx_init (mfs, false, false, 0, 1); mfs->beacon = true; for (i = 0; i < NB_ITER; i++) { test_verbose_print ("prepare"); pb_beacon_t *beacon = (pb_beacon_t *) blk_alloc_desc (); pbproc_tx_beacon_params_t params = { { mfs->next_ssn, mfs->next_ssn + 1, mfs->next_ssn + 2, mfs->next_ssn + 3 }, NULL }; beacon->first_data_word = 42; mfs->next_ssn++; pbproc_mfs_beacon_prepare (INVALID_PTR, mfs, beacon, ¶ms); IT (); } test_pbproc_check (t, &test_pbproc, mfs); if (mfs->head) blk_release_desc_range (&mfs->head->blk, &mfs->tail->blk); blk_release (mfs); test_pbproc_uninit (&test_pbproc); } test_end; } void mfs_test_suite (test_t t) { test_suite_begin (t, "mfs"); mfs_basic_test_case (t); } int main (int argc, char **argv) { test_t t; test_init (t, argc, argv); mfs_test_suite (t); test_result (t); return test_nb_failed (t) == 0 ? 0 : 1; }