Skip to content

Commit 5530189

Browse files
committed
Run the unit tests
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.
1 parent 765291a commit 5530189

File tree

5 files changed

+157
-110
lines changed

5 files changed

+157
-110
lines changed

.github/jobs/baseinstall.sh

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,22 @@
44

55
export version="$1"
66
db=${2:-install}
7-
phpversion="${3}"
7+
phpversion="${3:-8.1}"
8+
# If this script is called from unit-tests.sh, we use the test environment
9+
export APP_ENV="${4:-prod}"
10+
11+
# In the test environment, we need to use a different database
12+
[ "$APP_ENV" = "prod" ] && DATABASE_NAME=domjudge || DATABASE_NAME=domjudge_test
813

914
MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD:-root}
1015

1116
set -eux
1217

1318
if [ -z "$phpversion" ]; then
14-
PHPVERSION=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION."\n";')
19+
phpversion=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION."\n";')
1520
fi
1621

17-
show_phpinfo "$PHPVERSION"
22+
show_phpinfo "$phpversion"
1823

1924
section_start "Run composer"
2025
export APP_ENV="dev"
@@ -47,22 +52,24 @@ else
4752
--enable-judgehost-build=no | tee "$ARTIFACTS"/configure.txt
4853
make domserver
4954
make install-domserver
55+
rm -rf /opt/domjudge/domserver/webapp/public/doc
56+
cp -r doc /opt/domjudge/domserver/webapp/public/
57+
find /opt/domjudge/domserver -name DOMjudgelogo.pdf
5058
fi
51-
5259
section_end
5360

5461
section_start "SQL settings"
5562
cat > ~/.my.cnf <<EOF
5663
[client]
5764
host=sqlserver
5865
user=root
59-
password=root
66+
password=${MYSQL_ROOT_PASSWORD}
6067
EOF
6168
cat ~/.my.cnf
6269

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

6875
# Show some MySQL debugging
@@ -73,7 +80,7 @@ mysql_root "SELECT user,host FROM mysql.user"
7380
mysql_root "SET GLOBAL max_allowed_packet=1073741824"
7481
mysql_root "SHOW GLOBAL STATUS LIKE 'Connection_errors_%'"
7582
mysql_root "SHOW VARIABLES LIKE '%_timeout'"
76-
echo "unused:sqlserver:domjudge:domjudge:domjudge:3306" > /opt/domjudge/domserver/etc/dbpasswords.secret
83+
echo "unused:sqlserver:$DATABASE_NAME:domjudge:domjudge:3306" > /opt/domjudge/domserver/etc/dbpasswords.secret
7784
mysql_user "SELECT CURRENT_USER();"
7885
mysql_user "SELECT USER();"
7986
section_end
@@ -100,7 +107,7 @@ cp /proc/cmdline "$ARTIFACTS"/cmdline.txt
100107
section_end
101108

102109
section_start "Setup webserver"
103-
cp /opt/domjudge/domserver/etc/domjudge-fpm.conf /etc/php/"$PHPVERSION"/fpm/pool.d/domjudge.conf
110+
cp /opt/domjudge/domserver/etc/domjudge-fpm.conf /etc/php/"$phpversion"/fpm/pool.d/domjudge.conf
104111

105112
rm -f /etc/nginx/sites-enabled/*
106113
cp /opt/domjudge/domserver/etc/nginx-conf /etc/nginx/sites-enabled/domjudge
@@ -114,38 +121,41 @@ nginx -t
114121
section_end
115122

116123
section_start "Show webserver is up"
117-
for service in nginx php${PHPVERSION}-fpm; do
124+
for service in nginx php${phpversion}-fpm; do
118125
service "$service" restart
119126
service "$service" status
120127
done
121128
section_end
122129

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

129140
section_start "Setup user"
130141
# We're using the admin user in all possible roles
131-
mysql_root "DELETE FROM userrole WHERE userid=1;" domjudge
142+
mysql_root "DELETE FROM userrole WHERE userid=1;" $DATABASE_NAME
132143
if [ "$version" = "team" ]; then
133144
# Add team to admin user
134-
mysql_root "INSERT INTO userrole (userid, roleid) VALUES (1, 3);" domjudge
135-
mysql_root "UPDATE user SET teamid = 1 WHERE userid = 1;" domjudge
145+
mysql_root "INSERT INTO userrole (userid, roleid) VALUES (1, 3);" $DATABASE_NAME
146+
mysql_root "UPDATE user SET teamid = 1 WHERE userid = 1;" $DATABASE_NAME
136147
elif [ "$version" = "jury" ]; then
137148
# Add jury to admin user
138-
mysql_root "INSERT INTO userrole (userid, roleid) VALUES (1, 2);" domjudge
149+
mysql_root "INSERT INTO userrole (userid, roleid) VALUES (1, 2);" $DATABASE_NAME
139150
elif [ "$version" = "balloon" ]; then
140151
# Add balloon to admin user
141-
mysql_root "INSERT INTO userrole (userid, roleid) VALUES (1, 4);" domjudge
152+
mysql_root "INSERT INTO userrole (userid, roleid) VALUES (1, 4);" $DATABASE_NAME
142153
elif [ "$version" = "admin" ]; then
143154
# Add admin to admin user
144-
mysql_root "INSERT INTO userrole (userid, roleid) VALUES (1, 1);" domjudge
145-
elif [ "$version" = "all" ]; then
146-
mysql_root "INSERT INTO userrole (userid, roleid) VALUES (1, 1);" domjudge
147-
mysql_root "INSERT INTO userrole (userid, roleid) VALUES (1, 3);" domjudge
148-
mysql_root "UPDATE user SET teamid = 1 WHERE userid = 1;" domjudge
155+
mysql_root "INSERT INTO userrole (userid, roleid) VALUES (1, 1);" $DATABASE_NAME
156+
elif [ "$version" = "all" ] || [ "$version" = "unit" ]; then
157+
mysql_root "INSERT INTO userrole (userid, roleid) VALUES (1, 1);" $DATABASE_NAME
158+
mysql_root "INSERT INTO userrole (userid, roleid) VALUES (1, 3);" $DATABASE_NAME
159+
mysql_root "UPDATE user SET teamid = 1 WHERE userid = 1;" $DATABASE_NAME
149160
fi
150161
section_end
151-

.github/jobs/unit-tests.sh

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#!/bin/bash
2+
3+
. .github/jobs/ci_settings.sh
4+
5+
DIR="$PWD"
6+
7+
export version=$1
8+
unittest=$2
9+
[ "$version" = "8.1" ] && CODECOVERAGE=1 || CODECOVERAGE=0
10+
11+
# Set up
12+
export unit=1
13+
14+
# Add team to admin user
15+
echo "UPDATE user SET teamid = 1 WHERE userid = 1;" | mysql domjudge_test
16+
17+
# Copy the .env.test file, as this is normally not done during
18+
# installation and we need it.
19+
cp webapp/.env.test /opt/domjudge/domserver/webapp/
20+
21+
# We also need the composer.json for PHPunit to detect the correct directory.
22+
cp webapp/composer.json /opt/domjudge/domserver/webapp/
23+
24+
cd /opt/domjudge/domserver
25+
26+
# Run phpunit tests.
27+
pcov=""
28+
phpcov=""
29+
if [ "$CODECOVERAGE" -eq 1 ]; then
30+
phpcov="-dpcov.enabled=1 -dpcov.directory=webapp/src"
31+
pcov="--coverage-html=${DIR}/coverage-html --coverage-clover coverage.xml"
32+
fi
33+
set +e
34+
echo "unused:sqlserver:domjudge:domjudge:domjudge:3306" > /opt/domjudge/domserver/etc/dbpasswords.secret
35+
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
36+
UNITSUCCESS=$?
37+
38+
# Store the unit tests also in the root for the GHA
39+
cp $ARTIFACTS/unit-tests.xml $DIR/
40+
41+
# Make sure the log exists before copy
42+
touch ${DIR}/webapp/var/log/test.log
43+
cp ${DIR}/webapp/var/log/*.log "$ARTIFACTS"/
44+
45+
set -e
46+
CNT=0
47+
THRESHOLD=32
48+
if [ $CODECOVERAGE -eq 1 ]; then
49+
CNT=$(sed -n '/Generating code coverage report/,$p' "$ARTIFACTS"/phpunit.out | grep -v DoctrineTestBundle | grep -cv ^$)
50+
fi
51+
52+
if [ $UNITSUCCESS -ne 0 ] || [ $CNT -gt $THRESHOLD ]; then
53+
exit 1
54+
fi
55+
56+
if [ $CODECOVERAGE -eq 1 ]; then
57+
section_start "Upload code coverage"
58+
# Only upload when we got working unit-tests.
59+
set +u # Uses some variables which are not set
60+
# shellcheck disable=SC1090
61+
. $DIR/.github/jobs/uploadcodecov.sh &>> "$ARTIFACTS"/codecov.log
62+
section_end
63+
fi

.github/workflows/unit-tests.yml

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
name: Unit tests
2+
# We can speedup with: https://github.com/actions/cache
23
on:
34
merge_group:
45
pull_request:
@@ -16,3 +17,65 @@ jobs:
1617
- name: Detect changes to manually verify
1718
run: diff newcodecov .github/jobs/uploadcodecov.sh
1819

20+
unit-tests:
21+
runs-on: ubuntu-24.04
22+
timeout-minutes: 20
23+
container:
24+
image: domjudge/gitlabci:24.04
25+
services:
26+
sqlserver:
27+
image: mariadb
28+
ports:
29+
- 3306:3306
30+
env:
31+
MYSQL_ROOT_PASSWORD: root
32+
MYSQL_USER: domjudge
33+
MYSQL_PASSWORD: domjudge
34+
options: --health-cmd="healthcheck.sh --connect --innodb_initialized" --health-interval=10s --health-timeout=5s --health-retries=3
35+
strategy:
36+
matrix:
37+
PHPVERSION: [8.1, 8.4]
38+
TEST: [Unit, E2E]
39+
steps:
40+
- uses: actions/checkout@v4
41+
- name: info
42+
run: |
43+
cat /proc/cmdline && echo &&
44+
cat /proc/mounts && echo &&
45+
ls -al /sys/fs/cgroup && echo &&
46+
uname -a && echo &&
47+
stat -fc %T /sys/fs/cgroup && echo &&
48+
cat /proc/self/cgroup && echo &&
49+
cat /proc/cpuinfo
50+
- name: pstree
51+
run: pstree -p
52+
- name: Install DOMjudge
53+
run: .github/jobs/baseinstall.sh unit install ${{ matrix.PHPVERSION }} test
54+
- name: Check nginx
55+
run: curl -v https://localhost/domjudge/
56+
- name: Run the unit-tests
57+
run: .github/jobs/unit-tests.sh ${{ matrix.PHPVERSION }} ${{ matrix.TEST }}
58+
- name: Publish Test Results
59+
uses: EnricoMi/publish-unit-test-result-action@v2
60+
if: ${{ !cancelled() }}
61+
with:
62+
comment_mode: changes in failures
63+
check_name: unit-tests-${{ matrix.PHPVERSION }}-${{ matrix.TEST }}.xml
64+
files: unit-tests-${{ matrix.PHPVERSION }}-${{ matrix.TEST }}.xml
65+
- name: Get SQL logs
66+
run: docker logs "${{ job.services.sqlserver.id }}"
67+
- name: Collect docker logs on failure
68+
if: ${{ !cancelled() }}
69+
uses: jwalton/gh-docker-logs@v1
70+
with:
71+
dest: '/tmp/docker-logs'
72+
- name: Upload all logs/artifacts
73+
if: ${{ !cancelled() }}
74+
uses: actions/upload-artifact@v4
75+
with:
76+
name: Logs-${{ matrix.PHPVERSION }}-${{ matrix.TEST }}
77+
path: |
78+
/var/log/nginx
79+
/opt/domjudge/domserver/webapp/var/log/*.log
80+
/tmp/docker-logs
81+
/tmp/artifacts

gitlab/base.sh

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,6 @@ export APP_ENV="${1:-prod}"
1010

1111
lsb_release -a
1212

13-
cat > ~/.my.cnf <<EOF
14-
[client]
15-
host=sqlserver
16-
user=root
17-
password=${MYSQL_ROOT_PASSWORD}
18-
EOF
19-
cat ~/.my.cnf
20-
2113
# FIXME: This chicken-egg problem is annoying but let us bootstrap for now.
2214
echo "CREATE DATABASE IF NOT EXISTS \`${DATABASE_NAME}\` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" | mysql
2315
echo "CREATE USER 'domjudge'@'%' IDENTIFIED BY 'domjudge';" | mysql

gitlab/unit-tests.sh

Lines changed: 0 additions & 81 deletions
This file was deleted.

0 commit comments

Comments
 (0)