From 82b3000ea04aaaa76924c5b3cf840d9f38de763d Mon Sep 17 00:00:00 2001 From: Ivan Shymko Date: Fri, 30 Jan 2026 15:22:33 +0000 Subject: [PATCH 1/4] Run tests and linter --- .github/workflows/linter.yaml | 2 +- .github/workflows/unit-tests.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/linter.yaml b/.github/workflows/linter.yaml index bdd4c5b8b..f71d66b9c 100644 --- a/.github/workflows/linter.yaml +++ b/.github/workflows/linter.yaml @@ -2,7 +2,7 @@ name: Lint Code Base on: pull_request: - branches: [main] + branches: [main, "ishymko/tests-base"] permissions: contents: read jobs: diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 16052ba19..597b91e4b 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -2,7 +2,7 @@ name: Run Unit Tests on: pull_request: - branches: [main] + branches: [main, "ishymko/tests-base"] permissions: contents: read jobs: From 686668c4f47584252f4d83789315ad588ec88cb2 Mon Sep 17 00:00:00 2001 From: Ivan Shymko Date: Fri, 30 Jan 2026 17:32:26 +0100 Subject: [PATCH 2/4] test: add script to run DB integration tests locally (#653) Based on [`unit-tests.yml`](https://github.com/a2aproject/a2a-python/blob/main/.github/workflows/unit-tests.yml). Supports: - `--debug` to start DB(s) without running tests (for selective running in IDE) - `--mysql`, `--postgres` to use only one DB - `--stop` to stop after running with `--debug` From project root: ```bash ./scripts/run_integration_tests.sh ``` Re #652 to troubleshoot failures --- .github/actions/spelling/allow.txt | 2 + scripts/docker-compose.test.yml | 29 ++++++++ scripts/run_integration_tests.sh | 102 +++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+) create mode 100644 scripts/docker-compose.test.yml create mode 100755 scripts/run_integration_tests.sh diff --git a/.github/actions/spelling/allow.txt b/.github/actions/spelling/allow.txt index a016962ca..bda9f9dca 100644 --- a/.github/actions/spelling/allow.txt +++ b/.github/actions/spelling/allow.txt @@ -58,6 +58,7 @@ Llm lstrips mikeas mockurl +mysqladmin notif oauthoidc oidc @@ -66,6 +67,7 @@ otherurl postgres POSTGRES postgresql +proot protoc pyi pypistats diff --git a/scripts/docker-compose.test.yml b/scripts/docker-compose.test.yml new file mode 100644 index 000000000..a2df936e1 --- /dev/null +++ b/scripts/docker-compose.test.yml @@ -0,0 +1,29 @@ +services: + postgres: + image: postgres:15-alpine + environment: + POSTGRES_USER: a2a + POSTGRES_PASSWORD: a2a_password + POSTGRES_DB: a2a_test + ports: + - "5432:5432" + healthcheck: + test: ["CMD-SHELL", "pg_isready"] + interval: 10s + timeout: 5s + retries: 5 + + mysql: + image: mysql:8.0 + environment: + MYSQL_ROOT_PASSWORD: root + MYSQL_DATABASE: a2a_test + MYSQL_USER: a2a + MYSQL_PASSWORD: a2a_password + ports: + - "3306:3306" + healthcheck: + test: ["CMD-SHELL", "mysqladmin ping -h localhost -u root -proot"] + interval: 10s + timeout: 5s + retries: 5 diff --git a/scripts/run_integration_tests.sh b/scripts/run_integration_tests.sh new file mode 100755 index 000000000..5b9767136 --- /dev/null +++ b/scripts/run_integration_tests.sh @@ -0,0 +1,102 @@ +#!/bin/bash +set -e + +# Get the directory of this script +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" + +# Docker compose file path +COMPOSE_FILE="$SCRIPT_DIR/docker-compose.test.yml" + +# Initialize variables +DEBUG_MODE=false +STOP_MODE=false +SERVICES=() +PYTEST_ARGS=() + +# Parse arguments +while [[ $# -gt 0 ]]; do + case $1 in + --debug) + DEBUG_MODE=true + shift + ;; + --stop) + STOP_MODE=true + shift + ;; + --postgres) + SERVICES+=("postgres") + shift + ;; + --mysql) + SERVICES+=("mysql") + shift + ;; + *) + # Preserve other arguments for pytest + PYTEST_ARGS+=("$1") + shift + ;; + esac +done + +# Handle --stop +if [[ "$STOP_MODE" == "true" ]]; then + echo "Stopping test databases..." + docker compose -f "$COMPOSE_FILE" down + exit 0 +fi + +# Default to running both databases if none specified +if [[ ${#SERVICES[@]} -eq 0 ]]; then + SERVICES=("postgres" "mysql") +fi + +# Cleanup function to stop docker containers +cleanup() { + echo "Stopping test databases..." + docker compose -f "$COMPOSE_FILE" down +} + +# Start the databases +echo "Starting/Verifying databases: ${SERVICES[*]}..." +docker compose -f "$COMPOSE_FILE" up -d --wait "${SERVICES[@]}" + +# Set up environment variables based on active services +# Only export DSNs for started services so tests skip missing ones +for service in "${SERVICES[@]}"; do + if [[ "$service" == "postgres" ]]; then + export POSTGRES_TEST_DSN="postgresql+asyncpg://a2a:a2a_password@localhost:5432/a2a_test" + elif [[ "$service" == "mysql" ]]; then + export MYSQL_TEST_DSN="mysql+aiomysql://a2a:a2a_password@localhost:3306/a2a_test" + fi +done + +# Handle --debug mode +if [[ "$DEBUG_MODE" == "true" ]]; then + echo "---------------------------------------------------" + echo "Debug mode enabled. Databases are running." + echo "You can connect to them using the following DSNs." + echo "" + echo "Run the following commands to set up your environment:" + echo "" + [[ -n "$POSTGRES_TEST_DSN" ]] && echo "export POSTGRES_TEST_DSN=\"$POSTGRES_TEST_DSN\"" + [[ -n "$MYSQL_TEST_DSN" ]] && echo "export MYSQL_TEST_DSN=\"$MYSQL_TEST_DSN\"" + echo "" + echo "---------------------------------------------------" + echo "Run ./scripts/run_integration_tests.sh --stop to shut databases down." + exit 0 +fi + +# Register cleanup trap for normal test run +trap cleanup EXIT + +# Run the tests +echo "Running integration tests..." +cd "$PROJECT_ROOT" + +uv run --extra all pytest -v \ + tests/server/tasks/test_database_task_store.py \ + tests/server/tasks/test_database_push_notification_config_store.py \ + "${PYTEST_ARGS[@]}" From 9b539e6ebfc00c23bee1faf0bdce149bc3c3e34b Mon Sep 17 00:00:00 2001 From: Ivan Shymko Date: Sat, 31 Jan 2026 15:05:03 +0000 Subject: [PATCH 3/4] fix: use MySQL compatible ordering for listing tasks --- src/a2a/server/tasks/database_task_store.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/a2a/server/tasks/database_task_store.py b/src/a2a/server/tasks/database_task_store.py index 2ec02831c..1605c601a 100644 --- a/src/a2a/server/tasks/database_task_store.py +++ b/src/a2a/server/tasks/database_task_store.py @@ -189,8 +189,10 @@ async def list( count_stmt = select(func.count()).select_from(base_stmt.alias()) total_count = (await session.execute(count_stmt)).scalar_one() + # Use coalesce to treat NULL timestamps as empty strings, + # which sort last in descending order stmt = base_stmt.order_by( - timestamp_col.desc().nulls_last(), + func.coalesce(timestamp_col, '').desc(), self.task_model.id.desc(), ) From 4a1e918170a572a77632d4360a8e36656be733a6 Mon Sep 17 00:00:00 2001 From: Ivan Shymko Date: Mon, 2 Feb 2026 07:54:46 +0000 Subject: [PATCH 4/4] Revert "test: add script to run DB integration tests locally (#653)" This reverts commit 9dad851127995fb92860febef7deadc0ad79e294. --- .github/actions/spelling/allow.txt | 2 - .github/workflows/linter.yaml | 2 +- .github/workflows/unit-tests.yml | 2 +- scripts/docker-compose.test.yml | 29 -------- scripts/run_integration_tests.sh | 102 ----------------------------- 5 files changed, 2 insertions(+), 135 deletions(-) delete mode 100644 scripts/docker-compose.test.yml delete mode 100755 scripts/run_integration_tests.sh diff --git a/.github/actions/spelling/allow.txt b/.github/actions/spelling/allow.txt index bda9f9dca..a016962ca 100644 --- a/.github/actions/spelling/allow.txt +++ b/.github/actions/spelling/allow.txt @@ -58,7 +58,6 @@ Llm lstrips mikeas mockurl -mysqladmin notif oauthoidc oidc @@ -67,7 +66,6 @@ otherurl postgres POSTGRES postgresql -proot protoc pyi pypistats diff --git a/.github/workflows/linter.yaml b/.github/workflows/linter.yaml index f71d66b9c..bdd4c5b8b 100644 --- a/.github/workflows/linter.yaml +++ b/.github/workflows/linter.yaml @@ -2,7 +2,7 @@ name: Lint Code Base on: pull_request: - branches: [main, "ishymko/tests-base"] + branches: [main] permissions: contents: read jobs: diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 597b91e4b..7dee3e0a6 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -2,7 +2,7 @@ name: Run Unit Tests on: pull_request: - branches: [main, "ishymko/tests-base"] + branches: [main, 1.0-dev] permissions: contents: read jobs: diff --git a/scripts/docker-compose.test.yml b/scripts/docker-compose.test.yml deleted file mode 100644 index a2df936e1..000000000 --- a/scripts/docker-compose.test.yml +++ /dev/null @@ -1,29 +0,0 @@ -services: - postgres: - image: postgres:15-alpine - environment: - POSTGRES_USER: a2a - POSTGRES_PASSWORD: a2a_password - POSTGRES_DB: a2a_test - ports: - - "5432:5432" - healthcheck: - test: ["CMD-SHELL", "pg_isready"] - interval: 10s - timeout: 5s - retries: 5 - - mysql: - image: mysql:8.0 - environment: - MYSQL_ROOT_PASSWORD: root - MYSQL_DATABASE: a2a_test - MYSQL_USER: a2a - MYSQL_PASSWORD: a2a_password - ports: - - "3306:3306" - healthcheck: - test: ["CMD-SHELL", "mysqladmin ping -h localhost -u root -proot"] - interval: 10s - timeout: 5s - retries: 5 diff --git a/scripts/run_integration_tests.sh b/scripts/run_integration_tests.sh deleted file mode 100755 index 5b9767136..000000000 --- a/scripts/run_integration_tests.sh +++ /dev/null @@ -1,102 +0,0 @@ -#!/bin/bash -set -e - -# Get the directory of this script -SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) -PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" - -# Docker compose file path -COMPOSE_FILE="$SCRIPT_DIR/docker-compose.test.yml" - -# Initialize variables -DEBUG_MODE=false -STOP_MODE=false -SERVICES=() -PYTEST_ARGS=() - -# Parse arguments -while [[ $# -gt 0 ]]; do - case $1 in - --debug) - DEBUG_MODE=true - shift - ;; - --stop) - STOP_MODE=true - shift - ;; - --postgres) - SERVICES+=("postgres") - shift - ;; - --mysql) - SERVICES+=("mysql") - shift - ;; - *) - # Preserve other arguments for pytest - PYTEST_ARGS+=("$1") - shift - ;; - esac -done - -# Handle --stop -if [[ "$STOP_MODE" == "true" ]]; then - echo "Stopping test databases..." - docker compose -f "$COMPOSE_FILE" down - exit 0 -fi - -# Default to running both databases if none specified -if [[ ${#SERVICES[@]} -eq 0 ]]; then - SERVICES=("postgres" "mysql") -fi - -# Cleanup function to stop docker containers -cleanup() { - echo "Stopping test databases..." - docker compose -f "$COMPOSE_FILE" down -} - -# Start the databases -echo "Starting/Verifying databases: ${SERVICES[*]}..." -docker compose -f "$COMPOSE_FILE" up -d --wait "${SERVICES[@]}" - -# Set up environment variables based on active services -# Only export DSNs for started services so tests skip missing ones -for service in "${SERVICES[@]}"; do - if [[ "$service" == "postgres" ]]; then - export POSTGRES_TEST_DSN="postgresql+asyncpg://a2a:a2a_password@localhost:5432/a2a_test" - elif [[ "$service" == "mysql" ]]; then - export MYSQL_TEST_DSN="mysql+aiomysql://a2a:a2a_password@localhost:3306/a2a_test" - fi -done - -# Handle --debug mode -if [[ "$DEBUG_MODE" == "true" ]]; then - echo "---------------------------------------------------" - echo "Debug mode enabled. Databases are running." - echo "You can connect to them using the following DSNs." - echo "" - echo "Run the following commands to set up your environment:" - echo "" - [[ -n "$POSTGRES_TEST_DSN" ]] && echo "export POSTGRES_TEST_DSN=\"$POSTGRES_TEST_DSN\"" - [[ -n "$MYSQL_TEST_DSN" ]] && echo "export MYSQL_TEST_DSN=\"$MYSQL_TEST_DSN\"" - echo "" - echo "---------------------------------------------------" - echo "Run ./scripts/run_integration_tests.sh --stop to shut databases down." - exit 0 -fi - -# Register cleanup trap for normal test run -trap cleanup EXIT - -# Run the tests -echo "Running integration tests..." -cd "$PROJECT_ROOT" - -uv run --extra all pytest -v \ - tests/server/tasks/test_database_task_store.py \ - tests/server/tasks/test_database_push_notification_config_store.py \ - "${PYTEST_ARGS[@]}"