From f294a6d8fea604325f915647c78e2ee89b79b5af Mon Sep 17 00:00:00 2001 From: Oliver Smith Date: Fri, 11 Oct 2019 16:37:59 +0200 Subject: [PATCH] ttcn3.sh: run ttcn3 testsuites from osmo-dev Build testsuite, SUT and dependencies and run everything with one command. Example usage: $ ./ttcn3.sh msc So far, it works at least with: hlr, mgw, msc, pcu, pcu-sns, sgsn Change-Id: I6b4bf2743adeec1a950d5f090a690182b991cf49 --- .gitignore | 6 + README | 20 ++ src/fake_trx.sh | 23 +++ src/osmo-bts-trx-respawn.sh | 6 + src/osmo-pcu-respawn.sh | 6 + ttcn3.opts | 1 + ttcn3.sh | 368 ++++++++++++++++++++++++++++++++++++ 7 files changed, 430 insertions(+) create mode 100755 src/fake_trx.sh create mode 100755 src/osmo-bts-trx-respawn.sh create mode 100755 src/osmo-pcu-respawn.sh create mode 100644 ttcn3.opts create mode 100755 ttcn3.sh diff --git a/.gitignore b/.gitignore index 1cfde3d..c8ebef4 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,9 @@ net/* !net/config_2g3g !net/README !net/fill_config.py + +# ttcn3.sh +ttcn3_out/ +3G+2G_ttcn3.deps +!src/fake_trx.sh +!src/osmo-*-respawn.sh diff --git a/README b/README index 9533d89..36cd225 100644 --- a/README +++ b/README @@ -132,6 +132,26 @@ default is /usr/local. Find other useful scripts in src/, see src/README. +=== ttcn3.sh + +Clone and build all dependencies, then run a given TTCN-3 testsuite and all +required components. This is intended to make test-cycles as short as possible, +without any manual configuration effort and without the need to rebuild the +entire testsuite, SUT (subject under test, e.g. osmo-mgw) and dependencies from +scratch for each code change. Instead, ttcn3.sh will make use of osmo-dev's +generated global makefile and only build what actually changed. + +Example usage: + + ./ttcn3.sh mgw + +Note that not all testsuites are supported at this point, see the output of +ttcn3.sh without any argument for more information. + +More about the testsuites: +https://osmocom.org/projects/cellular-infrastructure/wiki/Titan_TTCN3_Testsuites + + === Troubleshooting When using sanitize.opts, osmo-trx is not built with the address sanitizer diff --git a/src/fake_trx.sh b/src/fake_trx.sh new file mode 100755 index 0000000..1d39573 --- /dev/null +++ b/src/fake_trx.sh @@ -0,0 +1,23 @@ +#!/bin/sh -x +# Run in a separate script, so we can kill it with "killall" + +DIR="$(readlink -f "$(dirname $0)")" +cd "$DIR" +PID="" + +cleanup() { + echo "Caught signal, cleaning up..." + set -x + kill "$PID" + exit 1 +} + +trap cleanup "TERM" + +./osmocom-bb/src/target/trx_toolkit/fake_trx.py "$@" & +PID="$!" + +set +x +while true; do + sleep 0.1 +done diff --git a/src/osmo-bts-trx-respawn.sh b/src/osmo-bts-trx-respawn.sh new file mode 100755 index 0000000..475f807 --- /dev/null +++ b/src/osmo-bts-trx-respawn.sh @@ -0,0 +1,6 @@ +#!/bin/sh -x +# Automatically restart osmo-bts-trx while running TTCN3 tests. See docker-playground.git. + +while true; do + osmo-bts-trx "$@" +done diff --git a/src/osmo-pcu-respawn.sh b/src/osmo-pcu-respawn.sh new file mode 100755 index 0000000..3ff7213 --- /dev/null +++ b/src/osmo-pcu-respawn.sh @@ -0,0 +1,6 @@ +#!/bin/sh -x +# Automatically restart osmo-pcu while running TTCN3 tests. See docker-playground.git's osmo-pcu-master/respawn.sh. + +while true; do + osmo-pcu "$@" +done diff --git a/ttcn3.opts b/ttcn3.opts new file mode 100644 index 0000000..8acec2d --- /dev/null +++ b/ttcn3.opts @@ -0,0 +1 @@ +osmo-bts --enable-trx diff --git a/ttcn3.sh b/ttcn3.sh new file mode 100755 index 0000000..5d0eb40 --- /dev/null +++ b/ttcn3.sh @@ -0,0 +1,368 @@ +#!/bin/sh -e +PROJECT="$1" +PROJECT_UPPER="$(echo "$PROJECT" | tr '[:lower:]' '[:upper:]')" +DIR_OSMODEV="$(readlink -f "$(dirname $0)")" +DIR_MAKE="${DIR_MAKE:-${DIR_OSMODEV}/make-ttcn3}" +DIR_OUTPUT="${DIR_OUTPUT:-${DIR_OSMODEV}/ttcn3_out}" +JOBS="${JOBS:-9}" + +check_usage() { + if [ -z "$PROJECT" ]; then + echo "usage: $(basename $0) PROJECT" + echo "example: $(basename $0) hlr" + echo "known working projects: hlr, mgw, msc, pcu, pcu-sns, sgsn" + echo "wip: bts, bts-oml" + echo "" + echo "notes (see docker-playground.git/ttcn3-*/jenkins.sh):" + echo "- bts: classic test suite with BSC for OML and trxcon+fake_trx" + echo "- bts-oml: OML tests (without BSC)" + exit 1 + fi +} + +# Returns the name of the testsuite binary +get_testsuite_name() { + case "$PROJECT" in + bts-*) echo "BTS_Tests" ;; + mgw) echo "MGCP_Test" ;; + pcu-sns) echo "PCU_Tests" ;; + *) echo "${PROJECT_UPPER}_Tests" ;; + esac +} + +get_testsuite_dir() { + local hacks="${DIR_OSMODEV}/src/osmo-ttcn3-hacks" + + case "$PROJECT" in + bts-*) echo "$hacks/bts" ;; + pcu-sns) echo "$hacks/pcu" ;; + *) echo "$hacks/$PROJECT" ;; + esac +} + +get_testsuite_config() { + case "$PROJECT" in + bts-gprs) echo "BTS_Tests_GPRS.cfg" ;; + bts-oml) echo "BTS_Tests_OML.cfg" ;; + pcu-sns) echo "PCU_Tests_SNS.cfg" ;; + *) echo "$(get_testsuite_name).cfg" ;; + esac +} + +# Programs that need to be built, launched and killed. To add programs to only one of the steps, modify the appropriate +# function below (build_osmo_programs, run_osmo_programs, kill_osmo_programs). +get_programs() { + case "$PROJECT" in + bsc) echo "osmo-stp osmo-bsc osmo-bts-omldummy" ;; + bts) echo "osmo-bsc osmo-bts-trx fake_trx.py trxcon" ;; + msc) echo "osmo-stp osmo-msc" ;; + pcu-sns) echo "osmo-pcu" ;; + pcu) echo "osmo-pcu osmo-bsc osmo-bts-virtual virtphy" ;; + sgsn) echo "osmo-stp osmo-sgsn" ;; + *) echo "osmo-$PROJECT" ;; + esac +} + +# $1: program name +get_program_config() { + case "$1" in + fake_trx.py) ;; # no config + osmo-bts-*) echo "osmo-bts.cfg" ;; + osmo-pcu) + if [ "$PROJECT" = "pcu-sns" ]; then + echo "osmo-pcu-sns.cfg" + else + echo "osmo-pcu.cfg" + fi + ;; + trxcon) ;; # no config + virtphy) ;; # no config + *) echo "$1.cfg" ;; + esac +} + +# Return the git repository name, which has the source for a specific program. +# $1: program name +get_program_repo() { + case "$1" in + fake_trx.py) echo "osmocom-bb" ;; + osmo-bts-*) echo "osmo-bts" ;; + osmo-stp) echo "libosmo-sccp" ;; + trxcon) echo "osmocom-bb" ;; + virtphy) echo "osmocom-bb" ;; + *) echo "$1" ;; + esac +} + +check_ttcn3_install() { + if ! command -v ttcn3_compiler > /dev/null; then + echo "ERROR: ttcn3_compiler is not installed." + echo "Install eclipse-titan from the Osmocom latest repository." + echo "Details: https://osmocom.org/projects/cellular-infrastructure/wiki/Titan_TTCN3_Testsuites" + exit 1 + fi +} + +kill_osmo_programs() { + programs="$(get_programs)" + + # Kill wrappers first + for program in $programs; do + case "$program" in + osmo-pcu) killall osmo-pcu-respawn.sh || true ;; + osmo-bts-trx) killall osmo-bts-trx-respawn.sh || true ;; + fake_trx.py) killall fake_trx.sh || true ;; + esac + done + + killall $programs || true +} + +setup_dir_make() { + cd "$DIR_OSMODEV" + + ( echo "# Generated by ttcn3.sh, do not edit" + cat ./3G+2G.deps + echo + echo "osmo-bts libosmocore libosmo-abis" + echo "osmo-pcu libosmocore" + # just clone these, building is handled by ttcn3.sh + echo "osmo-ttcn3-hacks" + echo "osmocom-bb") > 3G+2G_ttcn3.deps + + ./gen_makefile.py 3G+2G_ttcn3.deps default.opts iu.opts no_systemd.opts ttcn3.opts -I -m make-ttcn3 +} + +# $1: name of repository (e.g. osmo-ttcn3-hacks) +clone_repo() { + make -C "$DIR_MAKE" ".make.${1}.clone" +} + +# Require testsuite dir, with testsuite and all program configs +check_dir_testsuite() { + local program + local config_testsuite + local dir_testsuite="$(get_testsuite_dir)" + + if ! [ -d "$dir_testsuite" ]; then + echo "ERROR: project '$PROJECT' is invalid, resulting path not found: $dir_testsuite" + exit 1 + fi + + for program in $(get_programs); do + local config="$(get_program_config "$program")" + if [ -z "$config" ]; then + continue + fi + config="$dir_testsuite/$config" + if ! [ -e "$config" ]; then + echo "ERROR: config not found: $config" + echo "Copy it from docker-playground.git, and change IPs to 127.0.0.*." + echo "Make sure that everything works, then submit a patch with the config." + echo "If $program's config has a different name or is not needed at all, edit" + echo "get_program_config() in ttcn3.sh." + exit 1 + fi + done + + config_testsuite="$dir_testsuite/$(get_testsuite_config)" + if ! [ -e "$config_testsuite" ]; then + echo "ERROR: testsuite config not found: $config_testsuite" + echo "Copy it from docker-playground.git, change the paths to be relative and submit it as patch." + echo "If $program's testsuite has a different name, edit get_testsuite_name() in ttcn3.sh." + exit 1 + fi +} + +# Build a program that is in the subdir of a repository (e.g. trxcon in osmocom-bb.git). +# $1: repository +# $2: path in the repository +build_osmo_program_subdir() { + clone_repo "$1" + cd "$DIR_OSMODEV/src/$1/$2" + if ! [ -e "./configure" ] && [ -e "configure.ac" ]; then + autoreconf -fi + fi + if ! [ -e "Makefile" ] && [ -e "Makefile.am" ]; then + ./configure + fi + make -j"$JOBS" +} + +# Use osmo-dev to build a typical Osmocom program, and run a few sanity checks. +# $1 program +build_osmo_program_osmodev() { + local repo="$(get_program_repo "$program")" + make -C "$DIR_MAKE" "$repo" + + local path="$(command -v "$program")" + if [ -z "$path" ]; then + echo "ERROR: program was not installed to PATH: $program" + echo "Maybe you need to add /usr/local/bin to PATH?" + exit 1 + fi + + local pathdir="$(dirname "$path")" + local reference="$DIR_MAKE/.make.$repo.build" + if [ -z "$(find "$pathdir" -name "$program" -newer "$reference")" ]; then + echo "ERROR: $path is outdated!" + echo "Maybe you need to pass a configure argument to $repo.git, so it builds and installs $program?" + echo "Or the order in PATH is wrong?" + exit 1 + fi +} + +# Use osmo-dev to build one Osmocom program and its dependencies +build_osmo_programs() { + local program + for program in $(get_programs); do + case "$program" in + fake_trx.py) clone_repo "osmocom-bb" ;; + trxcon) build_osmo_program_subdir "osmocom-bb" "src/host/trxcon" ;; + virtphy) build_osmo_program_subdir "osmocom-bb" "src/host/virt_phy" ;; + *) build_osmo_program_osmodev "$program" ;; + esac + done +} + +build_testsuite() { + cd "$(get_testsuite_dir)" + ./gen_links.sh + ./regen_makefile.sh + make compile + make -j"$JOBS" +} + +remove_old_logs() { + cd "$(get_testsuite_dir)" + rm *.log *.merged 2> /dev/null || true +} + +prepare_dir_output() { + local program + local dir_testsuite="$(get_testsuite_dir)" + + rm -r "$DIR_OUTPUT"/* 2> /dev/null || true + mkdir -p "$DIR_OUTPUT" + + for program in $(get_programs); do + local config="$(get_program_config "$program")" + if [ -n "$config" ]; then + cp "$dir_testsuite/$config" "$DIR_OUTPUT" + fi + done +} + +# $1: log name +# $2: command to run +run_osmo_program() { + local pid + local log="$1" + shift + + echo "Starting ($log): $@" + "$@" > "$log" 2>&1 & + pid="$!" + + sleep 0.5 + if ! kill -0 "$pid" 2> /dev/null; then + echo "ERROR: failed to start: $@" + cat "$log" + exit 1 + fi +} + +run_osmo_programs() { + local program + local osmocom_bb="$DIR_OSMODEV/src/osmocom-bb" + + cd "$DIR_OUTPUT" + for program in $(get_programs); do + case "$program" in + fake_trx.py) + run_osmo_program "fake_trx.log" \ + "$DIR_OSMODEV/src/fake_trx.sh" \ + --log-level DEBUG \ + -b 127.0.0.21 \ + -R 127.0.0.20 \ + -r 127.0.0.22 + ;; + osmo-bts-omldummy) + for i in $(seq 0 2); do + run_osmo_program "osmo-bts-$i.log" osmo-bts-omldummy 127.0.0.1 $((i + 1234)) 1 + done + ;; + osmo-bts-trx) + run_osmo_program "$program.log" \ + "$DIR_OSMODEV/src/osmo-bts-trx-respawn.sh" -i 127.0.0.10 + ;; + osmo-pcu) + run_osmo_program "$program.log" "$DIR_OSMODEV/src/osmo-pcu-respawn.sh" \ + -c "$(get_program_config osmo-pcu)" + ;; + trxcon) + run_osmo_program "$program.log" \ + "$osmocom_bb/src/host/trxcon/trxcon" \ + trxcon -i 127.0.0.21 \ + -s /tmp/osmocom_l2 + ;; + virtphy) + run_osmo_program "$program.log" "$osmocom_bb/src/host/virt_phy/src/virtphy" \ + -s /tmp/osmocom_l2 + ;; + *) + run_osmo_program "$program.log" "$program" + ;; + esac + done +} + +run_testsuite() { + local testsuite="$(get_testsuite_name)" + local cfg="$(get_testsuite_config)" + + cd "$(get_testsuite_dir)" + ../start-testsuite.sh "$testsuite" "$cfg" 2>&1 | tee "$DIR_OUTPUT/ttcn3_stdout.log" +} + +collect_logs() { + # Merge and move logs + cd "$(get_testsuite_dir)" + ../log_merge.sh $(get_testsuite_name) --rm + if ! mv *.merged "$DIR_OUTPUT"; then + echo "---" + echo "ERROR: no logs generated! Invalid test names in $(get_testsuite_config)?" + echo "---" + exit 1 + fi + + # Format logs + cd "$DIR_OUTPUT" + for log in *.merged; do + ttcn3_logformat -o "${log}.log" "$log" + rm "$log" + done + + # Print log path + echo "---" + echo "Logs: $DIR_OUTPUT" + echo "---" +} + +# Tell glibc to print segfault output to stderr (OS#4212) +export LIBC_FATAL_STDERR_=1 + +check_usage +kill_osmo_programs +check_ttcn3_install +setup_dir_make +clone_repo "osmo-ttcn3-hacks" +check_dir_testsuite +build_osmo_programs +build_testsuite +remove_old_logs +prepare_dir_output +run_osmo_programs +run_testsuite +kill_osmo_programs +collect_logs