Skip to content

Commit

Permalink
Run the unit tests
Browse files Browse the repository at this point in the history
We'll need to play around with the unit test upload features
(https://github.com/EnricoMi/publish-unit-test-result-action#configuration)
what works best.

This is based on what we do for the integration test. Most shared code
is handled by baseinstall.sh.

We can now also install a database with a different name as the unit
tests use that locally. As side-effect we directly test this in CI.

The CI ran on GitLab before and needed extra steps to push the result to
GitHub. As everything is in GitHub Actions now we can remove those extra
steps.

(cherry picked from commit 5530189)
  • Loading branch information
vmcj committed Dec 9, 2024
1 parent e900c21 commit 9cb48fd
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 30 deletions.
86 changes: 64 additions & 22 deletions .github/jobs/baseinstall.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ alias section_start='trace_off ; section_start_internal '
alias section_end='trace_off ; section_end_internal '

export version="$1"
db=${2:-install}
phpversion="${3:-8.1}"
# If this script is called from unit-tests.sh, we use the test environment
export APP_ENV="${4:-prod}"

# In the test environment, we need to use a different database
[ "$APP_ENV" = "prod" ] && DATABASE_NAME=domjudge || DATABASE_NAME=domjudge_test

MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD:-root}

Expand All @@ -38,8 +45,11 @@ sudo apt install -y acl zip unzip nginx php php-fpm php-gd \
python3-yaml latexmk curl
section_end

PHPVERSION=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION."\n";')
export PHPVERSION
if [ -z "$phpversion" ]; then
phpversion=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION."\n";')
fi

show_phpinfo "$phpversion"

section_start "Install composer"
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
Expand All @@ -60,18 +70,41 @@ section_end

section_start "Install domserver"
make configure
./configure --with-baseurl='https://localhost/domjudge/' --enable-doc-build=no --prefix="/opt/domjudge"

make domserver
sudo make install-domserver
if [ "$version" = "all" ]; then
# Note that we use http instead of https here as python requests doesn't
# like our self-signed cert. We should fix this separately.
./configure \
--with-baseurl='http://localhost/domjudge/' \
--with-domjudge-user=domjudge \
--with-judgehost-chrootdir=/chroot/domjudge | tee "$ARTIFACTS"/configure.txt
make build-scripts domserver judgehost docs
make install-domserver install-judgehost install-docs
else
./configure \
--with-baseurl='https://localhost/domjudge/' \
--with-domjudge-user=root \
--enable-doc-build=no \
--enable-judgehost-build=no | tee "$ARTIFACTS"/configure.txt
make domserver
make install-domserver
rm -rf /opt/domjudge/domserver/webapp/public/doc
cp -r doc /opt/domjudge/domserver/webapp/public/
find /opt/domjudge/domserver -name DOMjudgelogo.pdf
fi
section_end

section_start "Explicit start mysql + install DB"
sudo /etc/init.d/mysql start
section_start "SQL settings"
cat > ~/.my.cnf <<EOF
[client]
host=sqlserver
user=root
password=${MYSQL_ROOT_PASSWORD}
EOF
cat ~/.my.cnf

mysql_root "CREATE DATABASE IF NOT EXISTS \`domjudge\` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
mysql_root "CREATE DATABASE IF NOT EXISTS \`$DATABASE_NAME\` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
mysql_root "CREATE USER IF NOT EXISTS \`domjudge\`@'%' IDENTIFIED BY 'domjudge';"
mysql_root "GRANT SELECT, INSERT, UPDATE, DELETE ON \`domjudge\`.* TO 'domjudge'@'%';"
mysql_root "GRANT SELECT, INSERT, UPDATE, DELETE ON \`$DATABASE_NAME\`.* TO 'domjudge'@'%';"
mysql_root "FLUSH PRIVILEGES;"

# Show some MySQL debugging
Expand All @@ -80,7 +113,9 @@ mysql_root "SELECT CURRENT_USER();"
mysql_root "SELECT USER();"
mysql_root "SELECT user,host FROM mysql.user"
mysql_root "SET GLOBAL max_allowed_packet=1073741824"
echo "unused:sqlserver:domjudge:domjudge:domjudge:3306" > /opt/domjudge/domserver/etc/dbpasswords.secret
mysql_root "SHOW GLOBAL STATUS LIKE 'Connection_errors_%'"
mysql_root "SHOW VARIABLES LIKE '%_timeout'"
echo "unused:sqlserver:$DATABASE_NAME:domjudge:domjudge:3306" > /opt/domjudge/domserver/etc/dbpasswords.secret
mysql_user "SELECT CURRENT_USER();"
mysql_user "SELECT USER();"
section_end
Expand All @@ -107,7 +142,7 @@ cp /proc/cmdline "$ARTIFACTS"/cmdline.txt
section_end

section_start "Setup webserver"
sudo cp /opt/domjudge/domserver/etc/domjudge-fpm.conf /etc/php/$PHPVERSION/fpm/pool.d/domjudge.conf
cp /opt/domjudge/domserver/etc/domjudge-fpm.conf /etc/php/"$phpversion"/fpm/pool.d/domjudge.conf

sudo rm -f /etc/nginx/sites-enabled/*
sudo cp /opt/domjudge/domserver/etc/nginx-conf /etc/nginx/sites-enabled/domjudge
Expand All @@ -121,34 +156,41 @@ sudo nginx -t
section_end

section_start "Show webserver is up"
for service in nginx php${PHPVERSION}-fpm; do
sudo systemctl restart $service
sudo systemctl status $service
for service in nginx php${phpversion}-fpm; do
service "$service" restart
service "$service" status
done
section_end

if [ "${db}" = "install" ]; then
section_start "Install the example data"
if [ "$version" = "unit" ]; then
# Make sure admin has no team associated so we will not insert submissions during unit tests.
mysql_root "UPDATE user SET teamid=null WHERE userid=1;" $DATABASE_NAME
fi
/opt/domjudge/domserver/bin/dj_setup_database -uroot -p${MYSQL_ROOT_PASSWORD} install-examples | tee -a "$ARTIFACTS/mysql.txt"
section_end
fi

section_start "Setup user"
# We're using the admin user in all possible roles
echo "DELETE FROM userrole WHERE userid=1;" | mysql -uroot -proot domjudge
mysql_root "DELETE FROM userrole WHERE userid=1;" $DATABASE_NAME
if [ "$version" = "team" ]; then
# Add team to admin user
echo "INSERT INTO userrole (userid, roleid) VALUES (1, 3);" | mysql -uroot -proot domjudge
echo "UPDATE user SET teamid = 1 WHERE userid = 1;" | mysql -uroot -proot domjudge
mysql_root "INSERT INTO userrole (userid, roleid) VALUES (1, 3);" $DATABASE_NAME
mysql_root "UPDATE user SET teamid = 1 WHERE userid = 1;" $DATABASE_NAME
elif [ "$version" = "jury" ]; then
# Add jury to admin user
echo "INSERT INTO userrole (userid, roleid) VALUES (1, 2);" | mysql -uroot -proot domjudge
mysql_root "INSERT INTO userrole (userid, roleid) VALUES (1, 2);" $DATABASE_NAME
elif [ "$version" = "balloon" ]; then
# Add balloon to admin user
echo "INSERT INTO userrole (userid, roleid) VALUES (1, 4);" | mysql -uroot -proot domjudge
mysql_root "INSERT INTO userrole (userid, roleid) VALUES (1, 4);" $DATABASE_NAME
elif [ "$version" = "admin" ]; then
# Add admin to admin user
echo "INSERT INTO userrole (userid, roleid) VALUES (1, 1);" | mysql -uroot -proot domjudge
mysql_root "INSERT INTO userrole (userid, roleid) VALUES (1, 1);" $DATABASE_NAME
elif [ "$version" = "all" ] || [ "$version" = "unit" ]; then
mysql_root "INSERT INTO userrole (userid, roleid) VALUES (1, 1);" $DATABASE_NAME
mysql_root "INSERT INTO userrole (userid, roleid) VALUES (1, 3);" $DATABASE_NAME
mysql_root "UPDATE user SET teamid = 1 WHERE userid = 1;" $DATABASE_NAME
fi
section_end

63 changes: 63 additions & 0 deletions .github/jobs/unit-tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#!/bin/bash

. .github/jobs/ci_settings.sh

DIR="$PWD"

export version=$1
unittest=$2
[ "$version" = "8.1" ] && CODECOVERAGE=1 || CODECOVERAGE=0

# Set up
export unit=1

# Add team to admin user
echo "UPDATE user SET teamid = 1 WHERE userid = 1;" | mysql domjudge_test

# Copy the .env.test file, as this is normally not done during
# installation and we need it.
cp webapp/.env.test /opt/domjudge/domserver/webapp/

# We also need the composer.json for PHPunit to detect the correct directory.
cp webapp/composer.json /opt/domjudge/domserver/webapp/

cd /opt/domjudge/domserver

# Run phpunit tests.
pcov=""
phpcov=""
if [ "$CODECOVERAGE" -eq 1 ]; then
phpcov="-dpcov.enabled=1 -dpcov.directory=webapp/src"
pcov="--coverage-html=${DIR}/coverage-html --coverage-clover coverage.xml"
fi
set +e
echo "unused:sqlserver:domjudge:domjudge:domjudge:3306" > /opt/domjudge/domserver/etc/dbpasswords.secret
php $phpcov webapp/bin/phpunit -c webapp/phpunit.xml.dist webapp/tests/$unittest --log-junit ${ARTIFACTS}/unit-tests.xml --colors=never $pcov > "$ARTIFACTS"/phpunit.out
UNITSUCCESS=$?

# Store the unit tests also in the root for the GHA
cp $ARTIFACTS/unit-tests.xml $DIR/

# Make sure the log exists before copy
touch ${DIR}/webapp/var/log/test.log
cp ${DIR}/webapp/var/log/*.log "$ARTIFACTS"/

set -e
CNT=0
THRESHOLD=32
if [ $CODECOVERAGE -eq 1 ]; then
CNT=$(sed -n '/Generating code coverage report/,$p' "$ARTIFACTS"/phpunit.out | grep -v DoctrineTestBundle | grep -cv ^$)
fi

if [ $UNITSUCCESS -ne 0 ] || [ $CNT -gt $THRESHOLD ]; then
exit 1
fi

if [ $CODECOVERAGE -eq 1 ]; then
section_start "Upload code coverage"
# Only upload when we got working unit-tests.
set +u # Uses some variables which are not set
# shellcheck disable=SC1090
. $DIR/.github/jobs/uploadcodecov.sh &>> "$ARTIFACTS"/codecov.log
section_end
fi
63 changes: 63 additions & 0 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
name: Unit tests
# We can speedup with: https://github.com/actions/cache
on:
push:
branches:
Expand All @@ -19,3 +20,65 @@ jobs:
- name: Detect changes to manually verify
run: diff newcodecov .github/jobs/uploadcodecov.sh

unit-tests:
runs-on: ubuntu-24.04
timeout-minutes: 20
container:
image: domjudge/gitlabci:24.04
services:
sqlserver:
image: mariadb
ports:
- 3306:3306
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_USER: domjudge
MYSQL_PASSWORD: domjudge
options: --health-cmd="healthcheck.sh --connect --innodb_initialized" --health-interval=10s --health-timeout=5s --health-retries=3
strategy:
matrix:
PHPVERSION: [8.1, 8.4]
TEST: [Unit, E2E]
steps:
- uses: actions/checkout@v4
- name: info
run: |
cat /proc/cmdline && echo &&
cat /proc/mounts && echo &&
ls -al /sys/fs/cgroup && echo &&
uname -a && echo &&
stat -fc %T /sys/fs/cgroup && echo &&
cat /proc/self/cgroup && echo &&
cat /proc/cpuinfo
- name: pstree
run: pstree -p
- name: Install DOMjudge
run: .github/jobs/baseinstall.sh unit install ${{ matrix.PHPVERSION }} test
- name: Check nginx
run: curl -v https://localhost/domjudge/
- name: Run the unit-tests
run: .github/jobs/unit-tests.sh ${{ matrix.PHPVERSION }} ${{ matrix.TEST }}
- name: Publish Test Results
uses: EnricoMi/publish-unit-test-result-action@v2
if: ${{ !cancelled() }}
with:
comment_mode: changes in failures
check_name: unit-tests-${{ matrix.PHPVERSION }}-${{ matrix.TEST }}.xml
files: unit-tests-${{ matrix.PHPVERSION }}-${{ matrix.TEST }}.xml
- name: Get SQL logs
run: docker logs "${{ job.services.sqlserver.id }}"
- name: Collect docker logs on failure
if: ${{ !cancelled() }}
uses: jwalton/gh-docker-logs@v1
with:
dest: '/tmp/docker-logs'
- name: Upload all logs/artifacts
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v4
with:
name: Logs-${{ matrix.PHPVERSION }}-${{ matrix.TEST }}
path: |
/var/log/nginx
/opt/domjudge/domserver/webapp/var/log/*.log
/tmp/docker-logs
/tmp/artifacts
8 changes: 0 additions & 8 deletions gitlab/base.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,6 @@

lsb_release -a

cat > ~/.my.cnf <<EOF
[client]
host=sqlserver
user=root
password=${MYSQL_ROOT_PASSWORD}
EOF
cat ~/.my.cnf

# FIXME: This chicken-egg problem is annoying but let us bootstrap for now.
echo "CREATE DATABASE IF NOT EXISTS \`domjudge\` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" | mysql
echo "CREATE USER 'domjudge'@'%' IDENTIFIED BY 'domjudge';" | mysql
Expand Down

0 comments on commit 9cb48fd

Please sign in to comment.