Skip to content

add logging to debug #91

add logging to debug

add logging to debug #91

################################################################################
# trigger CI
# DataSHIELD GHA test suite - dsBaseClient
# Replaces azure-pipelines.yml / opal_azure-pipelines.yml / armadillo_azure-pipelines.yml.
#
# Structure (all jobs below run in parallel except where "needs" says otherwise):
# r-checks - devtools::document()/check() sync checks. No backend needed.
# opal-dsbase (matrix: smk/arg/perf/misc) - dsBase suite against Opal,
# one category per job.
# opal-dsdanger - dsDanger suite against Opal (small, not sharded).
# opal-report - needs the two Opal jobs above; merges + publishes report.
# armadillo-dsbase (matrix: smk/arg/perf/misc) - dsBase suite against Armadillo.
# armadillo-dsdanger - dsDanger suite against Armadillo.
# armadillo-report - needs the two Armadillo jobs above; merges + publishes report.
#
# The dsBase suite (matching TEST_FILTER_DSBASE - same 292 files the Azure
# pipelines run) is split by matrix into 4 fixed categories - smk (116 files),
# arg (96), perf (51), and misc (the smaller categories: datachk, disc, expt,
# smk_expt, math, and the "_-" catch-all - 29 combined) - each with its own
# testthat filter substring, no file-list partitioning logic. Categories
# aren't evenly sized, so job durations differ, but a category can be added,
# removed, or temporarily skipped just by editing the matrix list.
#
# Each dsbase/dsdanger job spins up its OWN backend instance (isolated - no
# shared server state / concurrency risk between categories running at once).
#
# Opal runs via docker-compose (docker-compose_opal.yml).
# Armadillo runs as a plain `java -jar` process (not docker-compose): Armadillo
# self-manages its Rock container over the host Docker socket
# (docker-management-enabled: true / docker-run-in-container: false), which skips
# building/pulling the old custom armadillo_citest image. See
# molgenis-service-armadillo's application.template.yml for that flag pairing.
#
# Every job starts its backend as the very first step so it boots in the
# background while R dependencies install, instead of paying for both serially.
#
# As of Sept. 2025 the single-backend, dsBase-only, unsharded version of this
# took ~ 95 mins; the full (Opal+Armadillo, dsBase+dsDanger) unsharded run is
# well over an hour.
################################################################################
name: dsBaseClient tests' suite
on:
push:
workflow_dispatch:
schedule:
- cron: '0 0 * * 0' # Weekly
- cron: '0 1 * * *' # Nightly
permissions:
contents: read
env:
_r_check_system_clock_: 0
WORKFLOW_ID: ${{ github.run_id }}-${{ github.run_attempt }}
PROJECT_NAME: dsBaseClient
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
REPO_OWNER: ${{ github.repository_owner }}
R_KEEP_PKG_SOURCE: yes
GITHUB_TOKEN: ${{ github.token || 'placeholder-token' }}
# These should all be constant, except the two TEST_FILTER_* values. These can
# be used to test subsets of test files in the testthat directory. Options are
# like: '*' <- run all tests, '*_smk_*' <- run all the smoke tests.
TEST_FILTER_DSBASE: '_-|datachk-|smk-|arg-|disc-|perf-|smk_expt-|expt-|math-'
TEST_FILTER_DSDANGER: '__dgr-|datachk_dgr-|smk_dgr-|arg_dgr-|disc_dgr-|smk_expt_dgr-|expt_dgr-|math_dgr-'
jobs:
################################################################################
# Doc-sync / R CMD check - no backend needed, so this runs once, not per
# backend or per shard.
################################################################################
r-checks:
name: Package checks (doc sync, R CMD check)
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: r-lib/actions/setup-pandoc@v2
- uses: r-lib/actions/setup-r@v2
with:
r-version: release
http-user-agent: release
use-public-rspm: true
- name: Install system libraries
run: |
sudo apt-get update -qq
sudo apt-get install -qq libxml2-dev libcurl4-openssl-dev libssl-dev libgsl-dev libgit2-dev -y
sudo apt-get install -qq libharfbuzz-dev libfribidi-dev libmagick++-dev libudunits2-dev libuv1-dev -y
- uses: r-lib/actions/setup-r-dependencies@v2
with:
dependencies: 'c("Imports")'
extra-packages: |
any::rcmdcheck
cran::devtools
cran::usethis
needs: check
- name: Check manual updated
run: |
orig_sum=$(find man -type f | sort -u | xargs cat | md5sum)
R -q -e "devtools::document()"
new_sum=$(find man -type f | sort -u | xargs cat | md5sum)
if [ "$orig_sum" != "$new_sum" ]; then
echo "Your committed man/*.Rd files are out of sync with the R headers."
exit 1
fi
continue-on-error: true
- name: Devtools checks
run: |
R -q -e "devtools::check(args = c('--no-examples', '--no-tests'))" | tee azure-pipelines_check.Rout
grep --quiet "^0 errors" azure-pipelines_check.Rout && grep --quiet " 0 warnings" azure-pipelines_check.Rout && grep --quiet " 0 notes" azure-pipelines_check.Rout
continue-on-error: true
################################################################################
# Opal - dsBase suite, sharded 4 ways. Each shard is a fully isolated job
# with its own Opal instance.
################################################################################
opal-dsbase:
name: Opal dsBase tests (${{ matrix.category }})
runs-on: ubuntu-latest
timeout-minutes: 60
strategy:
fail-fast: false
# One matrix entry per test-file category, each with its own testthat
# filter substring - not evenly sized (smk/arg are much bigger than
# perf/misc), so job durations differ. Traded for the ability to add,
# remove, or temporarily skip a whole category by editing this list
# alone, with no shell-side partitioning logic to keep in sync.
matrix:
include:
- category: smk
filter: 'smk-'
- category: arg
filter: 'arg-'
- category: perf
filter: 'perf-'
- category: misc
filter: 'datachk-|disc-|expt-|smk_expt-|math-|_-'
env:
DS_DRIVER: OpalDriver
DSBASE_REF: v7.0-dev
steps:
- name: Checkout dsBaseClient
uses: actions/checkout@v4
with:
path: dsBaseClient
- name: Start Opal docker-compose
run: docker compose -f docker-compose_opal.yml up -d --build
working-directory: dsBaseClient
- name: Uninstall default MySQL
run: |
sudo service mysql stop || true
sudo apt-get update
sudo apt-get remove --purge mysql-client mysql-server mysql-common -y
sudo apt-get autoremove -y
sudo apt-get autoclean -y
sudo rm -rf /var/lib/mysql/
- uses: r-lib/actions/setup-pandoc@v2
- uses: r-lib/actions/setup-r@v2
with:
r-version: release
http-user-agent: release
use-public-rspm: true
- name: Install system libraries
run: |
sudo apt-get update -qq
sudo apt-get install -qq libxml2-dev libcurl4-openssl-dev libssl-dev libgsl-dev libgit2-dev -y
sudo apt-get install -qq libharfbuzz-dev libfribidi-dev libmagick++-dev libudunits2-dev libuv1-dev -y
- uses: r-lib/actions/setup-r-dependencies@v2
with:
dependencies: 'c("Imports")'
extra-packages: |
cran::devtools
cran::usethis
cran::covr
cran::fields
cran::meta
cran::metafor
cran::ggplot2
cran::gridExtra
cran::data.table
cran::DSI
cran::opalr
cran::DSOpal
cran::DSLite
cran::MolgenisAuth
cran::MolgenisArmadillo
cran::DSMolgenisArmadillo
cran::DescTools
cran::e1071
needs: check
- name: Install test datasets to Opal
run: |
sleep 60
R -q -f "obiba_opal-upload_testing_datasets.R"
working-directory: dsBaseClient/tests/testthat/data_files
- name: Install dsBase to Opal, set disclosure test options
run: |
R -q -e "library(opalr); opal <- opal.login(username = 'administrator', password = 'datashield_test&', url = 'http://localhost:8080/'); opal.put(opal, 'system', 'conf', 'general', '_rPackage'); opal.logout(opal)"
R -q -e "library(opalr); opal <- opal.login('administrator','datashield_test&', url='http://localhost:8080/'); dsadmin.install_github_package(opal, 'dsBase', username = 'datashield', ref = '${{ env.DSBASE_REF }}'); opal.logout(opal)"
sleep 60
expected_version=$(curl -sf "https://raw.githubusercontent.com/datashield/dsBase/${{ env.DSBASE_REF }}/DESCRIPTION" | sed -n 's/^Version: //p' | tr -d '\r')
if [ -z "$expected_version" ]; then
echo "Could not determine expected dsBase version from GitHub"
exit 1
fi
echo "Expected dsBase version: $expected_version"
R -q -e "library(opalr); opal <- opal.login('administrator', 'datashield_test&', url='http://localhost:8080/'); desc <- dsadmin.package_description(opal, 'dsBase'); opal.logout(opal); installed_version <- desc[['Version']]; cat('Installed dsBase version:', installed_version, '\n'); if (is.null(installed_version) || installed_version != '$expected_version') stop('dsBase version mismatch: expected $expected_version, found ', installed_version)"
R -q -e "library(opalr); opal <- opal.login('administrator', 'datashield_test&', url='http://localhost:8080/'); dsadmin.profile_init(opal, name = 'default', packages = c('dsBase', 'dsTidyverse', 'resourcer')); opal.logout(opal)"
R -q -e "library(opalr); opal <- opal.login('administrator', 'datashield_test&', url='http://localhost:8080/'); dsadmin.set_option(opal, 'default.datashield.privacyControlLevel', 'permissive'); opal.logout(opal)"
working-directory: dsBaseClient/tests/testthat/data_files
- name: Run dsBase tests with coverage & JUnit report
run: |
R -q -e "devtools::reload();"
R -q -e '
write.csv(
covr::coverage_to_list(
covr::package_coverage(
type = c("none"),
code = c('"'"'
output_file <- file("test_console_output_dsbase.txt");
sink(output_file);
sink(output_file, type = "message");
junit_rep <- testthat::JunitReporter$new(file = file.path(getwd(), "test_results_dsbase.xml"));
progress_rep <- testthat::ProgressReporter$new(max_failures = 999999);
multi_rep <- testthat::MultiReporter$new(reporters = list(progress_rep, junit_rep));
options("datashield.return_errors" = FALSE, "default_driver" = "${{ env.DS_DRIVER }}");
testthat::test_package("${{ env.PROJECT_NAME }}", filter = "${{ matrix.filter }}", reporter = multi_rep, stop_on_failure = FALSE)'"'"'
)
)
),
"coveragelist.csv"
)'
cat test_console_output_dsbase.txt
working-directory: dsBaseClient
- name: Upload shard results
uses: actions/upload-artifact@v4
with:
name: opal-dsbase-${{ matrix.category }}
path: |
dsBaseClient/test_results_dsbase.xml
dsBaseClient/test_console_output_dsbase.txt
dsBaseClient/coveragelist.csv
################################################################################
# Opal - dsDanger suite. Small (~15 files), so it stays a single job rather
# than sharding further.
################################################################################
opal-dsdanger:
name: Opal dsDanger tests
runs-on: ubuntu-latest
timeout-minutes: 60
env:
DS_DRIVER: OpalDriver
DSBASE_REF: v7.0-dev
DSDANGER_REF: '6.3.4'
steps:
- name: Checkout dsBaseClient
uses: actions/checkout@v4
with:
path: dsBaseClient
- name: Start Opal docker-compose
run: docker compose -f docker-compose_opal.yml up -d --build
working-directory: dsBaseClient
- name: Uninstall default MySQL
run: |
sudo service mysql stop || true
sudo apt-get update
sudo apt-get remove --purge mysql-client mysql-server mysql-common -y
sudo apt-get autoremove -y
sudo apt-get autoclean -y
sudo rm -rf /var/lib/mysql/
- uses: r-lib/actions/setup-pandoc@v2
- uses: r-lib/actions/setup-r@v2
with:
r-version: release
http-user-agent: release
use-public-rspm: true
- name: Install system libraries
run: |
sudo apt-get update -qq
sudo apt-get install -qq libxml2-dev libcurl4-openssl-dev libssl-dev libgsl-dev libgit2-dev -y
sudo apt-get install -qq libharfbuzz-dev libfribidi-dev libmagick++-dev libudunits2-dev libuv1-dev -y
- uses: r-lib/actions/setup-r-dependencies@v2
with:
dependencies: 'c("Imports")'
extra-packages: |
cran::devtools
cran::usethis
cran::git2r
cran::covr
cran::fields
cran::meta
cran::metafor
cran::ggplot2
cran::gridExtra
cran::data.table
cran::DSI
cran::opalr
cran::DSOpal
cran::DSLite
cran::MolgenisAuth
cran::MolgenisArmadillo
cran::DSMolgenisArmadillo
cran::DescTools
cran::e1071
needs: check
- name: Install dsDangerClient
run: R -q -e "devtools::install_github(repo='datashield/dsDangerClient', ref=Sys.getenv('BRANCH_NAME'))"
- name: Install test datasets to Opal
run: |
sleep 60
R -q -f "obiba_opal-upload_testing_datasets.R"
working-directory: dsBaseClient/tests/testthat/data_files
- name: Install dsBase to Opal, set disclosure test options
run: |
R -q -e "library(opalr); opal <- opal.login(username = 'administrator', password = 'datashield_test&', url = 'http://localhost:8080/'); opal.put(opal, 'system', 'conf', 'general', '_rPackage'); opal.logout(opal)"
R -q -e "library(opalr); opal <- opal.login('administrator','datashield_test&', url='http://localhost:8080/'); dsadmin.install_github_package(opal, 'dsBase', username = 'datashield', ref = '${{ env.DSBASE_REF }}'); opal.logout(opal)"
sleep 60
expected_version=$(curl -sf "https://raw.githubusercontent.com/datashield/dsBase/${{ env.DSBASE_REF }}/DESCRIPTION" | sed -n 's/^Version: //p' | tr -d '\r')
if [ -z "$expected_version" ]; then
echo "Could not determine expected dsBase version from GitHub"
exit 1
fi
echo "Expected dsBase version: $expected_version"
R -q -e "library(opalr); opal <- opal.login('administrator', 'datashield_test&', url='http://localhost:8080/'); desc <- dsadmin.package_description(opal, 'dsBase'); opal.logout(opal); installed_version <- desc[['Version']]; cat('Installed dsBase version:', installed_version, '\n'); if (is.null(installed_version) || installed_version != '$expected_version') stop('dsBase version mismatch: expected $expected_version, found ', installed_version)"
R -q -e "library(opalr); opal <- opal.login('administrator', 'datashield_test&', url='http://localhost:8080/'); dsadmin.profile_init(opal, name = 'default', packages = c('dsBase', 'dsTidyverse', 'resourcer')); opal.logout(opal)"
R -q -e "library(opalr); opal <- opal.login('administrator', 'datashield_test&', url='http://localhost:8080/'); dsadmin.set_option(opal, 'default.datashield.privacyControlLevel', 'permissive'); opal.logout(opal)"
working-directory: dsBaseClient/tests/testthat/data_files
- name: Install dsDanger package on Opal server
run: |
R -q -e "library(opalr); opal <- opal.login(username = 'administrator', password = 'datashield_test&', url = 'http://localhost:8080'); opal.put(opal, 'system', 'conf', 'general', '_rPackage'); opal.logout(opal)"
R -q -e "library(opalr); opal <- opal.login('administrator','datashield_test&', url='http://localhost:8080/'); dsadmin.install_github_package(opal, 'dsDanger', username = 'datashield', ref = '${{ env.DSDANGER_REF }}'); opal.logout(opal)"
working-directory: dsBaseClient
- name: Run dsDanger tests with JUnit report
run: |
R -q -e '
library(testthat);
output_file <- file("test_console_output_dsdanger.txt");
sink(output_file);
sink(output_file, type = "message");
junit_rep <- JunitReporter$new(file = "test_results_dsdanger.xml");
progress_rep <- ProgressReporter$new(max_failures = 999999);
multi_rep <- MultiReporter$new(reporters = list(progress_rep, junit_rep));
options("datashield.return_errors" = FALSE, "default_driver" = "${{ env.DS_DRIVER }}");
testthat::test_package("${{ env.PROJECT_NAME }}", filter = "${{ env.TEST_FILTER_DSDANGER }}", reporter = multi_rep, stop_on_failure = FALSE)'
cat test_console_output_dsdanger.txt
working-directory: dsBaseClient
- name: Upload dsDanger results
uses: actions/upload-artifact@v4
with:
name: opal-dsdanger
path: |
dsBaseClient/test_results_dsdanger.xml
dsBaseClient/test_console_output_dsdanger.txt
################################################################################
# Opal - merge all shard + dsDanger results and publish the report.
################################################################################
opal-report:
name: Opal report
needs: [opal-dsbase, opal-dsdanger]
if: always()
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout dsBaseClient
uses: actions/checkout@v4
with:
path: dsBaseClient
- name: Checkout testStatus
if: ${{ github.actor != 'nektos/act' }} # for local deployment only
uses: actions/checkout@v4
with:
repository: ${{ env.REPO_OWNER }}/testStatus
ref: master
path: testStatus
persist-credentials: false
token: ${{ env.GITHUB_TOKEN }}
- uses: r-lib/actions/setup-pandoc@v2
- uses: r-lib/actions/setup-r@v2
with:
r-version: release
use-public-rspm: true
- name: Install xml-twig-tools
run: |
sudo apt-get update -qq
sudo apt-get install -qq xml-twig-tools -y
- uses: r-lib/actions/setup-r-dependencies@v2
with:
dependencies: 'NA'
extra-packages: |
cran::quarto
cran::knitr
cran::kableExtra
cran::rmarkdown
cran::downlit
cran::xml2
cran::purrr
cran::dplyr
cran::stringr
cran::tidyr
cran::readr
cran::magrittr
- name: Download shard/dsdanger results
uses: actions/download-artifact@v4
with:
pattern: 'opal-*'
path: dsBaseClient/artifacts
- name: Merge results
run: |
mkdir -p logs
xml_grep --pretty_print indented --wrap "testsuites" --descr "" --cond "testsuite" artifacts/*/test_results_*.xml > logs/test_results.xml
cat artifacts/*/test_console_output_*.txt > logs/test_console_output.txt
first=1
for f in artifacts/opal-dsbase-*/coveragelist.csv; do
if [ $first -eq 1 ]; then
cat "$f" > logs/coveragelist.csv
first=0
else
tail -n +2 "$f" >> logs/coveragelist.csv
fi
done
working-directory: dsBaseClient
- name: Check for JUnit errors
run: |
issue_count=$(sed 's/failures="0" errors="0"//' test_results.xml | grep -c errors= || true)
echo "Number of testsuites with issues: $issue_count"
sed 's/failures="0" errors="0"//' test_results.xml | grep errors= > issues.log || true
cat issues.log || true
# continue with workflow even when some tests fail
exit 0
working-directory: dsBaseClient/logs
- name: Write versions to file
run: |
echo "branch:${{ env.BRANCH_NAME }}" > ${{ env.WORKFLOW_ID }}.txt
echo "os:$(lsb_release -ds)" >> ${{ env.WORKFLOW_ID }}.txt
echo "R:$(R --version | head -n1)" >> ${{ env.WORKFLOW_ID }}.txt
working-directory: dsBaseClient/logs
- name: Parse results from testthat and covr
run: Rscript --verbose --vanilla ../testStatus/source/parse_test_report.R logs/
working-directory: dsBaseClient
- name: Render report
run: |
cd testStatus
mkdir -p new/logs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/${{ env.WORKFLOW_ID }}/
mkdir -p new/docs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/${{ env.WORKFLOW_ID }}/
mkdir -p new/docs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/latest/
cp -rv ../dsBaseClient/logs/* new/logs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/${{ env.WORKFLOW_ID }}/
cp -rv ../dsBaseClient/logs/${{ env.WORKFLOW_ID }}.txt new/logs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/${{ env.WORKFLOW_ID }}/
R -e 'input_dir <- file.path("../new/logs", Sys.getenv("PROJECT_NAME"), Sys.getenv("BRANCH_NAME"), Sys.getenv("WORKFLOW_ID")); quarto::quarto_render("source/test_report.qmd", execute_params = list(input_dir = input_dir))'
mv source/test_report.html new/docs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/${{ env.WORKFLOW_ID }}/index.html
cp -r new/docs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/${{ env.WORKFLOW_ID }}/* new/docs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/latest
env:
PROJECT_NAME: ${{ env.PROJECT_NAME }}
BRANCH_NAME: ${{ env.BRANCH_NAME }}
WORKFLOW_ID: ${{ env.WORKFLOW_ID }}
- name: Upload test logs
uses: actions/upload-artifact@v4
with:
name: dsbaseclient-logs-opal
path: testStatus/new
################################################################################
# Armadillo - dsBase suite, sharded 4 ways. Each shard downloads and runs its
# own Armadillo jar instance.
#
# Runs as a plain `java -jar` process instead of docker-compose: Armadillo
# self-manages its own Rock container over the host Docker socket
# (docker-management-enabled: true / docker-run-in-container: false), which
# avoids building/pulling the old custom armadillo_citest image and its
# dockerised Armadillo layer. The latest GitHub release jar is downloaded at
# run time. No process is restarted after installing dsBase - install then
# whitelist directly.
################################################################################
armadillo-dsbase:
name: Armadillo dsBase tests (${{ matrix.category }})
runs-on: ubuntu-latest
timeout-minutes: 60
strategy:
fail-fast: false
# One matrix entry per test-file category, each with its own testthat
# filter substring - not evenly sized (smk/arg are much bigger than
# perf/misc), so job durations differ. Traded for the ability to add,
# remove, or temporarily skip a whole category by editing this list
# alone, with no shell-side partitioning logic to keep in sync.
matrix:
include:
- category: smk
filter: 'smk-'
- category: arg
filter: 'arg-'
- category: perf
filter: 'perf-'
- category: misc
filter: 'datachk-|disc-|expt-|smk_expt-|math-|_-'
env:
DS_DRIVER: ArmadilloDriver
DSBASE_TARBALL: dsBase_7.0.0-permissive.tar.gz
steps:
- name: Checkout dsBaseClient
uses: actions/checkout@v4
with:
path: dsBaseClient
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'
- name: Download and start Armadillo (jar)
run: |
mkdir -p armadillo_home/config armadillo_home/storage armadillo_home/logs
cat > armadillo_home/config/application.yml <<EOF
armadillo:
docker-management-enabled: true
docker-run-in-container: false
profiles:
- name: default
image: datashield/rock_citest-permissive:latest
port: 8085
package-whitelist:
- dsBase
- dsTidyverse
- resourcer
function-blacklist: [ ]
options:
datashield:
seed: 342325352
spring:
security:
user:
name: admin
password: admin
servlet:
multipart:
max-file-size: 1000MB
max-request-size: 1000MB
storage:
root-dir: $(pwd)/armadillo_home/storage
audit.log.path: '$(pwd)/armadillo_home/logs/audit.log'
stdout.log.path: '$(pwd)/armadillo_home/logs/armadillo.log'
logging:
level:
root: "warn"
org.molgenis: "warn"
EOF
release_json=$(curl -sf https://api.github.com/repos/molgenis/molgenis-service-armadillo/releases/latest)
jar_url=$(echo "$release_json" | jq -r '.assets[] | select(.name | endswith(".jar")) | .browser_download_url')
echo "Installing Armadillo $(echo "$release_json" | jq -r '.tag_name')"
curl -fSL -o armadillo_home/armadillo.jar "$jar_url"
JAVA_TOOL_OPTIONS="-Xms1G -Xmx2G -XX:+UseG1GC" \
nohup java -jar armadillo_home/armadillo.jar \
--server.port=8080 \
--spring.config.additional-location=file:$(pwd)/armadillo_home/config/application.yml \
> armadillo_home/logs/stdout.log 2>&1 &
echo $! > armadillo_home/armadillo.pid
docker pull datashield/rock_citest-permissive:latest
working-directory: dsBaseClient
- name: Uninstall default MySQL
run: |
sudo service mysql stop || true
sudo apt-get update
sudo apt-get remove --purge mysql-client mysql-server mysql-common -y
sudo apt-get autoremove -y
sudo apt-get autoclean -y
sudo rm -rf /var/lib/mysql/
- uses: r-lib/actions/setup-pandoc@v2
- uses: r-lib/actions/setup-r@v2
with:
r-version: release
http-user-agent: release
use-public-rspm: true
- name: Install system libraries
run: |
sudo apt-get update -qq
sudo apt-get install -qq libxml2-dev libcurl4-openssl-dev libssl-dev libgsl-dev libgit2-dev -y
sudo apt-get install -qq libharfbuzz-dev libfribidi-dev libmagick++-dev libudunits2-dev libuv1-dev -y
- uses: r-lib/actions/setup-r-dependencies@v2
with:
dependencies: 'c("Imports")'
extra-packages: |
cran::devtools
cran::usethis
cran::covr
cran::fields
cran::meta
cran::metafor
cran::ggplot2
cran::gridExtra
cran::data.table
cran::DSI
cran::opalr
cran::DSOpal
cran::DSLite
cran::MolgenisAuth
cran::MolgenisArmadillo
cran::DSMolgenisArmadillo
cran::DescTools
cran::e1071
needs: check
- name: Wait for Armadillo to be ready
run: |
for i in $(seq 1 60); do
if curl -fsS http://localhost:8080/actuator/health 2>/dev/null | grep -q '"status":"UP"'; then
echo "Armadillo is ready"
exit 0
fi
sleep 5
done
echo "Armadillo did not become ready in time"
cat armadillo_home/logs/stdout.log || true
exit 1
working-directory: dsBaseClient
- name: Install test datasets to Armadillo
run: R -q -f "molgenis_armadillo-upload_testing_datasets.R"
working-directory: dsBaseClient/tests/testthat/data_files
- name: Install dsBase to Armadillo
run: |
curl -u admin:admin -X GET http://localhost:8080/packages
install_status=$(curl -u admin:admin -H 'Content-Type: multipart/form-data' -F "file=@${{ env.DSBASE_TARBALL }}" -o /dev/null -w '%{http_code}' -X POST http://localhost:8080/install-package)
if [ "$install_status" != "200" ]; then
echo "dsBase install request failed with HTTP status $install_status"
exit 1
fi
expected_version=$(tar -xOzf ${{ env.DSBASE_TARBALL }} dsBase/DESCRIPTION | sed -n 's/^Version: //p' | tr -d '\r')
if [ -z "$expected_version" ]; then
echo "Could not determine expected dsBase version from ${{ env.DSBASE_TARBALL }}"
exit 1
fi
echo "Expected dsBase version: $expected_version"
actual_version=""
for i in $(seq 1 30); do
packages_json=$(curl -sf -u admin:admin -X GET http://localhost:8080/packages || true)
actual_version=$(echo "$packages_json" | jq -r '.[] | select(.name == "dsBase") | .version' 2>/dev/null || true)
if [ "$actual_version" == "$expected_version" ]; then
break
fi
sleep 10
done
echo "Installed dsBase version: $actual_version"
if [ "$actual_version" != "$expected_version" ]; then
echo "dsBase version mismatch: expected $expected_version, found '$actual_version'"
exit 1
fi
curl -u admin:admin -X POST http://localhost:8080/whitelist/dsBase
working-directory: dsBaseClient
- name: Dump Armadillo server log
if: failure()
run: tail -c 20000 armadillo_home/logs/stdout.log
working-directory: dsBaseClient
- name: Run dsBase tests with coverage & JUnit report
run: |
R -q -e "devtools::reload();"
R -q -e '
write.csv(
covr::coverage_to_list(
covr::package_coverage(
type = c("none"),
code = c('"'"'
output_file <- file("test_console_output_dsbase.txt");
sink(output_file);
sink(output_file, type = "message");
junit_rep <- testthat::JunitReporter$new(file = file.path(getwd(), "test_results_dsbase.xml"));
progress_rep <- testthat::ProgressReporter$new(max_failures = 999999);
multi_rep <- testthat::MultiReporter$new(reporters = list(progress_rep, junit_rep));
options("datashield.return_errors" = FALSE, "default_driver" = "${{ env.DS_DRIVER }}");
testthat::test_package("${{ env.PROJECT_NAME }}", filter = "${{ matrix.filter }}", reporter = multi_rep, stop_on_failure = FALSE)'"'"'
)
)
),
"coveragelist.csv"
)'
cat test_console_output_dsbase.txt
working-directory: dsBaseClient
- name: Upload shard results
uses: actions/upload-artifact@v4
with:
name: armadillo-dsbase-${{ matrix.category }}
path: |
dsBaseClient/test_results_dsbase.xml
dsBaseClient/test_console_output_dsbase.txt
dsBaseClient/coveragelist.csv
################################################################################
# Armadillo - dsDanger suite. Small, so it stays a single job.
################################################################################
armadillo-dsdanger:
name: Armadillo dsDanger tests
runs-on: ubuntu-latest
timeout-minutes: 60
env:
DS_DRIVER: ArmadilloDriver
DSBASE_TARBALL: dsBase_7.0.0-permissive.tar.gz
DSDANGER_TARBALL: dsDanger_6.3.4.tar.gz
steps:
- name: Checkout dsBaseClient
uses: actions/checkout@v4
with:
path: dsBaseClient
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'
- name: Download and start Armadillo (jar)
run: |
mkdir -p armadillo_home/config armadillo_home/storage armadillo_home/logs
cat > armadillo_home/config/application.yml <<EOF
armadillo:
docker-management-enabled: true
docker-run-in-container: false
profiles:
- name: default
image: datashield/rock_citest-permissive:latest
port: 8085
package-whitelist:
- dsBase
- dsTidyverse
- resourcer
function-blacklist: [ ]
options:
datashield:
seed: 342325352
spring:
security:
user:
name: admin
password: admin
servlet:
multipart:
max-file-size: 1000MB
max-request-size: 1000MB
storage:
root-dir: $(pwd)/armadillo_home/storage
audit.log.path: '$(pwd)/armadillo_home/logs/audit.log'
stdout.log.path: '$(pwd)/armadillo_home/logs/armadillo.log'
logging:
level:
root: "warn"
org.molgenis: "warn"
EOF
release_json=$(curl -sf https://api.github.com/repos/molgenis/molgenis-service-armadillo/releases/latest)
jar_url=$(echo "$release_json" | jq -r '.assets[] | select(.name | endswith(".jar")) | .browser_download_url')
echo "Installing Armadillo $(echo "$release_json" | jq -r '.tag_name')"
curl -fSL -o armadillo_home/armadillo.jar "$jar_url"
JAVA_TOOL_OPTIONS="-Xms1G -Xmx2G -XX:+UseG1GC" \
nohup java -jar armadillo_home/armadillo.jar \
--server.port=8080 \
--spring.config.additional-location=file:$(pwd)/armadillo_home/config/application.yml \
> armadillo_home/logs/stdout.log 2>&1 &
echo $! > armadillo_home/armadillo.pid
docker pull datashield/rock_citest-permissive:latest
working-directory: dsBaseClient
- name: Uninstall default MySQL
run: |
sudo service mysql stop || true
sudo apt-get update
sudo apt-get remove --purge mysql-client mysql-server mysql-common -y
sudo apt-get autoremove -y
sudo apt-get autoclean -y
sudo rm -rf /var/lib/mysql/
- uses: r-lib/actions/setup-pandoc@v2
- uses: r-lib/actions/setup-r@v2
with:
r-version: release
http-user-agent: release
use-public-rspm: true
- name: Install system libraries
run: |
sudo apt-get update -qq
sudo apt-get install -qq libxml2-dev libcurl4-openssl-dev libssl-dev libgsl-dev libgit2-dev -y
sudo apt-get install -qq libharfbuzz-dev libfribidi-dev libmagick++-dev libudunits2-dev libuv1-dev -y
- uses: r-lib/actions/setup-r-dependencies@v2
with:
dependencies: 'c("Imports")'
extra-packages: |
cran::devtools
cran::usethis
cran::git2r
cran::covr
cran::fields
cran::meta
cran::metafor
cran::ggplot2
cran::gridExtra
cran::data.table
cran::DSI
cran::opalr
cran::DSOpal
cran::DSLite
cran::MolgenisAuth
cran::MolgenisArmadillo
cran::DSMolgenisArmadillo
cran::DescTools
cran::e1071
needs: check
- name: Install dsDangerClient
run: R -q -e "devtools::install_github(repo='datashield/dsDangerClient', ref=Sys.getenv('BRANCH_NAME'))"
- name: Wait for Armadillo to be ready
run: |
for i in $(seq 1 60); do
if curl -fsS http://localhost:8080/actuator/health 2>/dev/null | grep -q '"status":"UP"'; then
echo "Armadillo is ready"
exit 0
fi
sleep 5
done
echo "Armadillo did not become ready in time"
cat armadillo_home/logs/stdout.log || true
exit 1
working-directory: dsBaseClient
- name: Install test datasets to Armadillo
run: R -q -f "molgenis_armadillo-upload_testing_datasets.R"
working-directory: dsBaseClient/tests/testthat/data_files
- name: Install dsBase to Armadillo
run: |
curl -u admin:admin -X GET http://localhost:8080/packages
install_status=$(curl -u admin:admin -H 'Content-Type: multipart/form-data' -F "file=@${{ env.DSBASE_TARBALL }}" -o /dev/null -w '%{http_code}' -X POST http://localhost:8080/install-package)
if [ "$install_status" != "200" ]; then
echo "dsBase install request failed with HTTP status $install_status"
exit 1
fi
expected_version=$(tar -xOzf ${{ env.DSBASE_TARBALL }} dsBase/DESCRIPTION | sed -n 's/^Version: //p' | tr -d '\r')
if [ -z "$expected_version" ]; then
echo "Could not determine expected dsBase version from ${{ env.DSBASE_TARBALL }}"
exit 1
fi
echo "Expected dsBase version: $expected_version"
actual_version=""
for i in $(seq 1 30); do
packages_json=$(curl -sf -u admin:admin -X GET http://localhost:8080/packages || true)
actual_version=$(echo "$packages_json" | jq -r '.[] | select(.name == "dsBase") | .version' 2>/dev/null || true)
if [ "$actual_version" == "$expected_version" ]; then
break
fi
sleep 10
done
echo "Installed dsBase version: $actual_version"
if [ "$actual_version" != "$expected_version" ]; then
echo "dsBase version mismatch: expected $expected_version, found '$actual_version'"
exit 1
fi
curl -u admin:admin -X POST http://localhost:8080/whitelist/dsBase
working-directory: dsBaseClient
- name: Dump Armadillo server log
if: failure()
run: tail -c 20000 armadillo_home/logs/stdout.log
working-directory: dsBaseClient
- name: Install dsDanger package on Armadillo server
run: |
curl -u admin:admin http://localhost:8080/whitelist
install_status=$(curl -u admin:admin -H 'Content-Type: multipart/form-data' -F "file=@${{ env.DSDANGER_TARBALL }}" -o /dev/null -w '%{http_code}' -X POST http://localhost:8080/install-package)
if [ "$install_status" != "200" ]; then
echo "dsDanger install request failed with HTTP status $install_status"
exit 1
fi
for i in $(seq 1 30); do
packages_json=$(curl -sf -u admin:admin -X GET http://localhost:8080/packages || true)
if echo "$packages_json" | jq -e '.[] | select(.name == "dsDanger")' >/dev/null 2>&1; then
break
fi
sleep 10
done
curl -u admin:admin -X POST http://localhost:8080/whitelist/dsDanger
curl -u admin:admin http://localhost:8080/whitelist
working-directory: dsBaseClient
- name: Run dsDanger tests with JUnit report
run: |
R -q -e '
library(testthat);
output_file <- file("test_console_output_dsdanger.txt");
sink(output_file);
sink(output_file, type = "message");
junit_rep <- JunitReporter$new(file = "test_results_dsdanger.xml");
progress_rep <- ProgressReporter$new(max_failures = 999999);
multi_rep <- MultiReporter$new(reporters = list(progress_rep, junit_rep));
options("datashield.return_errors" = FALSE, "default_driver" = "${{ env.DS_DRIVER }}");
testthat::test_package("${{ env.PROJECT_NAME }}", filter = "${{ env.TEST_FILTER_DSDANGER }}", reporter = multi_rep, stop_on_failure = FALSE)'
cat test_console_output_dsdanger.txt
working-directory: dsBaseClient
- name: Upload dsDanger results
uses: actions/upload-artifact@v4
with:
name: armadillo-dsdanger
path: |
dsBaseClient/test_results_dsdanger.xml
dsBaseClient/test_console_output_dsdanger.txt
################################################################################
# Armadillo - merge all shard + dsDanger results and publish the report.
################################################################################
armadillo-report:
name: Armadillo report
needs: [armadillo-dsbase, armadillo-dsdanger]
if: always()
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout dsBaseClient
uses: actions/checkout@v4
with:
path: dsBaseClient
- name: Checkout testStatus
if: ${{ github.actor != 'nektos/act' }} # for local deployment only
uses: actions/checkout@v4
with:
repository: ${{ env.REPO_OWNER }}/testStatus
ref: master
path: testStatus
persist-credentials: false
token: ${{ env.GITHUB_TOKEN }}
- uses: r-lib/actions/setup-pandoc@v2
- uses: r-lib/actions/setup-r@v2
with:
r-version: release
use-public-rspm: true
- name: Install xml-twig-tools
run: |
sudo apt-get update -qq
sudo apt-get install -qq xml-twig-tools -y
- uses: r-lib/actions/setup-r-dependencies@v2
with:
dependencies: 'NA'
extra-packages: |
cran::quarto
cran::knitr
cran::kableExtra
cran::rmarkdown
cran::downlit
cran::xml2
cran::purrr
cran::dplyr
cran::stringr
cran::tidyr
cran::readr
cran::magrittr
- name: Download shard/dsdanger results
uses: actions/download-artifact@v4
with:
pattern: 'armadillo-*'
path: dsBaseClient/artifacts
- name: Merge results
run: |
mkdir -p logs
xml_grep --pretty_print indented --wrap "testsuites" --descr "" --cond "testsuite" artifacts/*/test_results_*.xml > logs/test_results.xml
cat artifacts/*/test_console_output_*.txt > logs/test_console_output.txt
first=1
for f in artifacts/armadillo-dsbase-*/coveragelist.csv; do
if [ $first -eq 1 ]; then
cat "$f" > logs/coveragelist.csv
first=0
else
tail -n +2 "$f" >> logs/coveragelist.csv
fi
done
working-directory: dsBaseClient
- name: Check for JUnit errors
run: |
issue_count=$(sed 's/failures="0" errors="0"//' test_results.xml | grep -c errors= || true)
echo "Number of testsuites with issues: $issue_count"
sed 's/failures="0" errors="0"//' test_results.xml | grep errors= > issues.log || true
cat issues.log || true
# continue with workflow even when some tests fail
exit 0
working-directory: dsBaseClient/logs
- name: Write versions to file
run: |
echo "branch:${{ env.BRANCH_NAME }}" > ${{ env.WORKFLOW_ID }}.txt
echo "os:$(lsb_release -ds)" >> ${{ env.WORKFLOW_ID }}.txt
echo "R:$(R --version | head -n1)" >> ${{ env.WORKFLOW_ID }}.txt
working-directory: dsBaseClient/logs
- name: Parse results from testthat and covr
run: Rscript --verbose --vanilla ../testStatus/source/parse_test_report.R logs/
working-directory: dsBaseClient
- name: Render report
run: |
cd testStatus
mkdir -p new/logs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/${{ env.WORKFLOW_ID }}/
mkdir -p new/docs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/${{ env.WORKFLOW_ID }}/
mkdir -p new/docs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/latest/
cp -rv ../dsBaseClient/logs/* new/logs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/${{ env.WORKFLOW_ID }}/
cp -rv ../dsBaseClient/logs/${{ env.WORKFLOW_ID }}.txt new/logs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/${{ env.WORKFLOW_ID }}/
R -e 'input_dir <- file.path("../new/logs", Sys.getenv("PROJECT_NAME"), Sys.getenv("BRANCH_NAME"), Sys.getenv("WORKFLOW_ID")); quarto::quarto_render("source/test_report.qmd", execute_params = list(input_dir = input_dir))'
mv source/test_report.html new/docs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/${{ env.WORKFLOW_ID }}/index.html
cp -r new/docs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/${{ env.WORKFLOW_ID }}/* new/docs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/latest
env:
PROJECT_NAME: ${{ env.PROJECT_NAME }}
BRANCH_NAME: ${{ env.BRANCH_NAME }}
WORKFLOW_ID: ${{ env.WORKFLOW_ID }}
- name: Upload test logs
uses: actions/upload-artifact@v4
with:
name: dsbaseclient-logs-armadillo
path: testStatus/new