Skip to content
Open
Show file tree
Hide file tree
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
43 changes: 43 additions & 0 deletions .github/workflows/test-terra-base.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Test terra-base
# Smoke-test the terra-base image on pull requests that touch it.

on:
pull_request:
branches: [ master ]

workflow_dispatch:
# Allows manually triggering the workflow on a selected branch via the GitHub Actions tab.

jobs:

test_docker_image:
runs-on: self-hosted

steps:
- name: Checkout
uses: actions/checkout@v7

- name: Build the terra-base image locally
run: |
docker build --pull ./terra-base --tag terra-base:smoke-test

- name: Test Python version
run: |
version=$(docker run --rm --entrypoint="" terra-base:smoke-test python --version)
echo "$version"
[[ "$version" == "Python 3.10"* ]]

- name: Test OS version
run: |
version=$(docker run --rm --entrypoint="" terra-base:smoke-test \
bash -c 'source /etc/os-release && echo "$VERSION"')
echo "$version"
[[ "$version" == "22.04"* ]]

- name: Smoke test
run: |
docker run --rm \
--volume "$GITHUB_WORKSPACE/terra-base/tests:/tests:ro" \
--entrypoint="" \
terra-base:smoke-test \
/etc/jupyter/bin/python /tests/smoke_test.py
2 changes: 1 addition & 1 deletion build_all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# 8- terra-jupyter-bioconductor
# 9- terra-rstudio-aou
# 10- wondershaper
images=("terra-base", "terra-jupyter-base" "terra-jupyter-python" "terra-jupyter-r" "terra-jupyter-gatk" "terra-jupyter-hail" "terra-jupyter-aou" "terra-jupyter-bioconductor" "terra-rstudio-aou" "wondershaper")
images=("terra-base" "terra-jupyter-base" "terra-jupyter-python" "terra-jupyter-r" "terra-jupyter-gatk" "terra-jupyter-hail" "terra-jupyter-aou" "terra-jupyter-bioconductor" "terra-rstudio-aou" "wondershaper")

# Loop over each image to build in the correct order
for image in "${images[@]}"; do
Expand Down
87 changes: 87 additions & 0 deletions terra-base/tests/smoke_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
"""Smoke tests for the terra-base image.

Verifies that both the user-facing conda kernel env and the Jupyter server venv run the
image's target Python (the PYTHON_VERSION set in the Dockerfile), and that the Jupyter
stack and the Terra (Leonardo) notebook extensions import on that Python.

Has no third-party dependencies, so CI can run it without installing anything:

docker run --rm --entrypoint="" terra-base:smoke-test \
/etc/jupyter/bin/python /tests/smoke_test.py

Run it with the Jupyter *server* venv python (it shells out to check the kernel env too).
The functions are also pytest-discoverable if pytest is available in that interpreter.
"""
import os
import subprocess
import sys

# The Jupyter server runs in this venv; user notebook code runs in the conda kernel env.
SERVER_PY = "/etc/jupyter/bin/python"
KERNEL_PY = "/home/jupyter/.envs/python3/bin/python"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is this really the location? I thought it was under a python 3.10 specific name

# Where the Dockerfile copies the Leonardo extensions (loaded via run-jupyter.sh).
CUSTOM_DIR = "/etc/jupyter/custom"


def _target_version():
"""The image's target Python as 'major.minor' (from ENV PYTHON_VERSION), or None."""
return os.environ.get("PYTHON_VERSION", "").strip() or None


def _minor(python_path):
out = subprocess.check_output(
[python_path, "-c", "import sys; print('%d.%d' % sys.version_info[:2])"]
)
return out.decode().strip()


def test_kernel_env_matches_target():
target = _target_version()
got = _minor(KERNEL_PY)
if target:
assert got == target, f"conda kernel env is Python {got}, expected {target}"


def test_server_venv_matches_target():
target = _target_version()
got = _minor(SERVER_PY)
if target:
assert got == target, f"jupyter server venv is Python {got}, expected {target}"


def test_server_and_kernel_agree():
assert _minor(SERVER_PY) == _minor(KERNEL_PY), "server venv and kernel env Python differ"


def test_jupyter_stack_imports():

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

For notebooks and labs I would test that you are getting the expected version. Terra is currently not setup for notebook 7 for instance

# Runs under the server venv python, where the Jupyter stack lives.
import notebook # noqa: F401
import jupyterlab # noqa: F401
import jupyter_server # noqa: F401
import nbclassic # noqa: F401
import jupyter_core # noqa: F401
import traitlets # noqa: F401
import notebook.utils # noqa: F401 exercises the distutils->setuptools shim on 3.12+


def test_terra_extensions_import():
sys.path.insert(0, CUSTOM_DIR)
import jupyter_localize_extension # noqa: F401
import jupyter_delocalize # noqa: F401


if __name__ == "__main__":
import traceback

tests = [v for k, v in sorted(globals().items()) if k.startswith("test_") and callable(v)]
failed = 0
for test in tests:
try:
test()
print(f"PASS {test.__name__}")
except Exception:
failed += 1
print(f"FAIL {test.__name__}")
traceback.print_exc()
print(f"\n{len(tests) - failed}/{len(tests)} passed")
sys.exit(1 if failed else 0)
Loading