Skip to content
Merged
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
7 changes: 5 additions & 2 deletions e2e/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,13 @@ The following environment variables can be used to customize test execution:
| `E2E_VERBOSE` | Enable verbose logging | `true` | `make e2e-test E2E_VERBOSE=false` |
| `E2E_PARALLEL` | Run tests in parallel | `false` | `make e2e-test E2E_PARALLEL=true` |
| `E2E_TESTS` | Specific test cases to run | (all tests) | `make e2e-test-specific E2E_TESTS="test1,test2"` |
| `E2E_SETUP_ONLY` | Only setup profile without running tests | `false` | `make e2e-test E2E_SETUP_ONLY=true` |
| `E2E_SETUP_ONLY` | Only setup profile without running tests (automatically keeps cluster) | `false` | `make e2e-test E2E_SETUP_ONLY=true` |
| `E2E_SKIP_SETUP` | Skip setup and only run tests | `false` | `make e2e-test E2E_SKIP_SETUP=true` |

**Note**: When using the binary directly (`./bin/e2e`), use command-line flags instead:
**Note**:

- When `E2E_SETUP_ONLY=true` is set, the cluster is automatically kept (no need to set `E2E_KEEP_CLUSTER=true`)
- When using the binary directly (`./bin/e2e`), use command-line flags instead:

- `-profile` instead of `E2E_PROFILE`
- `-cluster` instead of `E2E_CLUSTER_NAME`
Expand Down
29 changes: 29 additions & 0 deletions e2e/cmd/e2e/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@ import (
"os"
"strings"

"github.com/vllm-project/semantic-router/e2e/pkg/banner"
"github.com/vllm-project/semantic-router/e2e/pkg/framework"
aigateway "github.com/vllm-project/semantic-router/e2e/profiles/ai-gateway"

// Import profiles to register test cases
_ "github.com/vllm-project/semantic-router/e2e/profiles/ai-gateway"
)

const version = "v1.0.0"

func main() {
// Parse command line flags
var (
Expand All @@ -31,12 +34,24 @@ func main() {

flag.Parse()

// Show banner
if isInteractive() {
banner.Show(version)
} else {
banner.ShowQuick(version)
}

// Validate flags
if *setupOnly && *skipSetup {
fmt.Fprintf(os.Stderr, "Error: --setup-only and --skip-setup cannot be used together\n")
os.Exit(1)
}

// Setup-only mode always keeps the cluster
if *setupOnly {
*keepCluster = true
}

// Parse test cases
var testCasesList []string
if *testCases != "" {
Expand Down Expand Up @@ -88,3 +103,17 @@ func getProfile(name string) (framework.Profile, error) {
return nil, fmt.Errorf("unknown profile: %s", name)
}
}

// isInteractive checks if the program is running in an interactive terminal
func isInteractive() bool {
// Check if CI environment variable is set
if os.Getenv("CI") != "" {
return false
}
// Check if stdout is a terminal
fileInfo, err := os.Stdout.Stat()
if err != nil {
return false
}
return (fileInfo.Mode() & os.ModeCharDevice) != 0
}
97 changes: 97 additions & 0 deletions e2e/pkg/banner/banner.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package banner

import (
"fmt"
"strings"
"time"
)

// Color codes
const (
Reset = "\033[0m"
Cyan = "\033[36m"
Purple = "\033[35m"
Green = "\033[32m"
Yellow = "\033[33m"
Bold = "\033[1m"
)

// ASCII art for vLLM Semantic Router
var logo = []string{
" ██╗ ██╗██╗ ██╗ ███╗ ███╗",
" ██║ ██║██║ ██║ ████╗ ████║",
" ██║ ██║██║ ██║ ██╔████╔██║",
" ╚██╗ ██╔╝██║ ██║ ██║╚██╔╝██║",
" ╚████╔╝ ███████╗███████╗██║ ╚═╝ ██║",
" ╚═══╝ ╚══════╝╚══════╝╚═╝ ╚═╝",
"",
" ███████╗███████╗███╗ ███╗ █████╗ ███╗ ██╗████████╗██╗ ██████╗",
" ██╔════╝██╔════╝████╗ ████║██╔══██╗████╗ ██║╚══██╔══╝██║██╔════╝",
" ███████╗█████╗ ██╔████╔██║███████║██╔██╗ ██║ ██║ ██║██║ ",
" ╚════██║██╔══╝ ██║╚██╔╝██║██╔══██║██║╚██╗██║ ██║ ██║██║ ",
" ███████║███████╗██║ ╚═╝ ██║██║ ██║██║ ╚████║ ██║ ██║╚██████╗",
" ╚══════╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═════╝",
"",
" ██████╗ ██████╗ ██╗ ██╗████████╗███████╗██████╗",
" ██╔══██╗██╔═══██╗██║ ██║╚══██╔══╝██╔════╝██╔══██╗",
" ██████╔╝██║ ██║██║ ██║ ██║ █████╗ ██████╔╝",
" ██╔══██╗██║ ██║██║ ██║ ██║ ██╔══╝ ██╔══██╗",
" ██║ ██║╚██████╔╝╚██████╔╝ ██║ ███████╗██║ ██║",
" ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═╝",
}

// Show displays the animated banner
func Show(version string) {
fmt.Println()
fmt.Println()

// Animate logo line by line
for _, line := range logo {
fmt.Printf("%s%s%s%s\n", Bold, Cyan, line, Reset)
time.Sleep(30 * time.Millisecond)
}

fmt.Println()

// Show version and info with animation
info := []string{
fmt.Sprintf("%s%s E2E Testing Framework%s", Bold, Purple, Reset),
fmt.Sprintf("%s Version: %s%s", Yellow, version, Reset),
"",
}

for _, line := range info {
fmt.Println(line)
time.Sleep(50 * time.Millisecond)
}

// Loading animation
loadingChars := []string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"}
fmt.Print(Green + " Initializing" + Reset)
for i := 0; i < 15; i++ {
fmt.Printf("\r%s Initializing %s%s", Green, loadingChars[i%len(loadingChars)], Reset)
time.Sleep(80 * time.Millisecond)
}
fmt.Printf("\r%s Initializing ✓%s\n", Green, Reset)

fmt.Println()
fmt.Println(strings.Repeat("═", 80))
fmt.Println()
}

// ShowQuick displays a quick version without animation (for CI/non-interactive)
func ShowQuick(version string) {
fmt.Println()
fmt.Println()

for _, line := range logo {
fmt.Printf("%s%s%s%s\n", Bold, Cyan, line, Reset)
}

fmt.Println()
fmt.Printf("%s%s E2E Testing Framework%s\n", Bold, Purple, Reset)
fmt.Printf("%s Version: %s%s\n", Yellow, version, Reset)
fmt.Println()
fmt.Println(strings.Repeat("═", 80))
fmt.Println()
}
21 changes: 12 additions & 9 deletions e2e/pkg/framework/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,15 +129,18 @@ func (r *Runner) Run(ctx context.Context) error {
return fmt.Errorf("failed to setup profile: %w", err)
}

defer func() {
teardownOpts := &TeardownOptions{
KubeClient: kubeClient,
KubeConfig: kubeConfig,
ClusterName: r.opts.ClusterName,
Verbose: r.opts.Verbose,
}
r.profile.Teardown(context.Background(), teardownOpts)
}()
// Only register teardown if not in setup-only mode
if !r.opts.SetupOnly {
defer func() {
teardownOpts := &TeardownOptions{
KubeClient: kubeClient,
KubeConfig: kubeConfig,
ClusterName: r.opts.ClusterName,
Verbose: r.opts.Verbose,
}
r.profile.Teardown(context.Background(), teardownOpts)
}()
}
} else {
r.log("⏭️ Skipping profile setup (--skip-setup enabled)")
}
Expand Down
4 changes: 2 additions & 2 deletions e2e/testcases/chat_completions_progressive_stress.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ type ProgressiveStageResult struct {

func testProgressiveStress(ctx context.Context, client *kubernetes.Clientset, opts pkgtestcases.TestCaseOptions) error {
if opts.Verbose {
fmt.Println("[Test] Starting progressive stress test: 10/20 concurrent requests")
fmt.Println("[Test] Starting progressive stress test: 10/20/50 concurrent requests")
}

// Setup service connection and get local port
Expand All @@ -45,7 +45,7 @@ func testProgressiveStress(ctx context.Context, client *kubernetes.Clientset, op
defer stopPortForward()

// Define concurrent request counts for each stage
concurrencyStages := []int{10, 20}
concurrencyStages := []int{10, 20, 50}

var stageResults []ProgressiveStageResult

Expand Down
26 changes: 3 additions & 23 deletions tools/make/e2e.mk
Original file line number Diff line number Diff line change
Expand Up @@ -53,33 +53,13 @@ e2e-test-debug: e2e-test
# Setup profile only without running tests
e2e-setup: ## Setup profile only without running tests
e2e-setup: E2E_SETUP_ONLY=true
e2e-setup: E2E_KEEP_CLUSTER=true
e2e-setup: build-e2e
@$(LOG_TARGET)
@echo "Setting up E2E environment with profile: $(E2E_PROFILE)"
@./bin/e2e \
-profile=$(E2E_PROFILE) \
-cluster=$(E2E_CLUSTER_NAME) \
-image-tag=$(E2E_IMAGE_TAG) \
-keep-cluster=true \
-verbose=$(E2E_VERBOSE) \
-setup-only=true
e2e-setup: e2e-test

# Run tests only without setup (assumes environment is already deployed)
e2e-test-only: ## Run tests only without setup (assumes environment is already deployed)
e2e-test-only: E2E_SKIP_SETUP=true
e2e-test-only: E2E_USE_EXISTING_CLUSTER=true
e2e-test-only: build-e2e
@$(LOG_TARGET)
@echo "Running E2E tests (skip setup) with profile: $(E2E_PROFILE)"
@./bin/e2e \
-profile=$(E2E_PROFILE) \
-cluster=$(E2E_CLUSTER_NAME) \
-use-existing-cluster=true \
-verbose=$(E2E_VERBOSE) \
-parallel=$(E2E_PARALLEL) \
-skip-setup=true \
$(if $(E2E_TESTS),-tests=$(E2E_TESTS),)
e2e-test-only: E2E_SKIP_SETUP=true
e2e-test-only: e2e-test

# Run specific E2E test cases
e2e-test-specific: ## Run specific E2E test cases (E2E_TESTS="test1,test2")
Expand Down
Loading