Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
420aff8
feature: add core unit testing to CI
JoshuaSBrown Mar 24, 2026
0cead87
refactor: leave off integration tests for first step.
JoshuaSBrown Mar 24, 2026
3096a7a
Apply suggestions from code review
JoshuaSBrown Mar 25, 2026
6be23f4
fix: make sure build container in intermediate stage exists.
JoshuaSBrown Mar 25, 2026
24b0569
feat: enable building of core integration tests
JoshuaSBrown Mar 25, 2026
51ced0c
fix: add intermediate to core image check.
JoshuaSBrown Mar 25, 2026
b20add2
fix: add missing test labels
JoshuaSBrown Mar 25, 2026
2cc37f9
refactor: add core build intermediate stage to compose build
JoshuaSBrown Mar 25, 2026
172e0ce
Merge remote-tracking branch 'origin/1906-DAPS-feat-core-ci-test-inte…
JoshuaSBrown Mar 25, 2026
fde4044
Merge branch 'devel' into 1906-DAPS-feat-core-ci-test-integration-uni…
JoshuaSBrown Mar 25, 2026
7cf7dca
refactor: Update CMakeLists.txt to include client handler for schemas.
JoshuaSBrown Mar 25, 2026
6d7b70e
Merge branch 'devel' into 1906-DAPS-feat-core-ci-test-integration-uni…
JoshuaSBrown Mar 25, 2026
c4ebadc
Merge branch 'devel' into 1906-DAPS-feat-core-ci-test-integration-uni…
JoshuaSBrown Mar 27, 2026
efd4fd5
Merge branch 'devel' into 1906-DAPS-feat-core-ci-test-integration-uni…
JoshuaSBrown Mar 27, 2026
65693fe
fix: get arango working with core server client handler integration t…
JoshuaSBrown Mar 27, 2026
b1c9b7a
tests: working integration tests with SchemaHandler.
JoshuaSBrown Mar 27, 2026
74ed809
chore: Auto-format shell scripts with shfmt
JoshuaSBrown Mar 27, 2026
7d93b1d
update: leave integration tests off in core build for now.
JoshuaSBrown Mar 27, 2026
6c6d00f
Merge branch '1916-DAPS-tests-add-integration-test-for-schema-client-…
JoshuaSBrown Mar 27, 2026
9327dd4
fix: uncomment commented out code block.
JoshuaSBrown Mar 27, 2026
81c774c
style: fix javascript formatting.
JoshuaSBrown Mar 27, 2026
0df6c4b
Merge branch '1916-DAPS-tests-add-integration-test-for-schema-client-…
JoshuaSBrown Mar 27, 2026
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
2 changes: 1 addition & 1 deletion core/database/foxx/api/schema_router.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ router
delete sch._key;
delete sch._rev;

sch.id = parsed.id + ":" + parsed.ver;
sch.id = parsed.id + ":" + obj.ver;
res.send([sch]);
},
});
Expand Down
84 changes: 80 additions & 4 deletions core/server/tests/integration/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,30 @@ set(MOCK_SCHEMA_PORT "4010"
set(MOCK_SCHEMA_PULL "true"
CACHE STRING "Pull the mock image before starting (set to 'false' for offline/local builds)")

set(ARANGO_IMAGE "savannah.ornl.gov/datafed/arango-foxx:latest"
CACHE STRING "Docker image for the ArangoDB test instance (with Foxx services)")
set(ARANGO_PORT "8529"
CACHE STRING "Host port for the ArangoDB test container")
set(ARANGO_ROOT_PASS "test"
CACHE STRING "Root password for the ArangoDB test instance")
set(ARANGO_PULL "true"
CACHE STRING "Pull the ArangoDB image before starting (set to 'false' for offline/local builds)")
set(DATAFED_TEST_DATABASE_NAME "sdms_test"
CACHE STRING "Database name for integration tests (default: sdms_test)")

# ── Check for Docker (needed by SchemaAPIClient tests) ───────────────────────

find_program(DOCKER_EXECUTABLE docker)
if(NOT DOCKER_EXECUTABLE)
message(STATUS "Docker not found — SchemaAPIClient integration tests will be skipped")
message(STATUS "Docker not found — integration tests requiring containers will be skipped")
endif()

# ── Compile and register all integration tests ──────────────────────────────

foreach(PROG
test_SchemaServiceFactory
test_SchemaAPIClient
test_SchemaHandler
)
file(GLOB ${PROG}_SOURCES ${PROG}*.cpp)
add_executable(integration_${PROG} ${${PROG}_SOURCES})
Expand Down Expand Up @@ -52,14 +64,18 @@ endforeach(PROG)

if(DOCKER_EXECUTABLE)

# ========================================================================
# Mock Schema API (Prism) fixture — used by SchemaAPIClient
# ========================================================================

set(_mock_schema_env
"MOCK_SCHEMA_IMAGE=${MOCK_SCHEMA_IMAGE}"
"MOCK_SCHEMA_PORT=${MOCK_SCHEMA_PORT}"
"MOCK_SCHEMA_PULL=${MOCK_SCHEMA_PULL}"
"CONTAINER_NAME=datafed-mock-schema"
)

set(_test_env
set(_mock_schema_test_env
"SCHEMA_API_TEST_URL=http://localhost:${MOCK_SCHEMA_PORT}"
)

Expand Down Expand Up @@ -91,14 +107,74 @@ if(DOCKER_EXECUTABLE)

set_tests_properties(integration_test_SchemaAPIClient PROPERTIES
FIXTURES_REQUIRED MockSchemaAPI
ENVIRONMENT "${_test_env}"
ENVIRONMENT "${_mock_schema_test_env}"
LABELS "integration"
)

if(ENABLE_MEMORY_TESTS)
set_tests_properties(memory_test_SchemaAPIClient PROPERTIES
FIXTURES_REQUIRED MockSchemaAPI
ENVIRONMENT "${_test_env}"
ENVIRONMENT "${_mock_schema_test_env}"
LABELS "integration;memory"
)
endif()

# ========================================================================
# ArangoDB fixture — used by SchemaHandler
# ========================================================================

set(_arango_env
"ARANGO_IMAGE=${ARANGO_IMAGE}"
"ARANGO_PORT=${ARANGO_PORT}"
"ARANGO_ROOT_PASS=${ARANGO_ROOT_PASS}"
"ARANGO_CONTAINER=datafed-test-arango"
"ARANGO_PULL=${ARANGO_PULL}"
"DATAFED_PROJECT_ROOT=${DataFed_SOURCE_DIR}"
"DATAFED_DATABASE_NAME=${DATAFED_TEST_DATABASE_NAME}"
)
set(_arango_test_env
"DATAFED_TEST_ARANGO_URL=http://localhost:${ARANGO_PORT}/_db/${DATAFED_TEST_DATABASE_NAME}/api/${DATAFED_FOXX_MAJOR}/"
"DATAFED_TEST_ARANGO_USER=root"
"DATAFED_TEST_ARANGO_PASS=${ARANGO_ROOT_PASS}"
"DATAFED_DATABASE_NAME=${ARANGO_TEST_DATABASE_NAME}"
)

# ── Fixture setup: start ArangoDB container ──────────────────────────

add_test(
NAME arango_start
COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/start_test_arango.sh
)
set_tests_properties(arango_start PROPERTIES
FIXTURES_SETUP TestArangoDB
ENVIRONMENT "${_arango_env}"
LABELS "fixture;integration"
)

# ── Fixture cleanup: stop and remove container ───────────────────────

add_test(
NAME arango_stop
COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/stop_test_arango.sh
)
set_tests_properties(arango_stop PROPERTIES
FIXTURES_CLEANUP TestArangoDB
ENVIRONMENT "${_arango_env}"
LABELS "fixture;integration"
)

# ── Attach fixture to SchemaHandler tests ────────────────────────────

set_tests_properties(integration_test_SchemaHandler PROPERTIES
FIXTURES_REQUIRED TestArangoDB
ENVIRONMENT "${_arango_test_env}"
LABELS "integration"
)

if(ENABLE_MEMORY_TESTS)
set_tests_properties(memory_test_SchemaHandler PROPERTIES
FIXTURES_REQUIRED TestArangoDB
ENVIRONMENT "${_arango_test_env}"
LABELS "integration;memory"
)
endif()
Expand Down
151 changes: 151 additions & 0 deletions core/server/tests/integration/start_test_arango.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
#!/usr/bin/env bash
# start_test_arango.sh — Start (or reuse) ArangoDB and provision Foxx services.
#
# If ArangoDB is already reachable at the target address, the existing instance
# is reused and no container is started. Either way, Foxx services are
# (re)installed via scripts/install_foxx.sh.
#
# Required env:
# DATAFED_PROJECT_ROOT — Path to the DataFed repository root
# ARANGO_IMAGE — Docker image (only required when starting a container)
#
# Optional env:
# ARANGO_PORT — Host port to bind (default: 8529)
# ARANGO_ROOT_PASS — Root password (default: "test")
# ARANGO_CONTAINER — Container name (default: datafed-test-arango)
# ARANGO_PULL — "true" to pull image before starting (default: true)
# DATAFED_DATABASE_NAME — Database name (default: "sdms_test")
set -eu

PROJECT_ROOT="${DATAFED_PROJECT_ROOT:?DATAFED_PROJECT_ROOT must be set}"
PORT="${ARANGO_PORT:-8529}"
ROOT_PASS="${ARANGO_ROOT_PASS:-test}"
NAME="${ARANGO_CONTAINER:-datafed-test-arango}"
PULL="${ARANGO_PULL:-true}"
DB_NAME="${DATAFED_DATABASE_NAME:-sdms_test}"
MAX_WAIT=60

# State file: if we create it, the cleanup step knows to tear down the
# container. If ArangoDB was already running, the file is never created
# and cleanup leaves the instance alone.
STATE_FILE="/tmp/${NAME}.started-by-fixture"
rm -f "${STATE_FILE}"

# ── Check for an already-running instance ────────────────────────────────────

if curl -sf -o /dev/null \
-u "root:${ROOT_PASS}" \
"http://localhost:${PORT}/_api/version" 2>/dev/null; then
echo "ArangoDB already reachable on port ${PORT} — reusing existing instance"
else
# ── No instance found — start a container ────────────────────────────────
IMAGE="${ARANGO_IMAGE:?ARANGO_IMAGE must be set (no running ArangoDB found)}"

if ! command -v docker &>/dev/null; then
echo "ERROR: docker not found and no ArangoDB running on port ${PORT}" >&2
exit 1
fi

docker rm -f "${NAME}" &>/dev/null || true

if [ "${PULL}" = "true" ]; then
echo "Pulling ${IMAGE}..."
docker pull "${IMAGE}"
fi

echo "Starting ArangoDB test instance on port ${PORT}..."
docker run -d \
--name "${NAME}" \
-p "${PORT}:8529" \
-e ARANGO_ROOT_PASSWORD="${ROOT_PASS}" \
"${IMAGE}"

# ── Wait for readiness ───────────────────────────────────────────────────
echo "Waiting for ArangoDB readiness (max ${MAX_WAIT}s)..."
for i in $(seq 1 "${MAX_WAIT}"); do
if curl -sf -o /dev/null \
-u "root:${ROOT_PASS}" \
"http://localhost:${PORT}/_api/version" 2>/dev/null; then
echo "ArangoDB ready on port ${PORT} (took ${i}s)"
break
fi
if [ "$i" -eq "${MAX_WAIT}" ]; then
echo "ERROR: ArangoDB did not become ready in ${MAX_WAIT}s" >&2
echo "--- container logs ---"
docker logs "${NAME}" 2>&1 | tail -50 || true
echo "--- end logs ---"
docker rm -f "${NAME}" &>/dev/null || true
exit 1
fi
sleep 1
done

# Mark that we started the container so cleanup knows to remove it.
touch "${STATE_FILE}"
fi

# ── Provision Foxx services ──────────────────────────────────────────────────
#
# install_foxx.sh is idempotent — it checks whether the DB/services exist and
# creates or replaces as needed. We pass credentials via env + CLI flags so
# the script finds the instance we just validated above.
echo "Provisioning database and Foxx services..."
export DATAFED_DATABASE_PASSWORD="${ROOT_PASS}"
export DATAFED_DATABASE_HOST="localhost"
export DATAFED_DATABASE_NAME="${DB_NAME}"

bash "${PROJECT_ROOT}/scripts/install_foxx.sh" \
-p "${ROOT_PASS}" \
-u "root" \
-i "localhost"

echo "Foxx provisioning complete."

# ── Clean up stale test data ─────────────────────────────────────────────────
#
# Previous test runs may have left behind schemas (e.g. from crashes, or from
# the earlier :null bug). Remove anything with a test_ prefix so the new run
# starts clean. This runs after Foxx provisioning to ensure the database and
# collections exist.

ARANGO_URL="http://localhost:${PORT}"

echo "Cleaning stale test schemas from ${DB_NAME}..."
RESULT=$(curl -sf -u "root:${ROOT_PASS}" \
"${ARANGO_URL}/_db/${DB_NAME}/_api/cursor" \
-X POST \
-H "Content-Type: application/json" \
-d '{"query": "FOR s IN sch FILTER STARTS_WITH(s.id, \"test_\") REMOVE s IN sch RETURN OLD.id"}' \
2>/dev/null) || true

if [ -n "${RESULT}" ]; then
REMOVED=$(echo "${RESULT}" | grep -o '"result":\[' | wc -l)
if [ "${REMOVED}" -gt 0 ]; then
COUNT=$(echo "${RESULT}" | grep -o '"id"' | wc -l)
echo "Removed ${COUNT} stale test schema(s)"
else
echo "No stale test schemas found"
fi
else
echo "No stale test schemas found (or sch collection does not exist yet)"
fi

# Also clean up stale schema version edges that reference removed schemas
echo "Cleaning stale schema version edges..."
curl -sf -u "root:${ROOT_PASS}" \
"${ARANGO_URL}/_db/${DB_NAME}/_api/cursor" \
-X POST \
-H "Content-Type: application/json" \
-d '{"query": "FOR e IN sch_ver LET fromExists = LENGTH(FOR s IN sch FILTER s._id == e._from LIMIT 1 RETURN 1) LET toExists = LENGTH(FOR s IN sch FILTER s._id == e._to LIMIT 1 RETURN 1) FILTER fromExists == 0 OR toExists == 0 REMOVE e IN sch_ver RETURN OLD._key"}' \
-o /dev/null 2>/dev/null || true

# Clean up stale schema dependency edges
echo "Cleaning stale schema dependency edges..."
curl -sf -u "root:${ROOT_PASS}" \
"${ARANGO_URL}/_db/${DB_NAME}/_api/cursor" \
-X POST \
-H "Content-Type: application/json" \
-d '{"query": "FOR e IN sch_dep LET fromExists = LENGTH(FOR s IN sch FILTER s._id == e._from LIMIT 1 RETURN 1) LET toExists = LENGTH(FOR s IN sch FILTER s._id == e._to LIMIT 1 RETURN 1) FILTER fromExists == 0 OR toExists == 0 REMOVE e IN sch_dep RETURN OLD._key"}' \
-o /dev/null 2>/dev/null || true

echo "Test environment ready."
26 changes: 26 additions & 0 deletions core/server/tests/integration/stop_test_arango.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env bash
# stop_test_arango.sh — Stop and remove the ArangoDB test container, but only
# if the fixture started it.
#
# If start_test_arango.sh reused a pre-existing instance, the state file won't
# exist and this script is a no-op.
#
# Optional env:
# ARANGO_CONTAINER — Container name (default: datafed-test-arango)
set -u

NAME="${ARANGO_CONTAINER:-datafed-test-arango}"
STATE_FILE="/tmp/${NAME}.started-by-fixture"

if [ -f "${STATE_FILE}" ]; then
if docker rm -f "${NAME}" &>/dev/null; then
echo "Stopped and removed container: ${NAME}"
else
echo "Container ${NAME} was not running (already removed?)"
fi
rm -f "${STATE_FILE}"
else
echo "ArangoDB was pre-existing — leaving it alone"
fi

exit 0
Loading
Loading