Add ttcn3-bts-test env

Change-Id: I3251a49503dc823f0ef1fe8ef5d68236a584dad4
This commit is contained in:
Pau Espin 2018-05-17 16:59:58 +02:00
parent 1dc9a04bc1
commit bc1ed88304
18 changed files with 395 additions and 2 deletions

1
.gitignore vendored
View File

@ -10,3 +10,4 @@ state
*.pyc
selftest/trial_test/
example/resources.conf
ttcn3/resources.conf

View File

@ -114,3 +114,6 @@ modem:
auth_algo: 'comp128v1'
ciphers: [a5_0, a5_1]
features: ['gprs', 'sim']
osmocon_phone:
- serial_device: '/dev/serial/by-id/usb-Silicon_Labs_CP2104_USB_to_UART_Bridge_Controller_00897B41-if00-port0'

View File

@ -87,3 +87,6 @@ modem:
auth_algo: 'comp128v1'
ciphers: [a5_0, a5_1]
features: ['gprs', 'sim']
osmocon_phone:
- serial_device: '/dev/serial/by-id/usb-Silicon_Labs_CP2104_USB_to_UART_Bridge_Controller_0089279D-if00-port0'

View File

@ -0,0 +1,103 @@
# osmo_gsm_tester: specifics for running an osmocon
#
# Copyright (C) 2018 by sysmocom - s.f.m.c. GmbH
#
# Author: Pau Espin Pedrol <pespin@sysmocom.de>
#
# 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 3 of the
# License, or (at your option) any later version.
#
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
import os
import tempfile
from . import log, util, process
from .event_loop import MainLoop
class Osmocon(log.Origin):
suite_run = None
run_dir = None
process = None
sk_tmp_dir = None
FIRMWARE_FILE="opt/osmocom-bb/target/firmware/board/compal_e88/layer1.compalram.bin"
def __init__(self, suite_run, conf):
serial_device = conf.get('serial_device')
if serial_device is None:
raise log.Error('osmocon_phone contains no attr "serial_device"')
self.serial_device = os.path.realpath(serial_device)
super().__init__(log.C_RUN, 'osmocon_%s' % os.path.basename(self.serial_device))
self.suite_run = suite_run
self.conf = conf
self.sk_tmp_dir = tempfile.mkdtemp('', 'ogtosmoconsk')
if len(self.l2_socket_path().encode()) > 107:
raise log.Error('Path for l2 socket is longer than max allowed len for unix socket path (107):', self.l2_socket_path())
if len(self.loader_socket_path().encode()) > 107:
raise log.Error('Path for loader socket is longer than max allowed len for unix socket path (107):', self.loader_socket_path())
def l2_socket_path(self):
return os.path.join(self.sk_tmp_dir, 'osmocom_l2')
def loader_socket_path(self):
return os.path.join(self.sk_tmp_dir, 'osmocom_loader')
def start(self):
self.log('Resetting the phone')
# TODO: make sure the pone is powered off before starting osmocon
self.log('Starting osmocon')
self.run_dir = util.Dir(self.suite_run.get_test_run_dir().new_dir(self.name()))
inst = util.Dir(os.path.abspath(self.suite_run.trial.get_inst('osmocom-bb')))
binary = inst.child('sbin', 'osmocon')
if not os.path.isfile(binary):
raise RuntimeError('Binary missing: %r' % binary)
lib = inst.child('lib')
if not os.path.isdir(lib):
raise RuntimeError('No lib/ in %r' % inst)
env = { 'LD_LIBRARY_PATH': util.prepend_library_path(lib) }
firmware_path = os.path.join(str(inst), Osmocon.FIRMWARE_FILE)
if not os.path.isfile(firmware_path):
raise RuntimeError('Binary missing: %r' % firmware_path)
self.dbg(run_dir=self.run_dir, binary=binary, env=env)
self.process = process.Process(self.name(), self.run_dir,
(binary, '-p', self.serial_device,
'-m', 'c123xor',
'-s', self.l2_socket_path(),
'-l', self.loader_socket_path(),
firmware_path),
env=env)
self.suite_run.remember_to_stop(self.process)
self.process.launch()
self.log('Waiting for osmocon to be up and running')
MainLoop.wait(self, os.path.exists, self.l2_socket_path())
def running(self):
return not self.process.terminated()
def cleanup(self):
if self.sk_tmp_dir:
try:
os.remove(self.l2_socket_path())
except OSError:
pass
try:
os.remove(self.loader_socket_path())
except OSError:
pass
os.rmdir(self.sk_tmp_dir)
# vim: expandtab tabstop=4 shiftwidth=4

View File

@ -44,7 +44,8 @@ R_IP_ADDRESS = 'ip_address'
R_BTS = 'bts'
R_ARFCN = 'arfcn'
R_MODEM = 'modem'
R_ALL = (R_IP_ADDRESS, R_BTS, R_ARFCN, R_MODEM)
R_OSMOCON = 'osmocon_phone'
R_ALL = (R_IP_ADDRESS, R_BTS, R_ARFCN, R_MODEM, R_OSMOCON)
RESOURCES_SCHEMA = {
'ip_address[].addr': schema.IPV4,
@ -76,6 +77,7 @@ RESOURCES_SCHEMA = {
'modem[].auth_algo': schema.AUTH_ALGO,
'modem[].ciphers[]': schema.CIPHER,
'modem[].features[]': schema.MODEM_FEATURE,
'osmocon_phone[].serial_device': schema.STR,
}
WANT_SCHEMA = util.dict_add(

View File

@ -23,7 +23,7 @@ import time
import pprint
from . import config, log, template, util, resource, schema, test
from .event_loop import MainLoop
from . import osmo_nitb, osmo_hlr, osmo_mgcpgw, osmo_mgw, osmo_msc, osmo_bsc, osmo_stp, osmo_ggsn, osmo_sgsn, modem, esme
from . import osmo_nitb, osmo_hlr, osmo_mgcpgw, osmo_mgw, osmo_msc, osmo_bsc, osmo_stp, osmo_ggsn, osmo_sgsn, modem, esme, osmocon
class Timeout(Exception):
pass
@ -332,6 +332,12 @@ class SuiteRun(log.Origin):
self.register_for_cleanup(esme_obj)
return esme_obj
def osmocon(self, specifics=None):
conf = self.reserved_resources.get(resource.R_OSMOCON, specifics=specifics)
osmocon_obj = osmocon.Osmocon(self, conf=conf)
self.register_for_cleanup(osmocon_obj)
return osmocon_obj
def msisdn(self):
msisdn = self.resources_pool.next_msisdn(self)
self.log('using MSISDN', msisdn)

20
ttcn3/README.txt Normal file
View File

@ -0,0 +1,20 @@
This directory contains a set of scripts and osmo-gsm-tester testsuites to run
osmo-ttcn3-hacks.git BTS_tests.ttcn (https://git.osmocom.org/osmo-ttcn3-hacks/tree/bts).
The idea is to set up automatically the following components:
TTCN3 <-> osmocon (osmocom-bb) <-> motorola C123 <-> RF network <-> BTS_TO_TEST <-> TTCN3 + osmo-bsc
* A jenkins job builds a docker image containing a built BTS_tests TTCN testsuite.
* Another jenkins job retrieves the artifacts from osmo-gsm-tester-build jobs
plus one for required osmocon binary. This job then calls osmo-gsm-tester/ttcn3/jenkins-run.sh, which will:
** Pull the above mentioned docker image containing BTS_Tests.
** Start osmo-gsm-tester with OSMO_GSM_TESTER_OPTS=osmo-gsm-tester/ttcn3/paths.conf,
that contains mostly same stuff as regular osmo-gsm-tester jobs, but with a
different testsuite containing 1 test "ttcn3_bts_tests.py".
** The test "ttcn3_bts_tests.py" does the following:
*** Start and manage all osmocom required components to run BTS_Tests: osmo-bts, osmo-bsc, osmocon, etc.
*** Generate the BTS_Tests.cfg required by BTS_Tests from a template to adapt to dynamic bits set by osmo-gsm-tester.
*** Launch script osmo-gsm-tester/ttcn3/suites/ttcn3_bts_tests/scripts/run_ttcn3_docker.sh with parameters and wait for it to finish.
This script will start and manage the lifecycle of the docker container running BTS_Tests
See OS#3155 for more information regarding this topic.

View File

@ -0,0 +1 @@
- ttcn3_bts_tests:trx

1
ttcn3/defaults.conf Symbolic link
View File

@ -0,0 +1 @@
../example/defaults.conf

58
ttcn3/jenkins-run.sh Executable file
View File

@ -0,0 +1,58 @@
#!/bin/sh
set -e -x
base="$PWD"
time_start="$(date '+%F %T')"
prepare_docker() {
OLDPWD=$PWD
# update docker-playground and update the BSC and bsc-test containers (if needed)
DIR=~/jenkins/docker-playground
if [ ! -d "$DIR" ]; then
mkdir -p ~/jenkins/ && cd ~/jenkins
git clone git://git.osmocom.org/docker-playground
fi
cd $DIR
git remote prune origin; git fetch; git checkout -f -B master origin/master
cd $DIR/debian-stretch-titan && make
docker pull laforge/debian-stretch-titan:latest # HACK
cd $DIR/ttcn3-bts-test && make
# execute the script to start containers, read results, ...
#cd $DIR/ttcn3-bts-test && sh -x ./jenkins.sh
PWD=$OLDPWD
}
docker pull registry.sysmocom.de/ttcn3-bts-test
# remove older trial dirs and *-run.tgz, if any
trial_dir_prefix="trial-"
rm -rf "$trial_dir_prefix"* || true
# Expecting *.tgz artifacts to be copied to this workspace from the various
# jenkins-*.sh runs, via jenkins job configuration. Compose a trial dir:
trial_dir="${trial_dir_prefix}$BUILD_NUMBER"
mkdir -p "$trial_dir"
mv *.tgz "$trial_dir"
cat *.md5 >> "$trial_dir/checksums.md5"
rm *.md5
# OSMO_GSM_TESTER_OPTS is a way to pass in e.g. logging preferences from the
# jenkins build job.
# On failure, first clean up below and then return the exit code.
exit_code="1"
if python3 -u "$(which osmo-gsm-tester.py)" "$trial_dir" $OSMO_GSM_TESTER_OPTS ; then
exit_code="0"
fi
# no need to keep extracted binaries
rm -rf "$trial_dir/inst" || true
# tar up all results for archiving (optional)
cd "$trial_dir"
journalctl -u ofono -o short-precise --since "${time_start}" > "$(readlink last_run)/ofono.log"
tar czf "$base/${trial_dir}-run.tgz" "$(readlink last_run)"
tar czf "$base/${trial_dir}-bin.tgz" *.md5 *.tgz
exit $exit_code

3
ttcn3/paths.conf Normal file
View File

@ -0,0 +1,3 @@
state_dir: '/var/tmp/osmo-gsm-tester/state'
suites_dir: './suites'
scenarios_dir: './scenarios'

1
ttcn3/resources.conf.prod Symbolic link
View File

@ -0,0 +1 @@
../example/resources.conf.prod

1
ttcn3/resources.conf.rnd Symbolic link
View File

@ -0,0 +1 @@
../example/resources.conf.rnd

1
ttcn3/scenarios/trx.conf Symbolic link
View File

@ -0,0 +1 @@
../../example/scenarios/trx.conf

View File

@ -0,0 +1,25 @@
[ORDERED_INCLUDE]
"/osmo-ttcn3-hacks/Common.cfg"
"/osmo-ttcn3-hacks/bts/BTS_Tests.default"
[LOGGING]
[TESTPORT_PARAMETERS]
*.BTSVTY.CTRL_HOSTNAME := "${btsvty_ctrl_hostname}"
[MODULE_PARAMETERS]
BTS_Tests.mp_rsl_ip := "172.18.9.10"
BTS_Tests.mp_bb_trxc_ip := "127.0.0.1"
BTS_Tests.mp_pcu_socket := "/data/unix_pcu/pcu_bts"
BTS_Tests.mp_bb_trxc_port := -1
L1CTL_PortType.m_l1ctl_sock_path := "/data/unix_l2/osmocom_l2"
BTS_Tests.mp_ctrl_ip := "${btsvty_ctrl_hostname}"
BTS_Tests.mp_rxlev_exp := 1
BTS_Tests.mp_tolerance_rxlev := 10;
BTS_Tests.mp_tolerance_rxqual := 1;
BTS_Tests.mp_trx0_arfcn := 868
[MAIN_CONTROLLER]
[EXECUTE]
BTS_Tests.control

View File

@ -0,0 +1,86 @@
#!/bin/sh
set -x
RUNDIR="$1"
JUNIT_TTCN3_DST_FILE="$2"
L2_SOCKET_PATH="$3"
PCU_SOCKET_PATH="$4"
# Absolute path to this script
SCRIPT=$(readlink -f "$0")
# Absolute path this script is in
SCRIPTPATH=$(dirname "$SCRIPT")
VOL_BASE_DIR="$RUNDIR/logs"
rm -rf "$VOL_BASE_DIR"
mkdir -p "$VOL_BASE_DIR"
if [ "x$BUILD_TAG" = "x" ]; then
BUILD_TAG=nonjenkins
fi
REPO_USER="registry.sysmocom.de"
SUITE_NAME="ttcn3-bts-test"
NET_NAME=$SUITE_NAME
DOCKER_NAME="$BUILD_TAG-$SUITE_NAME"
network_create() {
NET=$1
echo Creating network $NET_NAME
docker network create --internal --subnet $NET $NET_NAME
}
network_remove() {
echo Removing network $NET_NAME
docker network remove $NET_NAME
}
child_ps=0
forward_kill() {
sig="$1"
echo "Caught signal SIG$sig!"
if [ "$child_ps" != "0" ]; then
echo "Killing $child_ps with SIG$sig!"
docker kill ${DOCKER_NAME}
fi
exit 130
}
forward_kill_int() {
forward_kill "INT"
}
forward_kill_term() {
forward_kill "TERM"
}
# Don't use 'set -e', otherwise traps are not triggered!
trap forward_kill_int INT
trap forward_kill_term TERM
network_create 172.18.9.0/24
mkdir $VOL_BASE_DIR/bts-tester
echo "SCRIPTPATH=$SCRIPTPATH PWD=$PWD"
cp $RUNDIR/BTS_Tests.cfg $VOL_BASE_DIR/bts-tester/
echo Starting container with BTS testsuite
docker kill ${DOCKER_NAME}
docker run --rm \
--network $NET_NAME --ip 172.18.9.10 \
-e "TTCN3_PCAP_PATH=/data" \
--mount type=bind,source=$VOL_BASE_DIR/bts-tester,destination=/data \
--mount type=bind,source="$(dirname "$L2_SOCKET_PATH")",destination=/data/unix_l2 \
--mount type=bind,source="$(dirname "$PCU_SOCKET_PATH")",destination=/data/unix_pcu \
--name ${DOCKER_NAME} \
$REPO_USER/${SUITE_NAME} &
child_ps=$!
echo "$$: waiting for $child_ps"
wait "$child_ps"
child_exit_code="$?"
echo "ttcn3 docker exited with code $child_exit_code"
network_remove
echo "Copying TTCN3 junit file to $JUNIT_TTCN3_DST_FILE"
cp $VOL_BASE_DIR/bts-tester/junit-xml-*.log $JUNIT_TTCN3_DST_FILE
sed -i "s#classname='BTS_Tests'#classname='$(basename $JUNIT_TTCN3_DST_FILE)'#g" $JUNIT_TTCN3_DST_FILE
exit $child_exit_code

View File

@ -0,0 +1,7 @@
resources:
ip_address:
- times: 7 # msc, bsc, hlr, stp, mgw, sgsn, ggsn
bts:
- times: 1
osmocon_phone:
- times: 1

View File

@ -0,0 +1,71 @@
#!/usr/bin/env python3
import os
from mako.template import Template
from osmo_gsm_tester.testenv import *
hlr_dummy = suite.hlr()
mgw_dummy = suite.mgw()
stp_dummy = suite.stp()
msc_dummy = suite.msc(hlr_dummy, mgw_dummy, stp_dummy)
ggsn_dummy = suite.ggsn()
sgsn_dummy = suite.sgsn(hlr_dummy, ggsn_dummy)
bsc = suite.bsc(msc_dummy, mgw_dummy, stp_dummy)
bts = suite.bts()
osmocon = suite.osmocon()
bts.set_num_trx(1)
bts.set_trx_phy_channel(0, 0, 'CCCH+SDCCH4')
bts.set_trx_phy_channel(0, 1, 'TCH/F')
bts.set_trx_phy_channel(0, 2, 'TCH/F')
bts.set_trx_phy_channel(0, 3, 'TCH/F_PDCH')
bts.set_trx_phy_channel(0, 4, 'TCH/F_TCH/H_PDCH')
bts.set_trx_phy_channel(0, 5, 'TCH/H')
bts.set_trx_phy_channel(0, 6, 'SDCCH8')
bts.set_trx_phy_channel(0, 7, 'PDCH')
print('Starting CNI')
hlr_dummy.start()
stp_dummy.start()
msc_dummy.start()
mgw_dummy.start()
bsc.set_rsl_ip('172.18.9.10')
bsc.bts_add(bts)
sgsn_dummy.bts_add(bts)
bsc.start()
bts.start(keepalive=True)
print('Starting osmocon')
osmocon.start()
own_dir = os.path.dirname(os.path.realpath(__file__))
script_file = os.path.join(own_dir, 'scripts', 'run_ttcn3_docker.sh')
bts_tmpl_file = os.path.join(own_dir, 'scripts', 'BTS_Tests.cfg.tmpl')
script_run_dir = test.get_run_dir().new_dir('ttcn3')
bts_cfg_file = os.path.join(str(script_run_dir), 'BTS_Tests.cfg')
junit_ttcn3_dst_file = os.path.join(str(suite.trial.get_run_dir()), 'trial-') + suite.name() + '.xml'
docker_cmd = (script_file, str(script_run_dir), junit_ttcn3_dst_file, osmocon.l2_socket_path(), bts.pcu_socket_path())
print('Creating template')
mytemplate = Template(filename=bts_tmpl_file)
r = mytemplate.render(btsvty_ctrl_hostname=bts.remote_addr())
with open(bts_cfg_file, 'w') as f:
f.write(r)
print('Starting TTCN3 tests')
proc = process.Process('ttcn3', script_run_dir, docker_cmd)
try:
proc.launch()
print('Starting TTCN3 launched, waiting until it finishes')
proc.wait(timeout=3600)
except Exception as e:
proc.terminate()
raise e
if proc.result != 0:
raise RuntimeError("run_ttcn3_docker.sh exited with error code %d" % proc.result)
print('Done')