blob: 2053c68fdc131ce8ba9832dc0f4e24b28b293d22 [file]
#!/usr/bin/env bash
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# Runs the common.ai adapter tests for agent frameworks that cannot join the workspace lock.
#
# Strands Agents caps mcp, and Google ADK caps opentelemetry and websockets, below the versions
# uv.lock resolves, so their adapter tests are skipped everywhere else in CI. This installs one
# framework into the CI image and runs the tests of the framework-neutral tools and their adapters;
# the other framework's tests skip themselves. One framework per invocation, so a bad release of
# one cannot mask the other.
#
# By default every package already in the image is held at its installed version with uv's
# --override, so the framework is tested against the same dependencies as the rest of Airflow and
# its caps on them are overridden. With --framework-pins the framework's own requirements win
# instead, which is the environment a user who installs it gets.
#
# The newest framework release older than the repository's uv exclude-newer window is installed.
set -euo pipefail
TEST_PATH="providers/common/ai/tests/unit/common/ai/tools"
framework="${1:-}"
case "${framework}" in
strands-agents) import_check="import strands" ;;
google-adk) import_check="import google.adk" ;;
*)
echo "Usage: $0 <strands-agents|google-adk> [--framework-pins]" >&2
exit 1
;;
esac
framework_pins="false"
if [[ ${2:-} == "--framework-pins" ]]; then
framework_pins="true"
elif [[ -n ${2:-} ]]; then
echo "Unknown argument: ${2}. The only option after the framework is --framework-pins." >&2
exit 1
fi
cd "${AIRFLOW_SOURCES:-/opt/airflow}"
if [[ ${framework_pins} == "true" ]]; then
echo "Installing ${framework} with its own dependency pins"
uv pip install "${framework}"
else
overrides=$(mktemp)
before=$(mktemp)
after=$(mktemp)
trap 'rm -f "${overrides}" "${before}" "${after}"' EXIT
uv pip freeze | sort > "${before}"
# Only name==version lines: editable and local installs cannot be expressed as an override,
# and the frameworks do not depend on any of them. Overriding the rest means nothing the
# image ships should change; the check below is there in case something still does.
grep -E '^[A-Za-z0-9_.-]+==' "${before}" > "${overrides}"
echo "Installing ${framework}, holding the image's $(wc -l < "${overrides}") installed packages"
uv pip install --override "${overrides}" "${framework}"
uv pip freeze | sort > "${after}"
changed=$(comm -23 "${before}" "${after}")
if [[ -n ${changed} ]]; then
echo "Installing ${framework} changed packages the image already had:" >&2
echo "${changed}" >&2
exit 1
fi
fi
# Log the versions that decide whether the adapter works; the framework itself must be among them.
uv pip freeze | grep -iE '^(strands-agents|google-adk|mcp|opentelemetry-(api|sdk)|websockets|google-genai)==' \
|| { echo "${framework} is not installed after uv pip install" >&2; exit 1; }
# The adapter tests skip themselves when their framework is missing, so a broken install would
# otherwise pass as green.
python -c "${import_check}"
# --skip-db-tests: the job runs with backend "none", which has no database to set up.
pytest "${TEST_PATH}" --skip-db-tests -p no:cacheprovider --color=yes -ra