From 9e5989058f0d819ecc69986455ccccc6b0045985 Mon Sep 17 00:00:00 2001 From: roytman Date: Sat, 20 Jun 2026 23:12:37 +0300 Subject: [PATCH 1/4] test: consolidate and rename e2e runner scripts Signed-off-by: roytman --- .github/workflows/ci-pr-checks.yaml | 2 +- Makefile | 16 +++---- test/scripts/e2e-common.sh | 42 +++++++++++++++++++ test/scripts/run_e2e.sh | 29 ------------- .../scripts/test-e2e-gaie.sh | 28 ++++--------- test/scripts/test-e2e-router.sh | 17 ++++++++ 6 files changed, 77 insertions(+), 57 deletions(-) create mode 100644 test/scripts/e2e-common.sh delete mode 100755 test/scripts/run_e2e.sh rename hack/test-e2e.sh => test/scripts/test-e2e-gaie.sh (80%) create mode 100755 test/scripts/test-e2e-router.sh diff --git a/.github/workflows/ci-pr-checks.yaml b/.github/workflows/ci-pr-checks.yaml index 2afb92d737..767b4d12dc 100644 --- a/.github/workflows/ci-pr-checks.yaml +++ b/.github/workflows/ci-pr-checks.yaml @@ -450,4 +450,4 @@ jobs: E2E_LABEL_FILTER: ${{ matrix.suite.label-filter }} LOAD_VLLM_RENDER_IMAGE: ${{ matrix.suite.needs-renderer }} PULL_VLLM_RENDER_IMAGE: "false" - run: make test-e2e-scheduler-run + run: make test-e2e-router-run diff --git a/Makefile b/Makefile index 55d1359fc5..1424e39046 100644 --- a/Makefile +++ b/Makefile @@ -304,24 +304,24 @@ test-e2e-gaie-run: image-pull ## Ensure images are present, then run GAIE e2e te $(CONTAINER_RUNTIME) run $(BUILDER_RUN_FLAGS) $(BUILDER_E2E_FLAGS) \ -e EPP_IMAGE=$(GAIE_E2E_IMAGE) \ -e USE_KIND=true \ - $(BUILDER_IMAGE) ./hack/test-e2e.sh + $(BUILDER_IMAGE) ./test/scripts/test-e2e-gaie.sh .PHONY: test-e2e-gaie test-e2e-gaie: image-build-builder image-build ## Build images and run GAIE e2e tests $(MAKE) test-e2e-gaie-run -.PHONY: test-e2e-scheduler-run -test-e2e-scheduler-run: image-pull ## Ensure images are present, then run scheduler e2e tests +.PHONY: test-e2e-router-run +test-e2e-router-run: image-pull ## Ensure images are present, then run router e2e tests @printf "\033[33;1m==== Running End to End Tests ====\033[0m\n" $(CONTAINER_RUNTIME) run $(BUILDER_RUN_FLAGS) $(BUILDER_E2E_FLAGS) \ - $(BUILDER_IMAGE) ./test/scripts/run_e2e.sh + $(BUILDER_IMAGE) ./test/scripts/test-e2e-router.sh -.PHONY: test-e2e-scheduler -test-e2e-scheduler: image-build-builder image-build ## Build images and run scheduler e2e tests - $(MAKE) test-e2e-scheduler-run +.PHONY: test-e2e-router +test-e2e-router: image-build-builder image-build ## Build images and run router e2e tests + $(MAKE) test-e2e-router-run .PHONY: test-e2e -test-e2e: test-e2e-gaie test-e2e-scheduler ## Run all end-to-end tests sequentially +test-e2e: test-e2e-gaie test-e2e-router ## Run all end-to-end tests sequentially .PHONY: bench-tokenizer diff --git a/test/scripts/e2e-common.sh b/test/scripts/e2e-common.sh new file mode 100644 index 0000000000..13e8aba41e --- /dev/null +++ b/test/scripts/e2e-common.sh @@ -0,0 +1,42 @@ +# Copyright 2025 The Kubernetes Authors. +# +# Licensed 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. + +# Shared helpers for the e2e runner scripts. Source, do not execute. + +# e2e_handle_interrupt deletes the named kind cluster on Ctrl-C and exits 130. +# An empty cluster name means there is nothing to delete (the caller did not +# create a cluster it owns). E2E_KEEP_CLUSTER_ON_FAILURE=true keeps the cluster. +e2e_handle_interrupt() { + local cluster="$1" + echo "Interrupted!" + if [ -n "${cluster}" ] && [ "${E2E_KEEP_CLUSTER_ON_FAILURE:-false}" != "true" ]; then + echo "Deleting kind cluster '${cluster}'" + kind delete cluster --name "${cluster}" 2>/dev/null || true + elif [ -n "${cluster}" ]; then + echo "Keeping kind cluster '${cluster}' (E2E_KEEP_CLUSTER_ON_FAILURE=true)" + fi + exit 130 # SIGINT (Ctrl+C) +} + +# run_ginkgo_suite runs the Ginkgo e2e suite in the given package directory, +# applying E2E_LABEL_FILTER when set. +run_ginkgo_suite() { + local pkg="$1" + if [ -n "${E2E_LABEL_FILTER:-}" ]; then + echo "Label filter: ${E2E_LABEL_FILTER}" + go test -v -timeout 45m "${pkg}" -ginkgo.v -ginkgo.fail-fast "-ginkgo.label-filter=${E2E_LABEL_FILTER}" + else + go test -v -timeout 45m "${pkg}" -ginkgo.v -ginkgo.fail-fast + fi +} diff --git a/test/scripts/run_e2e.sh b/test/scripts/run_e2e.sh deleted file mode 100755 index 8f4b1d9893..0000000000 --- a/test/scripts/run_e2e.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -cleanup() { - echo "Interrupted!" - if [ "${E2E_KEEP_CLUSTER_ON_FAILURE:-false}" = "true" ]; then - echo "Keeping kind cluster 'e2e-tests' (E2E_KEEP_CLUSTER_ON_FAILURE=true)" - else - echo "Deleting kind cluster 'e2e-tests'" - kind delete cluster --name e2e-tests 2>/dev/null || true - fi - exit 130 # SIGINT (Ctrl+C) -} - -# Set trap only for interruption signals -# Normally kind cluster cleanup is done by AfterSuite -trap cleanup INT TERM - -echo "Running end to end tests" - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -if [ -n "${E2E_LABEL_FILTER:-}" ]; then - echo "Label filter: ${E2E_LABEL_FILTER}" - go test -v -timeout 45m "${DIR}/../e2e/" -ginkgo.v -ginkgo.fail-fast "-ginkgo.label-filter=${E2E_LABEL_FILTER}" -else - go test -v -timeout 45m "${DIR}/../e2e/" -ginkgo.v -ginkgo.fail-fast -fi diff --git a/hack/test-e2e.sh b/test/scripts/test-e2e-gaie.sh similarity index 80% rename from hack/test-e2e.sh rename to test/scripts/test-e2e-gaie.sh index 0c3de5bc85..d9720b4114 100755 --- a/hack/test-e2e.sh +++ b/test/scripts/test-e2e-gaie.sh @@ -18,9 +18,12 @@ set -euox pipefail DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +# shellcheck source=test/scripts/e2e-common.sh +source "${DIR}/e2e-common.sh" + EPP_IMAGE="${EPP_IMAGE:-ghcr.io/llm-d/llm-d-router-endpoint-picker:dev}" SIM_IMAGE="${VLLM_IMAGE:-ghcr.io/llm-d/llm-d-inference-sim:v0.9.2}" -MANIFEST_PATH="${MANIFEST_PATH:-${DIR}/../test/testdata/sim-deployment.yaml}" +MANIFEST_PATH="${MANIFEST_PATH:-${DIR}/../testdata/sim-deployment.yaml}" USE_KIND="${USE_KIND:-true}" KIND_NODE_IMAGE="${KIND_NODE_IMAGE:-mirror.gcr.io/kindest/node:v1.32.2}" @@ -48,18 +51,11 @@ load_images() { CLUSTER_NAME="${cluster}" ./scripts/load_image.sh "${EPP_IMAGE}" "${SIM_IMAGE}" } -cleanup() { - echo "Interrupted!" - if [ -n "${CREATED_CLUSTER}" ] && [ "${E2E_KEEP_CLUSTER_ON_FAILURE:-false}" != "true" ]; then - echo "Deleting kind cluster '${CREATED_CLUSTER}'" - kind delete cluster --name "${CREATED_CLUSTER}" 2>/dev/null || true - fi - exit 130 # SIGINT (Ctrl+C) -} - # Normally kind cluster cleanup is done by AfterSuite; this trap only fires on # interruption signals so that a Ctrl+C still cleans up the cluster we created. -trap cleanup INT TERM +# CREATED_CLUSTER is empty until we create a cluster ourselves, so an interrupt +# before then deletes nothing. +trap 'e2e_handle_interrupt "${CREATED_CLUSTER}"' INT TERM if [ "${USE_KIND}" = "true" ]; then install_kind @@ -92,11 +88,5 @@ else fi echo "Running Go e2e tests in ./test/e2e/epp/..." -if [ -n "${E2E_LABEL_FILTER:-}" ]; then - echo "Label filter: ${E2E_LABEL_FILTER}" - MANIFEST_PATH="${MANIFEST_PATH}" E2E_IMAGE="${EPP_IMAGE}" \ - go test "${DIR}/../test/e2e/epp/" -v -timeout 45m -ginkgo.v -ginkgo.fail-fast "-ginkgo.label-filter=${E2E_LABEL_FILTER}" -else - MANIFEST_PATH="${MANIFEST_PATH}" E2E_IMAGE="${EPP_IMAGE}" \ - go test "${DIR}/../test/e2e/epp/" -v -timeout 45m -ginkgo.v -ginkgo.fail-fast -fi +export MANIFEST_PATH E2E_IMAGE="${EPP_IMAGE}" +run_ginkgo_suite "${DIR}/../e2e/epp/" diff --git a/test/scripts/test-e2e-router.sh b/test/scripts/test-e2e-router.sh new file mode 100755 index 0000000000..508cf654ac --- /dev/null +++ b/test/scripts/test-e2e-router.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +set -euo pipefail + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +# shellcheck source=test/scripts/e2e-common.sh +source "${DIR}/e2e-common.sh" + +# Set trap only for interruption signals. +# Normally kind cluster cleanup is done by AfterSuite; this suite always owns its +# kind cluster, so an interrupt deletes it. +trap 'e2e_handle_interrupt "e2e-tests"' INT TERM + +echo "Running end to end tests" + +run_ginkgo_suite "${DIR}/../e2e/" From a2937effa3819729ea3c7d207d68a13a8c2a095d Mon Sep 17 00:00:00 2001 From: roytman Date: Sat, 20 Jun 2026 23:34:28 +0300 Subject: [PATCH 2/4] fix comments Signed-off-by: roytman --- test/scripts/e2e-common.sh | 2 +- test/scripts/test-e2e-router.sh | 23 ++++++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/test/scripts/e2e-common.sh b/test/scripts/e2e-common.sh index 13e8aba41e..5efd4da7a2 100644 --- a/test/scripts/e2e-common.sh +++ b/test/scripts/e2e-common.sh @@ -1,4 +1,4 @@ -# Copyright 2025 The Kubernetes Authors. +# Copyright 2026 The Kubernetes Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/test/scripts/test-e2e-router.sh b/test/scripts/test-e2e-router.sh index 508cf654ac..8bb9e2d777 100755 --- a/test/scripts/test-e2e-router.sh +++ b/test/scripts/test-e2e-router.sh @@ -1,4 +1,18 @@ -#!/bin/bash +#!/usr/bin/env bash + +# Copyright 2026 The Kubernetes Authors. +# +# Licensed 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. set -euo pipefail @@ -8,8 +22,11 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" source "${DIR}/e2e-common.sh" # Set trap only for interruption signals. -# Normally kind cluster cleanup is done by AfterSuite; this suite always owns its -# kind cluster, so an interrupt deletes it. +# Normally kind cluster cleanup is done by AfterSuite; this trap deletes the +# e2e-tests cluster on Ctrl-C. The delete is unconditional and only meaningful +# when the suite created that cluster (K8S_CONTEXT unset); when running against +# an existing context it is a no-op unless a cluster named e2e-tests happens to +# exist. trap 'e2e_handle_interrupt "e2e-tests"' INT TERM echo "Running end to end tests" From de2b57d8321e1f6a19e08c70f4ba04faaada37b2 Mon Sep 17 00:00:00 2001 From: Alexey Roytman Date: Sun, 21 Jun 2026 11:51:16 +0300 Subject: [PATCH 3/4] Update test/scripts/test-e2e-router.sh Co-authored-by: Shmuel Kallner Signed-off-by: Alexey Roytman --- test/scripts/test-e2e-router.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/scripts/test-e2e-router.sh b/test/scripts/test-e2e-router.sh index 8bb9e2d777..491cbdda3e 100755 --- a/test/scripts/test-e2e-router.sh +++ b/test/scripts/test-e2e-router.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Copyright 2026 The Kubernetes Authors. +# Copyright 2026 The llm-d Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. From acfd98c09497df8fdfffacc3102d6f705d95317d Mon Sep 17 00:00:00 2001 From: Alexey Roytman Date: Sun, 21 Jun 2026 11:51:28 +0300 Subject: [PATCH 4/4] Update test/scripts/e2e-common.sh Co-authored-by: Shmuel Kallner Signed-off-by: Alexey Roytman --- test/scripts/e2e-common.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/scripts/e2e-common.sh b/test/scripts/e2e-common.sh index 5efd4da7a2..91ab2d7854 100644 --- a/test/scripts/e2e-common.sh +++ b/test/scripts/e2e-common.sh @@ -1,4 +1,4 @@ -# Copyright 2026 The Kubernetes Authors. +# Copyright 2026 The llm-d Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License.