Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
265 changes: 265 additions & 0 deletions .github/workflows/container_testing_workflow.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
name: Container Integration Tests Workflow

on:
push:
branches:
- develop
paths-ignore:
- "doc/**"
- "**/*.md"
- "**/*.txt"
- ".github/ISSUE_TEMPLATE/**"
- ".github/*.md"
Comment on lines +7 to +12
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

paths-ignore excludes doc/**, but later this workflow reads and edits doc/sphinx-guides/source/_static/util/createsequence.sql. As a result, PRs that only change that SQL file (or nearby fixtures under doc/) will not trigger this workflow, even though the runtime behavior depends on it. Consider removing doc/** from the ignore list or switching to a paths: allowlist that includes this SQL file.

Copilot uses AI. Check for mistakes.
pull_request:
branches:
- develop
paths-ignore:
- "doc/**"
- "**/*.md"
- "**/*.txt"
- ".github/ISSUE_TEMPLATE/**"
- ".github/*.md"

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
main-integration-tests-workflow:
runs-on: ubuntu-latest
if: vars.ENABLE_DOCKER_TESTS == 'true'
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This job can run on pull_request events from forks; given it builds and runs Docker containers for up to 120 minutes, this can be an unnecessary resource hit and a potential abuse vector. Other container workflows gate execution to the upstream repo (e.g., .github/workflows/container_app_push.yml:36-38 uses if: ${{ github.repository_owner == 'IQSS' }}). Consider adding a similar guard (and/or restricting to pull_request_target with safe checkout patterns if secrets are ever needed).

Suggested change
if: vars.ENABLE_DOCKER_TESTS == 'true'
if: ${{ vars.ENABLE_DOCKER_TESTS == 'true' && github.repository_owner == 'IQSS' }}

Copilot uses AI. Check for mistakes.
timeout-minutes: 120

defaults:
run:
shell: bash

steps:
# ---------------------------
# CHECKOUT
# ---------------------------
- name: Checkout repository
uses: actions/checkout@v6

# ---------------------------
# VERIFY DOCKER
# ---------------------------
- name: Verify Docker
run: |
set -euo pipefail
docker version

# ---------------------------
# SETUP JAVA + MAVEN
# ---------------------------
- name: Setup Java
uses: actions/setup-java@v5
with:
distribution: "temurin"
java-version: "21"
cache: "maven"

- name: Verify Maven
run: |
set -euo pipefail
mvn -version

# ---------------------------
# CLEAN PREVIOUS VOLUMES
# ---------------------------
- name: Clean docker-dev-volumes
run: |
set -euo pipefail
rm -rf docker-dev-volumes || true

# ---------------------------
# BUILD IMAGES (Dataverse-native)
# ---------------------------
- name: Build Dataverse containers via Maven
run: |
set -euo pipefail
mvn -Pct clean package

# ---------------------------
# START CONTAINERS (BACKGROUND)
# ---------------------------
- name: Start Dataverse stack
run: |
set -euo pipefail
mvn -Pct docker:start \
-Ddataverse.cors.origin=* \
-Ddataverse.cors.methods=GET,POST,PUT,DELETE,OPTIONS \
-Ddataverse.cors.headers.allow=range,content-type,x-dataverse-key,accept \
-Ddataverse.cors.headers.expose=content-encoding,content-range,accept-ranges \
-Ddataverse.feature.index-harvested-metadata-source=true \
-Ddataverse.oai.server.maxidentifiers=2 \
-Ddataverse.oai.server.maxrecords=2 \
-Ddataverse.mail.system-email=noreply@dataverse.yourinstitution.edu

# ---------------------------
# WAIT FOR API READINESS
# ---------------------------
- name: Wait for Dataverse API readiness
run: |
set -euo pipefail
URL="http://localhost:8080/api/info/version"
MAX_ATTEMPTS=10
SLEEP_TIME=15
echo "Waiting for Dataverse readiness..."
for attempt in $(seq 1 $MAX_ATTEMPTS); do
echo "Attempt $attempt..."
RESPONSE=$(curl -s --max-time 15 "$URL" || true)
STATUS=$(echo "$RESPONSE" | jq -r '.status' 2>/dev/null || echo "NOT_READY")
if [ "$STATUS" = "OK" ]; then
echo "Dataverse endpoint is READY."
echo "Dataverse waiting for full readiness. Waiting 30 more seconds."
sleep 30
echo "Response: $RESPONSE"
exit 0
fi
echo "Not ready. Sleeping ${SLEEP_TIME}s..."
sleep $SLEEP_TIME
if [ $SLEEP_TIME -lt 60 ]; then
SLEEP_TIME=$((SLEEP_TIME * 2))
if [ $SLEEP_TIME -gt 60 ]; then
SLEEP_TIME=60
fi
fi
done
echo "Dataverse failed to become ready."
docker ps
CONTAINERS="$(docker ps -q)"
if [ -n "$CONTAINERS" ]; then
for cid in $CONTAINERS; do
echo "===== Logs for container $cid ====="
docker logs "$cid" || true
done
else
echo "No running containers to show logs for."
fi
exit 1

# ---------------------------
# MAP LOCALSTACK TO LOCALHOST
# ---------------------------
- name: Map localstack to localhost for Maven tests
run: echo "127.0.0.1 localstack" | sudo tee -a /etc/hosts

# ---------------------------
# CONFIGURE DATAVERSE FOR TESTS
# ---------------------------
- name: Configure Dataverse API Settings
run: |
set -euo pipefail

echo "Setting API Database Settings via internal container curl..."

# We define the settings in an array
declare -A settings=(
[":BuiltinUsersKey"]="burrito"
[":ProvCollectionEnabled"]="true"
[":AllowApiTokenLookupViaApi"]="true"
[":AllowSignUp"]="true"
)
# We run curl INSIDE the container so the source IP is 127.0.0.1
for key in "${!settings[@]}"; do
echo "Setting $key..."
docker exec dev_dataverse curl -s -X PUT -d "${settings[$key]}" "http://localhost:8080/api/admin/settings/$key"
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docker exec ... curl calls don't use --fail/--fail-with-body (and don't check HTTP status), so a 4xx/5xx response can still return exit code 0 and silently leave the instance misconfigured, causing harder-to-diagnose test failures later. Consider adding --fail-with-body (or --fail) and logging/validating the response for each setting update.

Suggested change
docker exec dev_dataverse curl -s -X PUT -d "${settings[$key]}" "http://localhost:8080/api/admin/settings/$key"
response="$(docker exec dev_dataverse curl --silent --show-error --fail-with-body -X PUT -d "${settings[$key]}" "http://localhost:8080/api/admin/settings/$key")"
echo "$response"

Copilot uses AI. Check for mistakes.
echo ""
done

# ---------------------------
# PRE-TEST INJECTIONS (FROM YOUR ALTERNATE WORKFLOWS)
# ---------------------------
- name: Put SUSHI config file in place
run: |
set -euo pipefail
# Fixes MakeDataCountApiIT
docker exec dev_dataverse sh -c 'curl https://raw.githubusercontent.com/IQSS/dataverse/develop/src/test/java/edu/harvard/iq/dataverse/makedatacount/sushi_sample_logs.json > /tmp/sushi_sample_logs.json && head /tmp/sushi_sample_logs.json'
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This step downloads a test fixture from raw.githubusercontent.com without pinning to a commit SHA and without curl --fail, which hurts CI reproducibility and can silently succeed on HTTP errors (e.g., 404 HTML saved as JSON). Prefer using a fixture checked into the repo, or pin to a specific commit + add -fL/--fail-with-body so failures are explicit.

Suggested change
docker exec dev_dataverse sh -c 'curl https://raw.githubusercontent.com/IQSS/dataverse/develop/src/test/java/edu/harvard/iq/dataverse/makedatacount/sushi_sample_logs.json > /tmp/sushi_sample_logs.json && head /tmp/sushi_sample_logs.json'
docker cp src/test/java/edu/harvard/iq/dataverse/makedatacount/sushi_sample_logs.json dev_dataverse:/tmp/sushi_sample_logs.json
docker exec dev_dataverse sh -c 'head /tmp/sushi_sample_logs.json'

Copilot uses AI. Check for mistakes.
- name: Run database sequence
run: |
set -euo pipefail
# Fixes DataRetrieverApiIT count expectations
export PGPASSWORD=secret
sed -i 's/dvnapp/dataverse/g' doc/sphinx-guides/source/_static/util/createsequence.sql
psql -h localhost -U dataverse dataverse -f doc/sphinx-guides/source/_static/util/createsequence.sql

# ---------------------------
# RUN MAVEN TESTS
# ---------------------------
- name: Run Maven Integration Tests
env:
DVAPIKEY: "burrito"
DV_APIKEY: "burrito"
DV_API_KEY: "burrito"
run: |
set -euo pipefail
# Read the file content into a variable
TEST_SUITE=$(cat tests/integration-tests.txt)

echo "Running suite: $TEST_SUITE"

# Notice we removed the reporting goals from this line so it strictly runs tests
mvn verify \
-Dtest="$TEST_SUITE" \
-Ddataverse.test.baseurl=http://localhost:8080 \
-DcompilerArgument=-Xlint:unchecked \
-DforkCount=1 \
-DreuseForks=true \
-DthreadCount=1 \
-Dparallel=none \
-P all-unit-tests package
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Maven invocation mixes lifecycle phases (verify and later package) in the same command. Because verify already runs all prior phases including package, this can cause redundant work (and in some setups can re-run parts of the build). Consider dropping the trailing package and only invoking verify (with the desired profile and system properties).

Suggested change
-P all-unit-tests package
-P all-unit-tests

Copilot uses AI. Check for mistakes.

# ---------------------------
# GENERATE REPORTS & DEPOSIT TO COVERALLS
# ---------------------------
- name: Generate Reports and Deposit to Coveralls
if: always()
env:
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
# We use continue-on-error here so a Coveralls API hiccup doesn't mark your build as a failure
continue-on-error: true
run: |
set -euo pipefail

echo "Generating JaCoCo XML and pushing to Coveralls..."

# 1. We combine jacoco:report and coveralls:report into ONE command.
# 2. We include the -P all-unit-tests profile so Coveralls inherits the POM configs.
# 3. We explicitly feed the path to the XML file via -DjacocoReports.
mvn jacoco:report coveralls:report \
-P all-unit-tests \
-DrepoToken=$COVERALLS_REPO_TOKEN \
-DjacocoReports=target/site/jacoco/jacoco.xml

# ---------------------------
# UPLOAD RAW HTML ARTIFACT
# ---------------------------
- name: Upload JaCoCo HTML Report
if: always()
uses: actions/upload-artifact@v4
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This workflow uses actions/upload-artifact@v4 while the rest of the repo has standardized on newer upload-artifact versions (e.g. .github/workflows/maven_unit_test.yml:65 uses @v7). Consider aligning to the same version to avoid inconsistencies and potential deprecation issues.

Suggested change
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7

Copilot uses AI. Check for mistakes.
with:
name: jacoco-coverage-report
# This is the standard Maven output path for JaCoCo. Adjust if your POM changes this!
path: target/site/jacoco/
retention-days: 14

# ---------------------------
# DUMP LOGS ON FAILURE
# ---------------------------
- name: Dump Dataverse Logs on Failure
if: failure()
run: docker logs dev_dataverse

# ---------------------------
# SHUTDOWN STACK
# ---------------------------
- name: Stop Dataverse stack
if: always()
run: |
set -euo pipefail
mvn -Pct docker:stop || true
- name: Final Docker cleanup
if: always()
run: |
docker system prune -af || true
Loading