ttcn3: run ttcn3 testsuites from osmo-dev
Build testsuite, SUT and dependencies and run everything with one
command. Example usage:
$ ./ttcn3/ttcn3.sh msc
So far, it works at least with:
hlr, mgw, msc, pcu, pcu-sns, sgsn
Change-Id: I6b4bf2743adeec1a950d5f090a690182b991cf49
diff --git a/ttcn3/ttcn3.sh b/ttcn3/ttcn3.sh
new file mode 100755
index 0000000..4cb4344
--- /dev/null
+++ b/ttcn3/ttcn3.sh
@@ -0,0 +1,369 @@
+#!/bin/sh -e
+PROJECT="$1"
+PROJECT_UPPER="$(echo "$PROJECT" | tr '[:lower:]' '[:upper:]')"
+DIR_OSMODEV="$(readlink -f "$(dirname $0)/..")"
+DIR_MAKE="${DIR_MAKE:-${DIR_OSMODEV}/ttcn3/make}"
+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") > ttcn3/3G+2G_ttcn3.deps
+
+ ./gen_makefile.py ttcn3/3G+2G_ttcn3.deps default.opts iu.opts no_systemd.opts ttcn3/ttcn3.opts -I -m "$DIR_MAKE"
+}
+
+# $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"
+ local wrappers="$DIR_OSMODEV/ttcn3/wrappers"
+
+ cd "$DIR_OUTPUT"
+ for program in $(get_programs); do
+ case "$program" in
+ fake_trx.py)
+ run_osmo_program "fake_trx.log" \
+ "$wrappers/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" \
+ "$wrappers/osmo-bts-trx-respawn.sh" -i 127.0.0.10
+ ;;
+ osmo-pcu)
+ run_osmo_program "$program.log" "$wrappers/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