Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
5fe5177
Add UDA reference-stack Docker spike + C-ABI smoke round trip (issue …
yohannmarguier Jul 15, 2026
b442af2
Add ./test dispatcher + make targets for the backend contract tiers
yohannmarguier Jul 15, 2026
46ef371
Add UDA read-only parity fixture over the equilibrium seed (issue #24)
yohannmarguier Jul 15, 2026
7432446
Add UDA parity breadth: real-path matrix, AOS/occurrences/list_filled…
yohannmarguier Jul 15, 2026
45806d9
Fix cell count in TRACEABILITY.md Part 5 (32, not 34)
yohannmarguier Jul 15, 2026
3aeba08
Add UDA unique-surface: cache modes, DD loading, datapath, capability…
yohannmarguier Jul 15, 2026
2b5069e
Add UDA unique-surface: fetch mode, local_cache, write-divergence pin…
yohannmarguier Jul 15, 2026
71ef604
Close TRACEABILITY Part 5: cross-reference notes + closure summary (i…
yohannmarguier Jul 16, 2026
ba58c83
Add non-blocking uda-contract CI leg (issue #29)
yohannmarguier Jul 16, 2026
dbb0548
Characterize UDA pulse lifecycle modes
yohannmarguier Jul 16, 2026
cd1f8c9
Pin the UDA-Plugins source commit
yohannmarguier Jul 16, 2026
4272444
Pin exact UDA complex AOS defects
yohannmarguier Jul 16, 2026
3d3e4f6
Correct UDA traceability closure counts
yohannmarguier Jul 16, 2026
7f4b935
Skip UDA contracts when the server is unreachable
yohannmarguier Jul 16, 2026
3290024
Read every reported UDA occurrence
yohannmarguier Jul 16, 2026
c2241f9
Pin UDA characterization defects accurately
yohannmarguier Jul 16, 2026
0036f31
Centralize UDA test addressing and assert cleanup
yohannmarguier Jul 16, 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
86 changes: 86 additions & 0 deletions .github/workflows/uda-contract.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: UDA contract suite (non-blocking)

# Issue #29 (parent #21): a dedicated, informational CI leg for the UDA tier
# (tests/contract/test_uda*.cpp, TRACEABILITY.md Part 5), mirroring the
# mdsplus-contract leg (mdsplus-contract.yml) and its rationale: UDA is one of
# the two DD-coupled backends (CLAUDE.md), and lands as a non-blocking leg only
# now that issue #28 has triaged the whole baseline to terminal statuses, so
# this leg is green (modulo pinned defects) from its first run and there is
# never a red informational leg to maintain.
#
# Runs on a GitHub-hosted arm64 runner: docker/uda/Dockerfile is aarch64 (the
# pinned reference stack docker/uda/README.md documents), matching the
# mdsplus-contract leg's own runner choice.
#
# One cache layer, unlike the mdsplus leg's two: the UDA image
# (docker/uda/Dockerfile) is the pinned, source-independent reference stack
# (UDA server + IMAS plugin source + IDSDef.xml); it does not COPY the repo, so
# it is cached across ordinary pushes and only Dockerfile/run.sh edits bust the
# cache. IMAS-Core itself and the IMAS server plugin are always built fresh
# from the mounted workspace by docker/uda/run.sh, by design (README.md
# "Design: toolchain image + build-workspace-at-runtime") — never baked into
# the image — so there is no second, workspace-keyed cache: CMake's own
# dependency tracking is the only reuse mdsplus's layer 2 gets from a restored
# build-mdsplus/ directory, and the UDA leg has no equivalent artifact to
# restore, only source it must always rebuild against.

on:
push:
pull_request:

env:
IMAGE_TAG: imas-core-uda:ci

jobs:
uda-contract:
name: UDA contract suite (aarch64, non-blocking)
runs-on: ubuntu-24.04-arm
continue-on-error: true # informational leg, not a gate

steps:
- name: Checkout code
uses: actions/checkout@v7
with:
fetch-depth: 0 # git describe needs full history for the version macro

- name: Cache reference-stack image (keyed on Dockerfile + run.sh)
id: cache-image
uses: actions/cache@v4
with:
path: /tmp/uda-image.tar
key: uda-image-${{ hashFiles('docker/uda/Dockerfile', 'docker/uda/run.sh') }}

- name: Build reference-stack image
if: steps.cache-image.outputs.cache-hit != 'true'
run: |
docker build --platform linux/arm64 -f docker/uda/Dockerfile -t "${IMAGE_TAG}" docker/uda
docker save "${IMAGE_TAG}" -o /tmp/uda-image.tar

- name: Load cached reference-stack image
if: steps.cache-image.outputs.cache-hit == 'true'
run: docker load -i /tmp/uda-image.tar

- name: Verify pinned stack identifiers match TRACEABILITY Part 5 header
run: |
set -euo pipefail
uda_server=$(docker inspect -f '{{ index .Config.Labels "org.iter.imas-core.uda-server-version" }}' "${IMAGE_TAG}")
uda_plugins=$(docker inspect -f '{{ index .Config.Labels "org.iter.imas-core.uda-plugins-version" }}' "${IMAGE_TAG}")
uda_plugins_commit=$(docker inspect -f '{{ index .Config.Labels "org.iter.imas-core.uda-plugins-commit" }}' "${IMAGE_TAG}")
dd_version=$(docker inspect -f '{{ index .Config.Labels "org.iter.imas-core.dd-version" }}' "${IMAGE_TAG}")
echo "Image labels: uda-server=${uda_server} uda-plugins=${uda_plugins}@${uda_plugins_commit} dd=${dd_version}"
header=tests/contract/TRACEABILITY.md
grep -q "tag \*\*${uda_server}\*\*" "${header}"
grep -q "tag \*\*${uda_plugins}\*\*" "${header}"
grep -q "commit \*\*\`${uda_plugins_commit}\`\*\*" "${header}"
grep -q "\*\*${dd_version}\*\*" "${header}"
echo "Image stack identifiers match ${header}'s Part 5 pinned-reference-stack table."

- name: Run the UDA contract tier
run: >
docker run --rm --platform linux/arm64
-v "$PWD":/workspace -w /workspace
"${IMAGE_TAG}" uda-run.sh

- name: Note
if: always()
run: echo "UDA leg is informational (issue #21/#29). Red-by-design only for un-pinned defects; TRACEABILITY.md Part 5 (issue #28) records the pinned baseline this leg should stay green against."
24 changes: 24 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Front door for the containerized backend contract tiers. These targets just
# delegate to ./test (the dispatcher); see docker/mdsplus/ and docker/uda/ for
# what each leg builds. The main build stays CMake (`cmake -B build && ...`).
.PHONY: help test test-common test-mdsplus test-uda

help:
@echo "make test-common always-on backends, host-native (== ./test common)"
@echo "make test-mdsplus MDSplus contract tier in Docker (== ./test mdsplus)"
@echo "make test-uda UDA contract tier in Docker (== ./test uda)"
@echo "make test common + mdsplus + uda (== ./test all)"
@echo ""
@echo "Override the platform on x86: PLATFORM=linux/amd64 make test-uda"

test-common:
@./test common

test-mdsplus:
@./test mdsplus

test-uda:
@./test uda

test:
@./test all
132 changes: 132 additions & 0 deletions docker/uda/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# UDA characterization environment (issue #23, feasibility spike for #21).
#
# aarch64 (native on Apple Silicon / GitHub arm64 runners) image standing up the
# pinned UDA reference stack for the contract suite's UDA tier. Mirrors the
# MDSplus leg's philosophy (docker/mdsplus/): the image is the *toolchain +
# pinned reference stack*, and the IMAS-Core client + the IMAS server plugin are
# built at run time against the mounted workspace, so the tests always exercise
# the source under review (never a stale baked-in core). See docker/uda/README.md
# for the run recipe, the gate decision, and the empirically-answered open items.
#
# Pinned stack identifiers (recorded for TRACEABILITY Part 5):
# - UDA server ....... ukaea/uda tag 2.9.3
# - IMAS UDA plugin .. iterorganization/UDA-Plugins tag 1.8.0,
# commit ede25b921081d8fc2d66c5b5ca152c664b50ee78
# - Data Dictionary .. IDSDef.xml DD 4.1.1
FROM ubuntu:24.04

ENV DEBIAN_FRONTEND=noninteractive

# Pinned stack versions (single source of truth; also surfaced as image labels).
ARG UDA_VERSION=2.9.3
ARG UDA_PLUGINS_VERSION=1.8.0
ARG UDA_PLUGINS_COMMIT=ede25b921081d8fc2d66c5b5ca152c664b50ee78
ARG DD_VERSION=4.1.1

LABEL org.iter.imas-core.uda-server-version="2.9.3"
LABEL org.iter.imas-core.uda-plugins-version="${UDA_PLUGINS_VERSION}"
LABEL org.iter.imas-core.uda-plugins-commit="${UDA_PLUGINS_COMMIT}"
LABEL org.iter.imas-core.dd-version="4.1.1"

# --- Toolchain + UDA server + IMAS-Core + plugin build/runtime dependencies ---
# UDA server 2.9.3 (docker/client.*.dockerfile + .github/workflows/cmake.yml):
# boost(+program_options), openssl, libxml2, fmt, spdlog, capnproto, tirpc.
# IMAS-Core (this repo, same set the mdsplus image uses): HDF5, Boost::filesystem.
# IMAS plugin (UDA-Plugins/source/imas): CURL, Boost::filesystem/system.
# xinetd fronts the per-connection uda_server on a TCP port (simplest in a
# container: no systemd/PID-1 dance).
RUN apt-get update && apt-get install -y --no-install-recommends \
git build-essential cmake ninja-build pkg-config ca-certificates wget \
libboost-dev libboost-program-options-dev libboost-filesystem-dev \
libboost-system-dev \
libssl-dev libxml2-dev libfmt-dev libspdlog-dev \
capnproto libcapnp-dev libtirpc-dev \
libhdf5-dev libcurl4-openssl-dev \
libgtest-dev \
python3 python3-venv python3-pip \
xinetd \
&& rm -rf /var/lib/apt/lists/*

# Cap'n Proto's Ubuntu 24.04 CMake config has a broken WITH_LIBATOMIC guard
# (ukaea/uda .github/workflows/cmake.yml patches the same file; the arm64 path
# is aarch64-linux-gnu). Harmless no-op if the line is ever fixed upstream.
RUN sed -i 's/if (yes) # WITH_LIBATOMIC/if (no) # WITH_LIBATOMIC/' \
/usr/lib/aarch64-linux-gnu/cmake/CapnProto/CapnProtoConfig.cmake || true

# --- UDA server (ukaea/uda, pinned) ----------------------------------------
# Full build (CLIENT_ONLY=OFF) so we get both the uda-cpp client the IMAS-Core
# UDA backend links AND the uda_server binary + install_plugin. SSL auth OFF to
# keep the reference stack self-contained (no cert provisioning); the contract
# suite characterizes data access, not transport security. Installs to
# /usr/local: uda_server, uda_cli, install_plugin, libuda_*.so, uda-cpp.pc.
RUN git clone --branch "${UDA_VERSION}" --depth 1 \
https://github.com/ukaea/uda.git /opt/uda-src \
&& cmake -G Ninja -S /opt/uda-src -B /opt/uda-src/build \
-DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Release \
-DCLIENT_ONLY=OFF -DSSLAUTHENTICATION=OFF -DENABLE_CAPNP=ON \
-DCMAKE_INSTALL_PREFIX=/usr/local \
&& cmake --build /opt/uda-src/build -j"$(nproc)" \
&& cmake --install /opt/uda-src/build \
&& rm -rf /opt/uda-src/build

ENV LD_LIBRARY_PATH="/usr/local/lib:/usr/local/lib/plugins"
ENV PATH="/usr/local/bin:${PATH}"

# --- Data Dictionary IDSDef.xml (DD 4.1.1) ---------------------------------
# Sourced from the official imas-data-dictionary PyPI wheel (the same source the
# repo's own ALBuildDataDictionary.cmake uses), NOT by baking a MDSplus model
# tree — AL_BUILD_MDSPLUS_MODELS is deliberately not enabled here. The DD's
# GitHub releases carry no IDSDef.xml asset (it is a generated artifact), so a
# direct release download is not an option; the wheel ships a prebuilt IDSDef.xml
# whose path the packaged `idsinfo idspath` reports. The IMAS-Core UDA backend
# walks this file at run time; its lookup order is $IDSDEF_PATH first, else
# $IMAS_PREFIX/include/IDSDef.xml (src/uda/uda_xml.cpp load_xml()).
RUN python3 -m venv /opt/ddvenv \
&& /opt/ddvenv/bin/pip install --no-cache-dir "imas-data-dictionary==${DD_VERSION}" \
&& cp "$(/opt/ddvenv/bin/idsinfo idspath)" /opt/IDSDef.xml \
&& test -s /opt/IDSDef.xml \
&& grep -q "<version>${DD_VERSION}</version>" /opt/IDSDef.xml
ENV IDSDEF_PATH="/opt/IDSDef.xml"

# --- A second, older DD version for the unique-surface "wrong-version DD"
# characterization (issue #26, test_uda_unique_surface.cpp) -- a real,
# pre-3-to-4-cliff IDSDef.xml, so the client can genuinely load a schema that
# disagrees with the reference stack's own DD 4.1.1, exposed as
# IDSDEF_PATH_OLDER. Not the default $IDSDEF_PATH (that stays DD 4.1.1 for
# every other test); tests that need it swap $IDSDEF_PATH to this value for
# one backend construction and restore it, and skip if this var is unset.
ARG DD_VERSION_OLDER=3.42.0
LABEL org.iter.imas-core.dd-version-older="3.42.0"
RUN python3 -m venv /opt/ddvenv-older \
&& /opt/ddvenv-older/bin/pip install --no-cache-dir "imas-data-dictionary==${DD_VERSION_OLDER}" \
&& cp "$(/opt/ddvenv-older/bin/idsinfo idspath)" /opt/IDSDef-older.xml \
&& test -s /opt/IDSDef-older.xml \
&& grep -q "<version>${DD_VERSION_OLDER}</version>" /opt/IDSDef-older.xml \
&& rm -rf /opt/ddvenv-older
ENV IDSDEF_PATH_OLDER="/opt/IDSDef-older.xml"

# --- IMAS UDA server plugin source (iterorganization/UDA-Plugins, pinned) ---
# Cloned (not tarball) so the plugin's git_describe-derived version resolves to
# the tag and the plugin reports 1.8.0 at run time. Pin both the human-readable
# tag and its immutable commit: if the upstream tag is moved, the build fails
# instead of silently changing the reference image. The plugin is *built* at
# run time (docker/uda/run.sh) because it must link the workspace's IMAS-Core
# (al-core.pc) — the subject under test — and must NOT fall back to the
# mapping-only NO_IMAS degradation.
RUN git clone --branch "${UDA_PLUGINS_VERSION}" --depth 1 \
https://github.com/iterorganization/UDA-Plugins.git /opt/uda-plugins-src \
&& actual_commit="$(git -C /opt/uda-plugins-src rev-parse HEAD)" \
&& if [ "${actual_commit}" != "${UDA_PLUGINS_COMMIT}" ]; then \
echo "UDA-Plugins tag ${UDA_PLUGINS_VERSION} resolved to ${actual_commit}, expected ${UDA_PLUGINS_COMMIT}" >&2; \
exit 1; \
fi \
&& actual_version="$(git -C /opt/uda-plugins-src describe --tags --exact-match HEAD)" \
&& if [ "${actual_version}" != "${UDA_PLUGINS_VERSION}" ]; then \
echo "UDA-Plugins git-describe yielded ${actual_version}, expected ${UDA_PLUGINS_VERSION}" >&2; \
exit 1; \
fi

COPY run.sh /usr/local/bin/uda-run.sh
RUN chmod +x /usr/local/bin/uda-run.sh

WORKDIR /workspace
Loading
Loading