pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/libosmo-netif/+/29513 )
Change subject: tests/osmux: Add new osmux_input_test to validate AMR FT changes ......................................................................
tests/osmux: Add new osmux_input_test to validate AMR FT changes
Related: SYS#5987 Change-Id: I105466fc8a4d92341f34886ee81ef0ca04014514 --- M tests/Makefile.am A tests/osmux/osmux_input_test.c A tests/osmux/osmux_input_test.ok M tests/testsuite.at 4 files changed, 305 insertions(+), 1 deletion(-)
git pull ssh://gerrit.osmocom.org:29418/libosmo-netif refs/changes/13/29513/1
diff --git a/tests/Makefile.am b/tests/Makefile.am index ab2bf59..cb31baa 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,7 +1,14 @@ AM_CFLAGS = -Wall -I$(top_srcdir)/include $(LIBOSMOCORE_CFLAGS) -g AM_LDFLAGS = $(LIBOSMOCORE_LDFLAGS) -no-install
-check_PROGRAMS = osmux/osmux_test osmux/osmux_output_test stream/stream_test jibuf/jibuf_test amr/amr_test +check_PROGRAMS = \ + osmux/osmux_test \ + osmux/osmux_output_test \ + osmux/osmux_input_test \ + stream/stream_test \ + jibuf/jibuf_test \ + amr/amr_test \ + $(NULL) check_HEADERS =
osmux_osmux_test_SOURCES = osmux/osmux_test.c @@ -10,6 +17,9 @@ osmux_osmux_output_test_SOURCES = osmux/osmux_output_test.c osmux_osmux_output_test_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(top_builddir)/src/libosmonetif.la
+osmux_osmux_input_test_SOURCES = osmux/osmux_input_test.c +osmux_osmux_input_test_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(top_builddir)/src/libosmonetif.la + stream_stream_test_SOURCES = stream/stream_test.c stream_stream_test_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(top_builddir)/src/libosmonetif.la
diff --git a/tests/osmux/osmux_input_test.c b/tests/osmux/osmux_input_test.c new file mode 100644 index 0000000..dcec949 --- /dev/null +++ b/tests/osmux/osmux_input_test.c @@ -0,0 +1,275 @@ +/* (C) 2022 by sysmocom - s.f.m.c. GmbH info@sysmocom.de + * + * Author: Pau Espin Pedrol pespin@sysmocom.de + * + * SPDX-License-Identifier: GPL-2.0+ + * + * This program 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 2 of the License, or + * (at your option) any later version. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <unistd.h> +#include <stdint.h> +#include <inttypes.h> +#include <string.h> +#include <signal.h> +#include <arpa/inet.h> +#include <sys/time.h> +#include <getopt.h> + +#include <osmocom/core/select.h> +#include <osmocom/core/application.h> +#include <osmocom/core/logging.h> +#include <osmocom/core/msgb.h> +#include <osmocom/netif/rtp.h> +#include <osmocom/netif/osmux.h> +#include <osmocom/netif/amr.h> + +static uint16_t rtp_next_seq; +static uint16_t rtp_next_ts; + +#define TIME_RTP_PKT_MS 20 +#define BATCH_FACTOR 6 +/* ----------------------------- */ + +/* Logging related stuff */ +#define INT2IDX(x) (-1*(x)-1) +struct log_info_cat jibuf_test_cat[] = { + [INT2IDX(DLMUX)] = { + .name = "DLMUX", + .description = "Osmocom Osmux", + .enabled = 1, .loglevel = LOGL_DEBUG, + }, +}; +const struct log_info log_info = { + .filter_fn = NULL, + .cat = jibuf_test_cat, + .num_cat = ARRAY_SIZE(jibuf_test_cat), +}; +/* ----------------------------- */ + +static void rtp_init(uint16_t seq, uint16_t ts) +{ + rtp_next_seq = seq; + rtp_next_ts = ts; +} + +static struct msgb *rtp_new(uint16_t seq, uint8_t timestamp, uint8_t marker) +{ + struct msgb *msg; + struct rtp_hdr *rtph; + + msg = msgb_alloc(1500, "rtp"); + if (!msg) + exit(EXIT_FAILURE); + msgb_put(msg, sizeof(struct rtp_hdr)); + + rtph = (struct rtp_hdr *)msg->data; + rtph->version = RTP_VERSION; + rtph->marker = marker; + rtph->sequence = htons(seq); + rtph->timestamp = htons(timestamp); + rtph->ssrc = 0x6789; + return msg; +} + +static struct msgb *rtp_next(void) +{ + rtp_next_seq++; + rtp_next_ts += TIME_RTP_PKT_MS; + return rtp_new(rtp_next_seq, rtp_next_ts, 0); +} + +static void rtp_append_amr(struct msgb *msg, uint8_t ft) +{ + struct amr_hdr *amrh; + struct rtp_hdr *rtph = (struct rtp_hdr *)msg->data; + + msgb_put(msg, sizeof(struct amr_hdr)); + amrh = (struct amr_hdr *)rtph->data; + + amrh->cmr = 0; + amrh->q = 1; + amrh->f = 0; + amrh->ft = ft; + msgb_put(msg, osmo_amr_bytes(amrh->ft)); +} + +static void sigalarm_handler(int foo) +{ + printf("FAIL: test did not run successfully\n"); + exit(EXIT_FAILURE); +} + +#define clock_debug(fmt, args...) \ + do { \ + struct timespec ts; \ + struct timeval tv; \ + osmo_clock_gettime(CLOCK_MONOTONIC, &ts); \ + osmo_gettimeofday(&tv, NULL); \ + fprintf(stdout, "sys={%lu.%06lu}, mono={%lu.%06lu}: " fmt "\n", \ + tv.tv_sec, tv.tv_usec, ts.tv_sec, ts.tv_nsec/1000, ##args); \ + } while(0) + +static void clock_override_enable(bool enable) +{ + osmo_gettimeofday_override = enable; + osmo_clock_override_enable(CLOCK_MONOTONIC, enable); +} + +static void clock_override_set(long sec, long usec) +{ + struct timespec *mono; + osmo_gettimeofday_override_time.tv_sec = sec; + osmo_gettimeofday_override_time.tv_usec = usec; + mono = osmo_clock_override_gettimespec(CLOCK_MONOTONIC); + mono->tv_sec = sec; + mono->tv_nsec = usec*1000; + + clock_debug("clock_override_set"); +} + +static void clock_override_add_debug(long sec, long usec, bool dbg) +{ + osmo_gettimeofday_override_add(sec, usec); + osmo_clock_override_add(CLOCK_MONOTONIC, sec, usec*1000); + if (dbg) + clock_debug("clock_override_add"); +} +#define clock_override_add(sec, usec) clock_override_add_debug(sec, usec, true) + +static void test_amr_ft_change_middle_batch_osmux_deliver_cb(struct msgb *batch_msg, void *data) +{ + struct osmux_hdr *osmuxh; + char buf[2048]; + int n = 0; + bool *osmux_transmitted = (bool *)data; + + osmux_snprintf(buf, sizeof(buf), batch_msg); + clock_debug("OSMUX message (len=%d): %s\n", batch_msg->len, buf); + + /* We expect 3 batches: */ + while ((osmuxh = osmux_xfrm_output_pull(batch_msg))) { + n++; + OSMO_ASSERT(osmuxh->ft == OSMUX_FT_VOICE_AMR); + OSMO_ASSERT(osmuxh->rtp_m == 0); + OSMO_ASSERT(osmuxh->amr_cmr == 0); + OSMO_ASSERT(osmuxh->amr_q == 1); + switch (n) { + case 1: + OSMO_ASSERT(osmuxh->seq == 0); + OSMO_ASSERT(osmuxh->ctr == 1); + OSMO_ASSERT(osmuxh->amr_ft == AMR_FT_2); + break; + case 2: + OSMO_ASSERT(osmuxh->seq == 1); + OSMO_ASSERT(osmuxh->ctr == 0); + OSMO_ASSERT(osmuxh->amr_ft == AMR_FT_6); + break; + case 3: + OSMO_ASSERT(osmuxh->seq == 2); + OSMO_ASSERT(osmuxh->ctr == 0); + OSMO_ASSERT(osmuxh->amr_ft == AMR_FT_1); + break; + } + } + OSMO_ASSERT(n == 3); + + msgb_free(batch_msg); + + *osmux_transmitted = true; +} +/* Test if an RTP pkt with changed AMR FT passed to osmux_input is properly + * processed: The current batch ends and a new batch with a new osmux header is + * appeneded to the generated packet. */ +static void test_amr_ft_change_middle_batch(void) +{ + struct msgb *msg; + int rc; + const uint8_t cid = 30; + bool osmux_transmitted = false; + + printf("===%s===\n", __FUNCTION__); + + + clock_override_enable(true); + clock_override_set(0, 0); + rtp_init(0, 0); + + struct osmux_in_handle h_input = { + .osmux_seq = 0, /* sequence number to start OSmux message from */ + .batch_factor = 4, /* batch up to 4 RTP messages */ + .deliver = test_amr_ft_change_middle_batch_osmux_deliver_cb, + .data = &osmux_transmitted, + }; + + osmux_xfrm_input_init(&h_input); + osmux_xfrm_input_open_circuit(&h_input, cid, false); + + /* First RTP frame at t=0 */ + msg = rtp_next(); + rtp_append_amr(msg, AMR_FT_2); + rc = osmux_xfrm_input(&h_input, msg, cid); + OSMO_ASSERT(rc == 0); + + /* Second RTP frame at t=20 */ + clock_override_add(0, TIME_RTP_PKT_MS*1000); + msg = rtp_next(); + rtp_append_amr(msg, AMR_FT_2); + rc = osmux_xfrm_input(&h_input, msg, cid); + OSMO_ASSERT(rc == 0); + + /* Third RTP frame at t=40, AMR FT changes: */ + clock_debug("Submit RTP with 1st AMR FT change"); + clock_override_add(0, TIME_RTP_PKT_MS*1000); + msg = rtp_next(); + rtp_append_amr(msg, AMR_FT_6); + rc = osmux_xfrm_input(&h_input, msg, cid); + OSMO_ASSERT(rc == 0); + + /* Forth RTP frame at t=60, AMR FT changes again: */ + clock_debug("Submit RTP with 2nd AMR FT change"); + clock_override_add(0, TIME_RTP_PKT_MS*1000); + msg = rtp_next(); + rtp_append_amr(msg, AMR_FT_1); + rc = osmux_xfrm_input(&h_input, msg, cid); + OSMO_ASSERT(rc == 0); + + /* t=80, osmux batch is scheduled to be transmitted: */ + clock_override_add(0, TIME_RTP_PKT_MS*1000); + clock_debug("Osmux frame should now be transmitted"); + osmo_select_main(0); + OSMO_ASSERT(osmux_transmitted == true); + + clock_debug("Closing circuit"); + osmux_xfrm_input_close_circuit(&h_input, cid); + osmux_xfrm_input_fini(&h_input); +} + +int main(int argc, char **argv) +{ + + if (signal(SIGALRM, sigalarm_handler) == SIG_ERR) { + perror("signal"); + exit(EXIT_FAILURE); + } + + void *tall_ctx = talloc_named_const(NULL, 1, "Root context"); + msgb_talloc_ctx_init(tall_ctx, 0); + osmo_init_logging2(tall_ctx, &log_info); + log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE); + log_set_log_level(osmo_stderr_target, LOGL_DEBUG); + log_set_category_filter(osmo_stderr_target, DLMUX, 1, LOGL_DEBUG); + + alarm(10); + + test_amr_ft_change_middle_batch(); + + fprintf(stdout, "OK: Test passed\n"); + return EXIT_SUCCESS; +} diff --git a/tests/osmux/osmux_input_test.ok b/tests/osmux/osmux_input_test.ok new file mode 100644 index 0000000..9aca52e --- /dev/null +++ b/tests/osmux/osmux_input_test.ok @@ -0,0 +1,13 @@ +===test_amr_ft_change_middle_batch=== +sys={0.000000}, mono={0.000000}: clock_override_set +sys={0.020000}, mono={0.020000}: clock_override_add +sys={0.020000}, mono={0.020000}: Submit RTP with 1st AMR FT change +sys={0.040000}, mono={0.040000}: clock_override_add +sys={0.040000}, mono={0.040000}: Submit RTP with 2nd AMR FT change +sys={0.060000}, mono={0.060000}: clock_override_add +sys={0.080000}, mono={0.080000}: clock_override_add +sys={0.080000}, mono={0.080000}: Osmux frame should now be transmitted +sys={0.080000}, mono={0.080000}: OSMUX message (len=81): OSMUX seq=000 ccid=030 ft=1 rtp_m=0 ctr=1 amr_f=0 amr_q=1 amr_ft=02 amr_cmr=00 [ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ], OSMUX seq=001 ccid=030 ft=1 rtp_m=0 ctr=0 amr_f=0 amr_q=1 amr_ft=06 amr_cmr=00 [ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ], OSMUX seq=002 ccid=030 ft=1 rtp_m=0 ctr=0 amr_f=0 amr_q=1 amr_ft=01 amr_cmr=00 [ 00 00 00 00 00 00 00 00 00 00 00 00 00 ] + +sys={0.080000}, mono={0.080000}: Closing circuit +OK: Test passed diff --git a/tests/testsuite.at b/tests/testsuite.at index 17883cc..b84c4ee 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -20,6 +20,12 @@ AT_CHECK([$abs_top_builddir/tests/osmux/osmux_output_test], [0], [expout], [ignore]) AT_CLEANUP
+AT_SETUP([osmux_input_test]) +AT_KEYWORDS([osmux_input_test]) +cat $abs_srcdir/osmux/osmux_input_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/osmux/osmux_input_test], [0], [expout], [ignore]) +AT_CLEANUP + AT_SETUP([jibuf_test]) AT_KEYWORDS([jibuf_test]) cat $abs_srcdir/jibuf/jibuf_test.ok > expout