From ea02f587a8cd7b8db899b04e41f64d2bda73a84b Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 24 Jul 2019 14:15:27 -0600 Subject: [PATCH] CI: Don't enable non-core modules in Certified branches We don't support non-core modules for Certified releases but we were enabling them for CI builds which was causing lots of test failures. Now we don't. NOTE: This change required that the rest of the CI shell scripts and jenkinsfiles be updates to the same level as certified/16.3. Change-Id: I0b3254c08a2479f3d39151690350cce5ce5ad766 --- tests/CI/buildAsterisk.sh | 185 ++++++++++++++++++------- tests/CI/gateTestGroups.json | 9 ++ tests/CI/gates.jenkinsfile | 109 ++++++++++----- tests/CI/installAsterisk.sh | 5 + tests/CI/periodic-dailyTestGroups.json | 8 +- tests/CI/periodics-daily.jenkinsfile | 61 ++++++-- tests/CI/ref_debug.jenkinsfile | 32 +++-- tests/CI/runTestsuite.sh | 16 ++- tests/CI/runUnittests.sh | 100 ++++++++++--- tests/CI/setupRealtime.sh | 162 +++++++++++++++------- tests/CI/teardownRealtime.sh | 8 +- tests/CI/unittests.jenkinsfile | 93 ++++++++----- 12 files changed, 575 insertions(+), 213 deletions(-) diff --git a/tests/CI/buildAsterisk.sh b/tests/CI/buildAsterisk.sh index 9840d859e5..2e947910d7 100755 --- a/tests/CI/buildAsterisk.sh +++ b/tests/CI/buildAsterisk.sh @@ -1,9 +1,21 @@ #!/usr/bin/env bash CIDIR=$(dirname $(readlink -fn $0)) +COVERAGE=0 REF_DEBUG=0 +DISABLE_BINARY_MODULES=0 +NO_CONFIGURE=0 +NO_MENUSELECT=0 +NO_MAKE=0 +NO_ALEMBIC=0 source $CIDIR/ci.functions +set -e + +if [ -z $BRANCH_NAME ]; then + BRANCH_NAME=$(git config -f .gitreview --get gerrit.defaultbranch) +fi + gen_cats() { set +x action=$1 @@ -26,10 +38,27 @@ gen_mods() { done } -[ x"$OUTPUT_DIR" != x ] && mkdir -p "$OUTPUT_DIR" 2&> /dev/null +run_alembic() { + pushd contrib/ast-db-manage >/dev/null + runner alembic $@ + RC=$? + popd > /dev/null + return $RC +} + +[ x"$OUTPUT_DIR" != x ] && mkdir -p "$OUTPUT_DIR" 2> /dev/null + +if [ -z $TESTED_ONLY ]; then + # Skip building untested modules by default if coverage is enabled. + TESTED_ONLY=$COVERAGE +fi + +if [ -z $LCOV_DIR ]; then + LCOV_DIR="${OUTPUT_DIR:+${OUTPUT_DIR}/}lcov" +fi if [ x"$CACHE_DIR" != x ] ; then - mkdir -p "$CACHE_DIR/sounds $CACHE_DIR/externals" 2&> /dev/null + mkdir -p $CACHE_DIR/sounds $CACHE_DIR/externals 2> /dev/null fi if [ ${CCACHE_DISABLE:-0} -ne 1 ] ; then @@ -58,76 +87,134 @@ runner ccache -s runner ulimit -a MAKE=`which make` +PKGCONFIG=`which pkg-config` [ -d /usr/lib64 ] && _libdir=/usr/lib64 common_config_args="--prefix=/usr ${_libdir:+--libdir=${_libdir}} --sysconfdir=/etc --with-pjproject-bundled" +$PKGCONFIG 'jansson >= 2.11' || common_config_args+=" --with-jansson-bundled" common_config_args+=" ${CACHE_DIR:+--with-sounds-cache=${CACHE_DIR}/sounds --with-externals-cache=${CACHE_DIR}/externals}" common_config_args+=" --enable-dev-mode" +if [ $COVERAGE -eq 1 ] ; then + common_config_args+=" --enable-coverage" +fi +if [ "$BRANCH_NAME" == "master" -o $DISABLE_BINARY_MODULES -eq 1 ] ; then + common_config_args+=" --disable-binary-modules" +fi + export WGET_EXTRA_ARGS="--quiet" -runner ./configure ${common_config_args} > ${OUTPUT_DIR:+${OUTPUT_DIR}/}configure.txt +if [ $NO_CONFIGURE -eq 0 ] ; then + runner ./configure ${common_config_args} > ${OUTPUT_DIR:+${OUTPUT_DIR}/}configure.txt +fi -runner ${MAKE} menuselect.makeopts +if [ $NO_MENUSELECT -eq 0 ] ; then + runner ${MAKE} menuselect.makeopts -runner menuselect/menuselect `gen_mods enable DONT_OPTIMIZE BETTER_BACKTRACES MALLOC_DEBUG DO_CRASH TEST_FRAMEWORK` menuselect.makeopts -runner menuselect/menuselect `gen_mods disable COMPILE_DOUBLE BUILD_NATIVE` menuselect.makeopts -if [ $REF_DEBUG -eq 1 ] ; then - runner menuselect/menuselect --enable REF_DEBUG menuselect.makeopts -fi + runner menuselect/menuselect `gen_mods enable DONT_OPTIMIZE BETTER_BACKTRACES MALLOC_DEBUG DO_CRASH TEST_FRAMEWORK` menuselect.makeopts + runner menuselect/menuselect `gen_mods disable COMPILE_DOUBLE BUILD_NATIVE` menuselect.makeopts + if [ $REF_DEBUG -eq 1 ] ; then + runner menuselect/menuselect --enable REF_DEBUG menuselect.makeopts + fi -cat_enables="MENUSELECT_BRIDGES MENUSELECT_CEL MENUSELECT_CDR" -cat_enables+=" MENUSELECT_CHANNELS MENUSELECT_CODECS MENUSELECT_FORMATS MENUSELECT_FUNCS" -cat_enables+=" MENUSELECT_PBX MENUSELECT_RES MENUSELECT_UTILS MENUSELECT_TESTS" -runner menuselect/menuselect `gen_cats enable $cat_enables` menuselect.makeopts + cat_enables="MENUSELECT_TESTS" + mod_disabled="" -mod_disables="res_digium_phone chan_vpb" -[ "$BRANCH_NAME" == "master" ] && mod_disables+=" codec_opus codec_silk codec_g729a codec_siren7 codec_siren14" -runner menuselect/menuselect `gen_mods disable $mod_disables` menuselect.makeopts + if [[ ! "${BRANCH_NAME}" =~ ^certified ]] ; then + cat_enables+=" MENUSELECT_BRIDGES MENUSELECT_CEL MENUSELECT_CDR" + cat_enables+=" MENUSELECT_CHANNELS MENUSELECT_CODECS MENUSELECT_FORMATS MENUSELECT_FUNCS" + cat_enables+=" MENUSELECT_PBX MENUSELECT_RES MENUSELECT_UTILS" + else + mod_disables+=" test_utils" + fi -mod_enables="app_voicemail app_directory FILE_STORAGE" -mod_enables+=" res_mwi_external res_ari_mailboxes res_mwi_external_ami res_stasis_mailbox" -mod_enables+=" CORE-SOUNDS-EN-GSM MOH-OPSOUND-GSM EXTRA-SOUNDS-EN-GSM" -runner menuselect/menuselect `gen_mods enable $mod_enables` menuselect.makeopts + runner menuselect/menuselect `gen_cats enable $cat_enables` menuselect.makeopts + + mod_disables+=" res_digium_phone chan_vpb" + if [ $TESTED_ONLY -eq 1 ] ; then + # These modules are not tested at all. They are loaded but nothing is ever done + # with them, no testsuite tests depend on them. + mod_disables+=" app_adsiprog app_alarmreceiver app_celgenuserevent app_db app_dictate" + mod_disables+=" app_dumpchan app_externalivr app_festival app_getcpeid app_ices app_image" + mod_disables+=" app_jack app_milliwatt app_minivm app_morsecode app_mp3 app_nbscat app_privacy" + mod_disables+=" app_readexten app_sms app_speech_utils app_test app_url app_waitforring" + mod_disables+=" app_waitforsilence app_waituntil app_zapateller" + mod_disables+=" cdr_adaptive_odbc cdr_custom cdr_manager cdr_odbc cdr_pgsql cdr_radius" + mod_disables+=" cdr_syslog cdr_tds" + mod_disables+=" cel_odbc cel_pgsql cel_radius cel_sqlite3_custom cel_tds" + mod_disables+=" chan_alsa chan_console chan_mgcp chan_motif chan_oss chan_rtp chan_skinny chan_unistim" + mod_disables+=" func_frame_trace func_pitchshift func_speex func_volume func_dialgroup" + mod_disables+=" func_periodic_hook func_sprintf func_enum func_extstate func_sysinfo func_iconv" + mod_disables+=" func_callcompletion func_version func_rand func_sha1 func_module func_md5" + mod_disables+=" pbx_dundi pbx_loopback" + mod_disables+=" res_ael_share res_calendar res_config_ldap res_config_pgsql res_corosync" + mod_disables+=" res_http_post res_pktccops res_rtp_multicast res_snmp res_xmpp" + fi -runner ${MAKE} -j8 || runner ${MAKE} -j1 NOISY_BUILD=yes + runner menuselect/menuselect `gen_mods disable $mod_disables` menuselect.makeopts -ALEMBIC=$(which alembic 2>/dev/null || : ) -if [ x"$ALEMBIC" = x ] ; then - echo "Alembic not installed" - exit 1 + mod_enables="app_voicemail app_directory FILE_STORAGE" + mod_enables+=" res_mwi_external res_ari_mailboxes res_mwi_external_ami res_stasis_mailbox" + mod_enables+=" CORE-SOUNDS-EN-GSM MOH-OPSOUND-GSM EXTRA-SOUNDS-EN-GSM" + runner menuselect/menuselect `gen_mods enable $mod_enables` menuselect.makeopts fi -cd contrib/ast-db-manage -find -name *.pyc -delete -out=$(alembic -c config.ini.sample branches) -if [ "x$out" != "x" ] ; then - >&2 echo "Alembic branches were found for config" - >&2 echo $out - exit 1 -else - >&2 echo "Alembic for 'config' OK" +if [ $NO_MAKE -eq 0 ] ; then + runner ${MAKE} -j8 || runner ${MAKE} -j1 NOISY_BUILD=yes fi -out=$(alembic -c cdr.ini.sample branches) -if [ "x$out" != "x" ] ; then - >&2 echo "Alembic branches were found for cdr" - >&2 echo $out - exit 1 -else - >&2 echo "Alembic for 'cdr' OK" +runner rm -f ${LCOV_DIR}/*.info +if [ $COVERAGE -eq 1 ] ; then + runner mkdir -p ${LCOV_DIR} + + # Zero counter data + runner lcov --quiet --directory . --zerocounters + + # Branch coverage is not supported by --initial. Disable to suppresses a notice + # printed if it was enabled in lcovrc. + # This initial capture ensures any module which was built but never loaded is + # reported with 0% coverage for all sources. + runner lcov --quiet --directory . --no-external --capture --initial --rc lcov_branch_coverage=0 \ + --output-file ${LCOV_DIR}/initial.info fi -out=$(alembic -c voicemail.ini.sample branches) -if [ "x$out" != "x" ] ; then - >&2 echo "Alembic branches were found for voicemail" - >&2 echo $out - exit 1 -else - >&2 echo "Alembic for 'voicemail' OK" +if [ $NO_ALEMBIC -eq 0 ] ; then + ALEMBIC=$(which alembic 2>/dev/null || : ) + if [ x"$ALEMBIC" = x ] ; then + >&2 echo "Alembic not installed" + exit 1 + fi + + find contrib/ast-db-manage -name *.pyc -delete + out=$(run_alembic -c config.ini.sample branches) + if [ "x$out" != "x" ] ; then + >&2 echo "Alembic branches were found for config" + >&2 echo $out + exit 1 + fi + run_alembic -c config.ini.sample upgrade head --sql > "${OUTPUT_DIR:+${OUTPUT_DIR}/}alembic-config.sql" || exit 1 + echo "Alembic for 'config' OK" + + out=$(run_alembic -c cdr.ini.sample branches) + if [ "x$out" != "x" ] ; then + >&2 echo "Alembic branches were found for cdr" + >&2 echo $out + exit 1 + fi + run_alembic -c cdr.ini.sample upgrade head --sql > "${OUTPUT_DIR:+${OUTPUT_DIR}/}alembic-cdr.sql" || exit 1 + echo "Alembic for 'cdr' OK" + + out=$(run_alembic -c voicemail.ini.sample branches) + if [ "x$out" != "x" ] ; then + >&2 echo "Alembic branches were found for voicemail" + >&2 echo $out + exit 1 + fi + run_alembic -c voicemail.ini.sample upgrade head --sql > "${OUTPUT_DIR:+${OUTPUT_DIR}/}alembic-voicemail.sql" || exit 1 + echo "Alembic for 'voicemail' OK" fi if [ -f "doc/core-en_US.xml" ] ; then - ${MAKE} validate-docs || ${MAKE} NOISY_BUILD=yes validate-docs + runner ${MAKE} validate-docs || ${MAKE} NOISY_BUILD=yes validate-docs fi diff --git a/tests/CI/gateTestGroups.json b/tests/CI/gateTestGroups.json index 7c8b917fd7..d0488962ba 100644 --- a/tests/CI/gateTestGroups.json +++ b/tests/CI/gateTestGroups.json @@ -2,46 +2,55 @@ { "name": "ari1", "dir": "tests/CI/output/ari1", + "runTestsuiteOptions": "--test-timeout=180", "testcmd": "--test-regex=tests/rest_api/[Ca-d]" }, { "name": "ari2", "dir": "tests/CI/output/ari2", + "runTestsuiteOptions": "--test-timeout=180", "testcmd": "--test-regex=tests/rest_api/[e-z]" }, { "name": "pjs1", "dir": "tests/CI/output/pjsip1", + "runTestsuiteOptions": "--test-timeout=180", "testcmd": "--test-regex=tests/channels/pjsip/[a-f]" }, { "name": "pjs2", "dir": "tests/CI/output/pjsip2", + "runTestsuiteOptions": "--test-timeout=180", "testcmd": "--test-regex=tests/channels/pjsip/[g-r]" }, { "name": "pjs3", "dir": "tests/CI/output/pjsip3", + "runTestsuiteOptions": "--test-timeout=180", "testcmd": "--test-regex=tests/channels/pjsip/[s-z]" }, { "name": "sip1", "dir": "tests/CI/output/sip1", + "runTestsuiteOptions": "--test-timeout=240", "testcmd": "--test-regex=tests/channels/SIP/[Sa-r]" }, { "name": "sip2", "dir": "tests/CI/output/sip2", + "runTestsuiteOptions": "--test-timeout=240", "testcmd": "--test-regex=tests/channels/SIP/[s-z]" }, { "name": "iax ", "dir": "tests/CI/output/iax2_local", + "runTestsuiteOptions": "--test-timeout=180", "testcmd": " -t tests/channels/iax2 -t tests/channels/local" }, { "name": "mwi ", "dir": "tests/CI/output/extmwi", + "runTestsuiteOptions": "--test-timeout=180", "testcmd": "--test-regex=tests/channels/pjsip/.*mwi" } ] diff --git a/tests/CI/gates.jenkinsfile b/tests/CI/gates.jenkinsfile index 9dc7308bec..bc23781d6f 100644 --- a/tests/CI/gates.jenkinsfile +++ b/tests/CI/gates.jenkinsfile @@ -10,7 +10,19 @@ * we need to dynamically determine which docker image we're going to use and * you can't do that in a delcarative pipeline. */ +def timeoutTime = 60 +def timeoutUnits = 'MINUTES' +if (env.TIMEOUT_GATES) { + def _timeout = env.TIMEOUT_GATES.split() + timeoutTime = _timeout[0].toInteger() + timeoutUnits = _timeout[1] +} + pipeline { + options { + timestamps() + timeout(time: timeoutTime, unit: timeoutUnits) + } triggers { /* * This trigger will match either the "asterisk" or "Security-asterisk" @@ -62,10 +74,12 @@ pipeline { steps { /* Here's where we switch to scripted pipeline */ script { + manager.build.displayName = "${env.GERRIT_CHANGE_NUMBER}" + manager.createSummary("/plugin/workflow-job/images/48x48/pipelinejob.png").appendText("Docker Host: ${NODE_NAME}", false) + stage ("Checkout") { sh "sudo chown -R jenkins:users ." - env.GERRIT_PROJECT_URL = env.GERRIT_CHANGE_URL.replaceAll(/\/[0-9]+$/, "/${env.GERRIT_PROJECT}") - sh "printenv | sort" + env.GERRIT_PROJECT_URL = env.GIT_URL.replaceAll(/[^\/]+$/, env.GERRIT_PROJECT) /* * Jenkins has already automatically checked out the base branch @@ -76,33 +90,46 @@ pipeline { * * The Gerrit Trigger provides all the URLs and refspecs to * check out the change. + * + * We need to retrieve the jenkins2 gerrit https credentials + * in case this review is in a restricted project. */ - checkout scm: [$class: 'GitSCM', - branches: [[name: env.GERRIT_BRANCH ]], - extensions: [ - [$class: 'ScmName', name: 'gerrit-public'], - [$class: 'CleanBeforeCheckout'], - [$class: 'PreBuildMerge', options: [ - mergeRemote: 'gerrit-public', - fastForwardMode: 'NO_FF', - mergeStrategy: 'RECURSIVE', - mergeTarget: env.GERRIT_BRANCH]], - [$class: 'CloneOption', - honorRefspec: true, - noTags: true, - depth: 10, - shallow: true + withCredentials([usernamePassword(credentialsId: "${JENKINS_GERRIT_CREDS}", + passwordVariable: 'GERRIT_USER_PW', usernameVariable: 'GERRIT_USER_NAME')]) { + + sh "printenv | sort" + + checkout scm: [$class: 'GitSCM', + branches: [[name: env.GERRIT_BRANCH ]], + extensions: [ + [$class: 'ScmName', name: env.GERRIT_NAME], + [$class: 'CleanBeforeCheckout'], + [$class: 'PreBuildMerge', options: [ + mergeRemote: env.GERRIT_NAME, + fastForwardMode: 'NO_FF', + mergeStrategy: 'RECURSIVE', + mergeTarget: env.GERRIT_BRANCH]], + [$class: 'CloneOption', + honorRefspec: true, + noTags: true, + depth: 10, + shallow: true + ], + [$class: 'PruneStaleBranch'], + [$class: 'BuildChooserSetting', + buildChooser: [$class: 'GerritTriggerBuildChooser'] + ] ], - [$class: 'PruneStaleBranch'], - [$class: 'BuildChooserSetting', - buildChooser: [$class: 'GerritTriggerBuildChooser'] + userRemoteConfigs: [ + [ + credentialsId: env.JENKINS_GERRIT_CREDS, + name: env.GERRIT_NAME, + refspec: env.GERRIT_REFSPEC, + url: env.GERRIT_PROJECT_URL.replaceAll("http(s)?://", "http\$1://${GERRIT_USER_NAME}@") + ] ] - ], - userRemoteConfigs: [ - [name: env.GERRIT_NAME, refspec: env.GERRIT_REFSPEC, url: env.GERRIT_PROJECT_URL ] ] - ] - + } sh "sudo tests/CI/setupJenkinsEnvironment.sh" } @@ -110,11 +137,14 @@ pipeline { def r = currentBuild.startTimeInMillis % images.length def ri = images[(int)r] def randomImage = env.DOCKER_REGISTRY + "/" + ri - def dockerOptions = "--ulimit core=0 --ulimit nofile=10240 " + - " -v /srv/jenkins:/srv/jenkins:rw -v /srv/cache:/srv/cache:rw " + + /* FYI... Jenkins takes care of mouting the workspace for the container */ + def dockerOptions = "--privileged --ulimit core=0 --ulimit nofile=10240 " + + " --tmpfs /tmp:exec,size=1G -v /srv/jenkins:/srv/jenkins:rw -v /srv/cache:/srv/cache:rw " + " --entrypoint=''" def bt = env.BUILD_TAG.replaceAll(/[^a-zA-Z0-9_.-]/, '-') def outputdir = "tests/CI/output/Testsuite" + + manager.createSummary("/plugin/workflow-job/images/48x48/pipelinejob.png").appendText("Docker Image: ${randomImage}", false) def img = docker.image(randomImage) img.pull() @@ -122,7 +152,7 @@ pipeline { img.inside(dockerOptions + " --name ${bt}-build") { echo 'Building..' env.CCACHE_DIR = "/srv/cache/ccache" - sh "./tests/CI/buildAsterisk.sh --output-dir=${outputdir} --cache-dir=/srv/cache" + sh "./tests/CI/buildAsterisk.sh --branch-name=${BRANCH_NAME} --output-dir=${outputdir} --cache-dir=/srv/cache" archiveArtifacts allowEmptyArchive: true, defaultExcludes: false, fingerprint: false, artifacts: "${outputdir}/*" @@ -148,13 +178,15 @@ pipeline { img.inside("${dockerOptions} --name ${bt}-${groupName}") { lock("${JOB_NAME}.${NODE_NAME}.installer") { - sh 'sudo ./tests/CI/installAsterisk.sh --user-group=jenkins:users' + sh "sudo ./tests/CI/installAsterisk.sh --uninstall-all --branch-name=${BRANCH_NAME} --user-group=jenkins:users" } sh "sudo rm -rf ${groupDir} || : " - checkout scm: [$class: 'GitSCM', - branches: [[name: "${BRANCH_NAME}"]], + withCredentials([usernamePassword(credentialsId: "${JENKINS_GERRIT_CREDS}", + passwordVariable: 'GERRIT_USER_PW', usernameVariable: 'GERRIT_USER_NAME')]) { + checkout scm: [$class: 'GitSCM', + branches: [[name: "${BRANCH_NAME}"]], extensions: [ [$class: 'RelativeTargetDirectory', relativeTargetDir: groupDir], [$class: 'CloneOption', @@ -164,10 +196,17 @@ pipeline { shallow: true ], ], - userRemoteConfigs: [[name: env.GERRIT_NAME, url: testsuiteUrl]] + userRemoteConfigs: [ + [ + credentialsId: env.JENKINS_GERRIT_CREDS, + name: env.GERRIT_NAME, + url: testsuiteUrl.replaceAll("http(s)?://", "http\$1://${GERRIT_USER_NAME}@") + ] + ] ] + } - sh "sudo tests/CI/runTestsuite.sh --testsuite-dir='${groupDir}' --test-command='${groupTestcmd}'" + sh "sudo tests/CI/runTestsuite.sh --testsuite-dir='${groupDir}' --testsuite-command='${groupTestcmd}'" archiveArtifacts allowEmptyArchive: true, defaultExcludes: false, fingerprint: true, artifacts: "${groupDir}/asterisk-test-suite-report.xml, ${groupDir}/logs/**, ${groupDir}/core*.txt" @@ -189,8 +228,8 @@ pipeline { } post { cleanup { - sh "sudo make distclean 2&>/dev/null || : " - sh "sudo rm -rf tests/CI/output 2&>/dev/null || : " + sh "sudo make distclean >/dev/null 2>&1 || : " + sh "sudo rm -rf tests/CI/output >/dev/null 2>&1 || : " } /* * The Gerrit Trigger will automatically post the "Verified" results back diff --git a/tests/CI/installAsterisk.sh b/tests/CI/installAsterisk.sh index 74f5651f6f..080656674c 100755 --- a/tests/CI/installAsterisk.sh +++ b/tests/CI/installAsterisk.sh @@ -1,6 +1,8 @@ #!/usr/bin/env bash CIDIR=$(dirname $(readlink -fn $0)) +UNINSTALL=0 +UNINSTALL_ALL=0 source $CIDIR/ci.functions MAKE=`which make` @@ -10,6 +12,9 @@ if [ x"$DESTDIR" != x ] ; then fi destdir=${DESTDIR:+DESTDIR=$DESTDIR} +[ $UNINSTALL -gt 0 ] && ${MAKE} ${destdir} uninstall +[ $UNINSTALL_ALL -gt 0 ] && ${MAKE} ${destdir} uninstall-all + ${MAKE} ${destdir} install || ${MAKE} ${destdir} NOISY_BUILD=yes install || exit 1 ${MAKE} ${destdir} samples if [ x"$DESTDIR" != x ] ; then diff --git a/tests/CI/periodic-dailyTestGroups.json b/tests/CI/periodic-dailyTestGroups.json index 01f51d1169..7f0fd7ecfa 100644 --- a/tests/CI/periodic-dailyTestGroups.json +++ b/tests/CI/periodic-dailyTestGroups.json @@ -2,37 +2,43 @@ { "name": "ari ", "dir": "tests/CI/output/ari", + "runTestsuiteOptions": "--test-timeout=180", "testcmd": "-t tests/rest_api/" }, { "name": "pjs ", "dir": "tests/CI/output/pjsip", + "runTestsuiteOptions": "--test-timeout=180", "testcmd": "-t tests/channels/pjsip" }, { "name": "sip ", "dir": "tests/CI/output/sip", + "runTestsuiteOptions": "--test-timeout=240", "testcmd": "-t tests/channels/SIP" }, { "name": "iax ", "dir": "tests/CI/output/iax2_local", + "runTestsuiteOptions": "--test-timeout=180", "testcmd": " -t tests/channels/iax2 -t tests/channels/local" }, { "name": "apps", "dir": "tests/CI/output/agi-apps", + "runTestsuiteOptions": "--test-timeout=180", "testcmd": " -t tests/agi -t tests/apps -t blind-transfer-parkingtimeout" }, { "name": "othr", "dir": "tests/CI/output/other", + "runTestsuiteOptions": "--test-timeout=180", "testcmd": " -T tests/(apps|agi|blind-transfer-parkingtimeout|rest_api|channels|realtime|example|skeleton_test|remote-test)" }, { "name": "real", "dir": "tests/CI/output/realtime", - "runTestsuiteOptions": "--realtime", + "runTestsuiteOptions": "--test-timeout=180 --realtime --initialize-db --cleanup-db", "testcmd": " -t tests/channels/pjsip -G realtime-incompatible" } ] diff --git a/tests/CI/periodics-daily.jenkinsfile b/tests/CI/periodics-daily.jenkinsfile index 8f5365875c..ae762f8e82 100644 --- a/tests/CI/periodics-daily.jenkinsfile +++ b/tests/CI/periodics-daily.jenkinsfile @@ -10,11 +10,23 @@ * we need to dynamically determine which docker image we're going to use and * you can't do that in a delcarative pipeline. */ +def timeoutTime = 3 +def timeoutUnits = 'HOURS' +if (env.TIMEOUT_DAILIES) { + def _timeout = env.TIMEOUT_DAILIES.split() + timeoutTime = _timeout[0].toInteger() + timeoutUnits = _timeout[1] +} + pipeline { + options { + timestamps() + timeout(time: timeoutTime, unit: timeoutUnits) + } triggers { cron 'H H(0-4) * * *' } - + agent { /* All of the stages need to be performed on a docker host */ label "swdev-docker" @@ -25,8 +37,10 @@ pipeline { steps { /* Here's where we switch to scripted pipeline */ script { + manager.createSummary("/plugin/workflow-job/images/48x48/pipelinejob.png").appendText("Docker Host: ${NODE_NAME}", false) + stage ("Checkout") { - sh "sudo chown -R jenkins:users ." + sh "sudo chown -R jenkins:users ." sh "printenv | sort" sh "sudo tests/CI/setupJenkinsEnvironment.sh" } @@ -35,23 +49,46 @@ pipeline { def r = currentBuild.startTimeInMillis % images.length def ri = images[(int)r] def randomImage = env.DOCKER_REGISTRY + "/" + ri - def dockerOptions = "--ulimit core=0 --ulimit nofile=10240 " + - " -v /srv/jenkins:/srv/jenkins:rw -v /srv/cache:/srv/cache:rw " + + def dockerOptions = "--privileged --ulimit core=0 --ulimit nofile=10240 " + + " --tmpfs /tmp:exec,size=1G -v /srv/jenkins:/srv/jenkins:rw -v /srv/cache:/srv/cache:rw " + " --entrypoint=''" def bt = env.BUILD_TAG.replaceAll(/[^a-zA-Z0-9_.-]/, '-') def outputdir = "tests/CI/output/Testsuite" + + manager.createSummary("/plugin/workflow-job/images/48x48/pipelinejob.png").appendText("Docker Image: ${randomImage}", false) def img = docker.image(randomImage) img.pull() - stage ("Build") { - img.inside(dockerOptions + " --name ${bt}-build") { + img.inside(dockerOptions + " --name ${bt}-build") { + stage ("Build") { echo 'Building..' env.CCACHE_DIR = "/srv/cache/ccache" - sh "./tests/CI/buildAsterisk.sh --output-dir=${outputdir} --cache-dir=/srv/cache" + sh "./tests/CI/buildAsterisk.sh --branch-name=${BRANCH_NAME} --output-dir=${outputdir} --cache-dir=/srv/cache" archiveArtifacts allowEmptyArchive: true, defaultExcludes: false, fingerprint: false, artifacts: "${outputdir}/*" } + stage ("Docs") { + + sh "sudo ./tests/CI/installAsterisk.sh --branch-name=${BRANCH_NAME} --user-group=jenkins:users" + + def docUrl = env.GIT_URL.replaceAll(/\/[^\/]+$/, "/publish-docs") + checkout scm: [$class: 'GitSCM', + branches: [[name: "master"]], + extensions: [ + [$class: 'RelativeTargetDirectory', relativeTargetDir: "tests/CI/output/publish-docs"], + [$class: 'CloneOption', + noTags: true, + depth: 10, + honorRefspec: true, + shallow: true + ], + ], + userRemoteConfigs: [[url: docUrl]] + ] + + sh "./tests/CI/publishAsteriskDocs.sh --user-group=jenkins:users --branch-name=${BRANCH_NAME} --wiki-doc-branch-regex=\"${WIKI_DOC_BRANCH_REGEX}\"" + } } def testGroups = readJSON file: "tests/CI/periodic-dailyTestGroups.json" @@ -74,11 +111,11 @@ pipeline { img.inside("${dockerOptions} --name ${bt}-${groupName}") { lock("${JOB_NAME}.${NODE_NAME}.installer") { - sh 'sudo ./tests/CI/installAsterisk.sh --user-group=jenkins:users' + sh "sudo ./tests/CI/installAsterisk.sh --uninstall-all --branch-name=${BRANCH_NAME} --user-group=jenkins:users" } sh "sudo rm -rf ${groupDir} || : " - + checkout scm: [$class: 'GitSCM', branches: [[name: "${BRANCH_NAME}"]], extensions: [ @@ -93,7 +130,7 @@ pipeline { userRemoteConfigs: [[url: testsuiteUrl]] ] - sh "sudo tests/CI/runTestsuite.sh ${groupRunTestsuiteOptions} --testsuite-dir='${groupDir}' --test-command='${groupTestcmd}'" + sh "sudo tests/CI/runTestsuite.sh ${groupRunTestsuiteOptions} --testsuite-dir='${groupDir}' --testsuite-command='${groupTestcmd}'" archiveArtifacts allowEmptyArchive: true, defaultExcludes: false, fingerprint: true, artifacts: "${groupDir}/asterisk-test-suite-report.xml, ${groupDir}/logs/**, ${groupDir}/core*.txt" @@ -115,8 +152,8 @@ pipeline { } post { cleanup { - sh "sudo make distclean 2&>/dev/null || : " - sh "sudo rm -rf tests/CI/output 2&>/dev/null || : " + sh "sudo make distclean >/dev/null 2>&1 || : " + sh "sudo rm -rf tests/CI/output >/dev/null 2>&1 || : " } success { echo "Reporting ${currentBuild.currentResult} Passed" diff --git a/tests/CI/ref_debug.jenkinsfile b/tests/CI/ref_debug.jenkinsfile index d0c42eab4d..0e0f49c1bd 100644 --- a/tests/CI/ref_debug.jenkinsfile +++ b/tests/CI/ref_debug.jenkinsfile @@ -10,7 +10,19 @@ * we need to dynamically determine which docker image we're going to use and * you can't do that in a delcarative pipeline. */ +def timeoutTime = 24 +def timeoutUnits = 'HOURS' +if (env.TIMEOUT_REF_DEBUG) { + def _timeout = env.TIMEOUT_REF_DEBUG.split() + timeoutTime = _timeout[0].toInteger() + timeoutUnits = _timeout[1] +} + pipeline { + options { + timestamps() + timeout(time: timeoutTime, unit: timeoutUnits) + } triggers { cron 'H H(0-4) * * 0' } @@ -25,6 +37,8 @@ pipeline { steps { /* Here's where we switch to scripted pipeline */ script { + manager.createSummary("/plugin/workflow-job/images/48x48/pipelinejob.png").appendText("Docker Host: ${NODE_NAME}", false) + stage ("Checkout") { sh "sudo chown -R jenkins:users ." sh "printenv | sort" @@ -35,11 +49,13 @@ pipeline { def r = currentBuild.startTimeInMillis % images.length def ri = images[(int)r] def randomImage = env.DOCKER_REGISTRY + "/" + ri - def dockerOptions = "--ulimit core=0 --ulimit nofile=10240 " + - " -v /srv/jenkins:/srv/jenkins:rw -v /srv/cache:/srv/cache:rw " + + def dockerOptions = "--privileged --ulimit core=0 --ulimit nofile=10240 " + + " --tmpfs /tmp:exec,size=1G -v /srv/jenkins:/srv/jenkins:rw -v /srv/cache:/srv/cache:rw " + " --entrypoint=''" def bt = env.BUILD_TAG.replaceAll(/[^a-zA-Z0-9_.-]/, '-') def outputdir = "tests/CI/output/Testsuite" + + manager.createSummary("/plugin/workflow-job/images/48x48/pipelinejob.png").appendText("Docker Image: ${randomImage}", false) def img = docker.image(randomImage) img.pull() @@ -47,7 +63,7 @@ pipeline { img.inside(dockerOptions + " --name ${bt}-build") { echo 'Building..' env.CCACHE_DIR = "/srv/cache/ccache" - sh "./tests/CI/buildAsterisk.sh --ref-debug --output-dir=${outputdir} --cache-dir=/srv/cache" + sh "./tests/CI/buildAsterisk.sh --ref-debug --branch-name=${BRANCH_NAME} --output-dir=${outputdir} --cache-dir=/srv/cache" archiveArtifacts allowEmptyArchive: true, defaultExcludes: false, fingerprint: false, artifacts: "${outputdir}/*" @@ -65,7 +81,7 @@ pipeline { def groupName = testGroup.name def groupDir = testGroup.dir def groupTestcmd = testGroup.testcmd - def testsuiteUrl = env.GIT_URL.replaceAll(/\/[^\/]+$/, "/1testsuite") + def testsuiteUrl = env.GIT_URL.replaceAll(/\/[^\/]+$/, "/testsuite") parallelTasks[groupName] = { stage (groupName) { @@ -73,7 +89,7 @@ pipeline { img.inside("${dockerOptions} --name ${bt}-${groupName}") { lock("${JOB_NAME}.${NODE_NAME}.installer") { - sh 'sudo ./tests/CI/installAsterisk.sh --user-group=jenkins:users' + sh "sudo ./tests/CI/installAsterisk.sh --uninstall-all --branch-name=${BRANCH_NAME} --user-group=jenkins:users" } sh "sudo rm -rf ${groupDir} || : " @@ -92,7 +108,7 @@ pipeline { userRemoteConfigs: [[url: testsuiteUrl]] ] - sh "sudo tests/CI/runTestsuite.sh --testsuite-dir='${groupDir}' --test-command='${groupTestcmd}'" + sh "sudo tests/CI/runTestsuite.sh --testsuite-dir='${groupDir}' --testsuite-command='${groupTestcmd}'" archiveArtifacts allowEmptyArchive: true, defaultExcludes: false, fingerprint: true, artifacts: "${groupDir}/asterisk-test-suite-report.xml, ${groupDir}/logs/**, ${groupDir}/core*.txt" @@ -111,8 +127,8 @@ pipeline { } post { cleanup { - sh "sudo make distclean 2&>/dev/null || : " - sh "sudo rm -rf tests/CI/output 2&>/dev/null || : " + sh "sudo make distclean >/dev/null 2>&1 || : " + sh "sudo rm -rf tests/CI/output >/dev/null 2>&1 || : " } success { echo "Reporting ${currentBuild.currentResult} Passed" diff --git a/tests/CI/runTestsuite.sh b/tests/CI/runTestsuite.sh index 4ca63691f2..466991a44c 100755 --- a/tests/CI/runTestsuite.sh +++ b/tests/CI/runTestsuite.sh @@ -1,23 +1,29 @@ #!/usr/bin/env bash CIDIR=$(dirname $(readlink -fn $0)) REALTIME=0 +TEST_TIMEOUT=600 source $CIDIR/ci.functions ASTETCDIR=$DESTDIR/etc/asterisk +if [ x"$WORK_DIR" != x ] ; then + export AST_WORK_DIR="$(readlink -f $WORK_DIR)" + mkdir -p "$AST_WORK_DIR" +fi + pushd $TESTSUITE_DIR ./cleanup-test-remnants.sh if [ $REALTIME -eq 1 ] ; then - $CIDIR/setupRealtime.sh + $CIDIR/setupRealtime.sh --initialize-db=${INITIALIZE_DB:?0} fi export PYTHONPATH=./lib/python/ -echo "Running tests ${TEST_COMMAND}" -./runtests.py --cleanup ${TEST_COMMAND} | contrib/scripts/pretty_print --no-color --no-timer --term-width=120 --show-errors || : +echo "Running tests ${TESTSUITE_COMMAND} ${AST_WORK_DIR:+with work directory ${AST_WORK_DIR}}" +./runtests.py --cleanup --timeout=${TEST_TIMEOUT} ${TESTSUITE_COMMAND} | contrib/scripts/pretty_print --no-color --no-timer --term-width=120 --show-errors || : if [ $REALTIME -eq 1 ] ; then - $CIDIR/teardownRealtime.sh + $CIDIR/teardownRealtime.sh --cleanup-db=${CLEANUP_DB:?0} fi if [ -f core* ] ; then @@ -26,4 +32,4 @@ if [ -f core* ] ; then exit 1 fi -popd \ No newline at end of file +popd diff --git a/tests/CI/runUnittests.sh b/tests/CI/runUnittests.sh index 0ad5f49533..e2d7e45a7e 100755 --- a/tests/CI/runUnittests.sh +++ b/tests/CI/runUnittests.sh @@ -1,9 +1,69 @@ #!/usr/bin/env bash CIDIR=$(dirname $(readlink -fn $0)) +NO_EXPECT=0 source $CIDIR/ci.functions ASTETCDIR=$DESTDIR/etc/asterisk -echo "full => notice,warning,error,debug,verbose" > "$ASTETCDIR/logger.conf" +asterisk_corefile_glob() { + local pattern=$(/sbin/sysctl -n kernel.core_pattern) + + # If core_pattern is a pipe there isn't much we can do + if [[ ${pattern:0:1} == "|" ]] ; then + echo "core*" + else + echo "${pattern%%%*}*" + fi +} + +run_tests_expect() { +$EXPECT <<-EOF + spawn sudo $ASTERISK ${USER_GROUP:+-U ${USER_GROUP%%:*} -G ${USER_GROUP##*:}} -fcng -C $CONFFILE + match_max 512 + set timeout 600 + expect -notransfer "Asterisk Ready." + send "core show settings\r" + expect -notransfer "CLI>" + send "${UNITTEST_COMMAND:-test execute all}\r" + expect -notransfer -ex "Test(s) Executed" + expect -notransfer "CLI>" + send "test show results failed\r" + expect -notransfer "CLI>" + send "test generate results xml ${OUTPUTFILE}\r" + expect -notransfer "CLI>" + send "core stop now\r" + expect -notransfer "Executing last minute cleanups" + wait +EOF +} + +run_tests_socket() { + sudo $ASTERISK ${USER_GROUP:+-U ${USER_GROUP%%:*} -G ${USER_GROUP##*:}} -gn -C $CONFFILE + for n in {1..5} ; do + sleep 3 + $ASTERISK -rx "core waitfullybooted" -C $CONFFILE && break + done + sleep 1 + $ASTERISK -rx "core show settings" -C $CONFFILE + $ASTERISK -rx "${UNITTEST_COMMAND:-test execute all}" -C $CONFFILE + $ASTERISK -rx "test show results failed" -C $CONFFILE + $ASTERISK -rx "test generate results xml $OUTPUTFILE" -C $CONFFILE + $ASTERISK -rx "core stop now" -C $CONFFILE +} + +# If DESTDIR is used to install and run asterisk from non standard locations, +# the directory entries in asterisk.conf need to be munged to prepend DESTDIR. +ALTERED=$(head -10 ../tmp/DESTDIR/etc/asterisk/asterisk.conf | grep -q "DESTDIR" && echo yes) +if [ x"$ALTERED" = x ] ; then + # In the section that starts with [directories and ends with a blank line, + # replace "=> " with "=> ${DESTDIR}" + sed -i -r -e "/^\[directories/,/^$/ s@=>\s+@=> ${DESTDIR}@" "$ASTETCDIR/asterisk.conf" +fi + +cat <<-EOF > "$ASTETCDIR/logger.conf" + [logfiles] + full => notice,warning,error,debug,verbose + console => notice,warning,error +EOF echo "[default]" > "$ASTETCDIR/extensions.conf" @@ -23,7 +83,7 @@ cat <<-EOF > "$ASTETCDIR/http.conf" [general] enabled=yes bindaddr=127.0.0.1 - port=8088 + bindport=8088 EOF cat <<-EOF > "$ASTETCDIR/modules.conf" @@ -44,6 +104,7 @@ ASTERISK="$DESTDIR/usr/sbin/asterisk" CONFFILE=$ASTETCDIR/asterisk.conf OUTPUTDIR=${OUTPUT_DIR:-tests/CI/output/} OUTPUTFILE=${OUTPUT_XML:-${OUTPUTDIR}/unittests-results.xml} +EXPECT="$(which expect 2>/dev/null || : )" [ ! -d ${OUTPUTDIR} ] && mkdir -p $OUTPUTDIR [ x"$USER_GROUP" != x ] && sudo chown -R $USER_GROUP $OUTPUTDIR @@ -51,23 +112,28 @@ OUTPUTFILE=${OUTPUT_XML:-${OUTPUTDIR}/unittests-results.xml} rm -rf $ASTETCDIR/extensions.{ael,lua} || : set -x -sudo $ASTERISK ${USER_GROUP:+-U ${USER_GROUP%%:*} -G ${USER_GROUP##*:}} -gn -C $CONFFILE -for n in `seq 1 5` ; do - sleep 3 - $ASTERISK -rx "core waitfullybooted" -C $CONFFILE && break -done -sleep 1 -$ASTERISK -rx "${TEST_COMMAND:-test execute all}" -C $CONFFILE -$ASTERISK -rx "test show results failed" -C $CONFFILE -$ASTERISK -rx "test generate results xml $OUTPUTFILE" -C $CONFFILE -$ASTERISK -rx "core stop now" -C $CONFFILE +if [ x"$EXPECT" != x -a $NO_EXPECT -eq 0 ] ; then + run_tests_expect +else + run_tests_socket +fi + +# Cleanup "just in case" +sudo killall -qe -ABRT $ASTERISK runner rsync -vaH $DESTDIR/var/log/asterisk/. $OUTPUTDIR set +x [ x"$USER_GROUP" != x ] && sudo chown -R $USER_GROUP $OUTPUTDIR -if [ -f core* ] ; then - echo "*** Found a core file after running unit tests ***" - $DESTDIR/var/lib/asterisk/scripts/ast_coredumper --no-default-search core* - exit 1 -fi + +for core in $(asterisk_corefile_glob) +do + if [ -f $core ] + then + echo "*** Found a core file ($core) after running unit tests ***" + set -x + sudo OUTPUTDIR=$OUTPUTDIR $DESTDIR/var/lib/asterisk/scripts/ast_coredumper --no-default-search $core + fi +done + +exit 0 diff --git a/tests/CI/setupRealtime.sh b/tests/CI/setupRealtime.sh index f599d335e0..49ffb8b89f 100755 --- a/tests/CI/setupRealtime.sh +++ b/tests/CI/setupRealtime.sh @@ -1,9 +1,114 @@ #!/usr/bin/env bash CIDIR=$(dirname $(readlink -fn $0)) +INITIALIZE_DB=0 source $CIDIR/ci.functions +ASTTOP=$(readlink -fn $CIDIR/../../) set -e +POSTGRES_PID=`pidof postgres || : ` + +if [ -z "$POSTGRES_PID" ] ; then + if [ -x /usr/local/bin/postgresql-start ] ; then + /usr/local/bin/postgresql-start + fi +fi + +POSTGRES_PID=`pidof postgres || : ` +if [ -z "$POSTGRES_PID" ] ; then + echo "Postgres isn't running. It must be started manually before this test can continue." + exit 1 +fi + +if [ $INITIALIZE_DB -gt 0 ] ; then + echo "(re)Initializing Database" + + sudo -u postgres dropdb -e asterisk_test >/dev/null 2>&1 || : + sudo -u postgres dropuser -e asterisk_test >/dev/null 2>&1 || : + sudo -u postgres createuser --username=postgres -RDIElS asterisk_test + sudo -u postgres createdb --username=postgres -E UTF-8 -O asterisk_test asterisk_test + + echo "Configuring ODBC" + + sudo odbcinst -u -d -n "PostgreSQL-Asterisk-Test" + + sudo odbcinst -i -d -n "PostgreSQL-Asterisk-Test" -f /dev/stdin <<-EOF + [PostgreSQL-Asterisk-Test] + Description=PostgreSQL ODBC driver (Unicode version) + Driver=psqlodbcw.so + Setup=libodbcpsqlS.so + Debug=0 + CommLog=1 + UsageCount=1 + EOF + + sudo odbcinst -u -s -l -n asterisk-connector-test + sudo odbcinst -i -s -l -n asterisk-connector-test -f /dev/stdin <<-EOF + [asterisk-connector-test] + Description = PostgreSQL connection to 'asterisk' database + Driver = PostgreSQL-Asterisk-Test + Database = asterisk_test + Servername = 127.0.0.1 + UserName = asterisk_test + Port = 5432 + Protocol = 9.1 + ReadOnly = No + RowVersioning = No + ShowSystemTables = No + ShowOldColumn = No + FakeOldIndex = No + ConnSettings = + EOF +fi + +cat >/tmp/config.ini <<-EOF + [alembic] + script_location = config + sqlalchemy.url = postgresql://asterisk_test@localhost/asterisk_test + + [loggers] + keys = root,sqlalchemy,alembic + + [handlers] + keys = console + + [formatters] + keys = generic + + [logger_root] + level = WARN + handlers = console + qualname = + + [logger_sqlalchemy] + level = WARN + handlers = + qualname = sqlalchemy.engine + + [logger_alembic] + level = INFO + handlers = + qualname = alembic + + [handler_console] + class = StreamHandler + args = (sys.stderr,) + level = NOTSET + formatter = generic + + [formatter_generic] + format = %(levelname)-5.5s [%(name)s] %(message)s + datefmt = %H:%M:%S +EOF + +pushd $ASTTOP/contrib/ast-db-manage + +psql --username=asterisk_test --host=localhost --db=asterisk_test --command='DROP OWNED BY asterisk_test CASCADE' +alembic -c /tmp/config.ini upgrade head +rm -rf /tmp/config.ini || : + +popd + cp test-config.yaml test-config.orig.yaml cat >test-config.yaml <<-EOF @@ -65,59 +170,10 @@ cat >test-config.yaml <<-EOF config-section: realtime-config realtime-config: - username: "asterisk" + username: "asterisk_test" + password: "asterisk_test" host: "localhost" - db: "asterisk" - dsn: "asterisk-connector" -EOF - -ASTTOP=$(readlink -fn $CIDIR/../../) - -cat >/tmp/config.ini <<-EOF - [alembic] - script_location = config - sqlalchemy.url = postgresql://asterisk@localhost/asterisk - - [loggers] - keys = root,sqlalchemy,alembic - - [handlers] - keys = console - - [formatters] - keys = generic - - [logger_root] - level = WARN - handlers = console - qualname = - - [logger_sqlalchemy] - level = WARN - handlers = - qualname = sqlalchemy.engine - - [logger_alembic] - level = INFO - handlers = - qualname = alembic - - [handler_console] - class = StreamHandler - args = (sys.stderr,) - level = NOTSET - formatter = generic - - [formatter_generic] - format = %(levelname)-5.5s [%(name)s] %(message)s - datefmt = %H:%M:%S + db: "asterisk_test" + dsn: "asterisk-connector-test" EOF -pushd $ASTTOP/contrib/ast-db-manage -if [ -x /usr/local/bin/postgresql-start ] ; then - /usr/local/bin/postgresql-start -fi -psql --username=asterisk --host=localhost --db=asterisk --command='DROP OWNED BY asterisk CASCADE' -alembic -c /tmp/config.ini upgrade head -rm -rf /tmp/config.ini || : -popd diff --git a/tests/CI/teardownRealtime.sh b/tests/CI/teardownRealtime.sh index 11146990ff..868770658f 100755 --- a/tests/CI/teardownRealtime.sh +++ b/tests/CI/teardownRealtime.sh @@ -1,6 +1,12 @@ #!/usr/bin/env bash CIDIR=$(dirname $(readlink -fn $0)) +CLEANUP_DB=0 source $CIDIR/ci.functions cp test-config.orig.yaml test-config.yaml -psql --username=asterisk --host=localhost --db=asterisk --command='DROP OWNED BY asterisk CASCADE' +if [ $CLEANUP_DB -gt 0 ] ; then + sudo -u postgres dropdb -e asterisk_test >/dev/null 2>&1 || : + sudo -u postgres dropuser -e asterisk_test >/dev/null 2>&1 || : + sudo odbcinst -u -d -n "PostgreSQL-Asterisk-Test" + sudo odbcinst -u -s -l -n "asterisk-connector-test" +fi diff --git a/tests/CI/unittests.jenkinsfile b/tests/CI/unittests.jenkinsfile index 767ff9447c..3961cf538b 100644 --- a/tests/CI/unittests.jenkinsfile +++ b/tests/CI/unittests.jenkinsfile @@ -10,7 +10,19 @@ * we need to dynamically determine which docker image we're going to use and * you can't do that in a delcarative pipeline. */ +def timeoutTime = 30 +def timeoutUnits = 'MINUTES' +if (env.TIMEOUT_UNITTESTS) { + def _timeout = env.TIMEOUT_UNITTESTS.split() + timeoutTime = _timeout[0].toInteger() + timeoutUnits = _timeout[1] +} + pipeline { + options { + timestamps() + timeout(time: timeoutTime, unit: timeoutUnits) + } triggers { /* * This trigger will match either the "asterisk" or "Security-asterisk" @@ -34,7 +46,7 @@ pipeline { triggerOnEvents: [ commentAddedContains('^recheck$'), patchsetCreated(excludeDrafts: false, - excludeNoCodeChange: true, + excludeNoCodeChange: false, excludeTrivialRebase: false), draftPublished() ], @@ -63,10 +75,12 @@ pipeline { } steps { script { + manager.build.displayName = "${env.GERRIT_CHANGE_NUMBER}" + manager.createSummary("/plugin/workflow-job/images/48x48/pipelinejob.png").appendText("Docker Host: ${NODE_NAME}", false) + stage ("Checkout") { sh "sudo chown -R jenkins:users ." - env.GERRIT_PROJECT_URL = env.GERRIT_CHANGE_URL.replaceAll(/\/[0-9]+$/, "/${env.GERRIT_PROJECT}") - sh "printenv | sort" + env.GERRIT_PROJECT_URL = env.GIT_URL.replaceAll(/[^\/]+$/, env.GERRIT_PROJECT) /* * Jenkins has already automatically checked out the base branch @@ -77,32 +91,46 @@ pipeline { * * The Gerrit Trigger provides all the URLs and refspecs to * check out the change. + * + * We need to retrieve the jenkins2 gerrit https credentials + * in case this review is in a restricted project. */ - checkout scm: [$class: 'GitSCM', - branches: [[name: env.GERRIT_BRANCH ]], - extensions: [ - [$class: 'ScmName', name: 'gerrit-public'], - [$class: 'CleanBeforeCheckout'], - [$class: 'PreBuildMerge', options: [ - mergeRemote: 'gerrit-public', - fastForwardMode: 'NO_FF', - mergeStrategy: 'RECURSIVE', - mergeTarget: env.GERRIT_BRANCH]], - [$class: 'CloneOption', - honorRefspec: true, - noTags: true, - depth: 10, - shallow: true + withCredentials([usernamePassword(credentialsId: "${JENKINS_GERRIT_CREDS}", + passwordVariable: 'GERRIT_USER_PW', usernameVariable: 'GERRIT_USER_NAME')]) { + + sh "printenv | sort" + + checkout scm: [$class: 'GitSCM', + branches: [[name: env.GERRIT_BRANCH ]], + extensions: [ + [$class: 'ScmName', name: env.GERRIT_NAME], + [$class: 'CleanBeforeCheckout'], + [$class: 'PreBuildMerge', options: [ + mergeRemote: env.GERRIT_NAME, + fastForwardMode: 'NO_FF', + mergeStrategy: 'RECURSIVE', + mergeTarget: env.GERRIT_BRANCH]], + [$class: 'CloneOption', + honorRefspec: true, + noTags: true, + depth: 10, + shallow: true + ], + [$class: 'PruneStaleBranch'], + [$class: 'BuildChooserSetting', + buildChooser: [$class: 'GerritTriggerBuildChooser'] + ] ], - [$class: 'PruneStaleBranch'], - [$class: 'BuildChooserSetting', - buildChooser: [$class: 'GerritTriggerBuildChooser'] + userRemoteConfigs: [ + [ + credentialsId: env.JENKINS_GERRIT_CREDS, + name: env.GERRIT_NAME, + refspec: env.GERRIT_REFSPEC, + url: env.GERRIT_PROJECT_URL.replaceAll("http(s)?://", "http\$1://${GERRIT_USER_NAME}@") + ] ] - ], - userRemoteConfigs: [ - [name: env.GERRIT_NAME, refspec: env.GERRIT_REFSPEC, url: env.GERRIT_PROJECT_URL ] ] - ] + } sh "sudo tests/CI/setupJenkinsEnvironment.sh" } @@ -112,11 +140,12 @@ pipeline { def ri = images[(int)r] def randomImage = env.DOCKER_REGISTRY + "/" + ri; def bt = env.BUILD_TAG.replaceAll(/[^a-zA-Z0-9_.-]/, '-') - def dockerOptions = "--ulimit core=0 --ulimit nofile=10240 " + - " -v /srv/jenkins:/srv/jenkins:rw -v /srv/cache:/srv/cache:rw " + + def dockerOptions = "--privileged --ulimit core=0 --ulimit nofile=10240 " + + " --tmpfs /tmp:exec,size=1G -v /srv/jenkins:/srv/jenkins:rw -v /srv/cache:/srv/cache:rw " + " --entrypoint='' --name ${bt}-build" def outputdir = "tests/CI/output/UnitTests" + manager.createSummary("/plugin/workflow-job/images/48x48/pipelinejob.png").appendText("Docker Image: ${randomImage}", false) def img = docker.image(randomImage) img.pull() img.inside(dockerOptions) { @@ -124,7 +153,7 @@ pipeline { stage ('Build') { echo 'Building..' - sh "./tests/CI/buildAsterisk.sh --output-dir=${outputdir} --cache-dir=/srv/cache" + sh "./tests/CI/buildAsterisk.sh --branch-name=${BRANCH_NAME} --output-dir=${outputdir} --cache-dir=/srv/cache" archiveArtifacts allowEmptyArchive: true, defaultExcludes: false, fingerprint: false, artifacts: "${outputdir}/*" @@ -134,9 +163,9 @@ pipeline { def outputfile = "${outputdir}/unittests-results.xml" def testcmd = "test execute all" - sh 'sudo ./tests/CI/installAsterisk.sh --user-group=jenkins:users' + sh "sudo ./tests/CI/installAsterisk.sh --uninstall-all --branch-name=${BRANCH_NAME} --user-group=jenkins:users" - sh "tests/CI/runUnittests.sh --user-group=jenkins:users --output-dir='${outputdir}' --output-xml='${outputfile}' --test-command='${testcmd}'" + sh "tests/CI/runUnittests.sh --user-group=jenkins:users --output-dir='${outputdir}' --output-xml='${outputfile}' --unittest-command='${testcmd}'" archiveArtifacts allowEmptyArchive: true, defaultExcludes: false, fingerprint: true, artifacts: "${outputdir}/**" @@ -152,8 +181,8 @@ pipeline { } post { cleanup { - sh "sudo make distclean 2&>/dev/null || : " - sh "sudo rm -rf tests/CI/output 2&>/dev/null || : " + sh "sudo make distclean >/dev/null 2>&1 || : " + sh "sudo rm -rf tests/CI/output >/dev/null 2>&1 || : " } /* * The Gerrit Trigger will automatically post the "Verified" results back -- 2.47.2