Skip to content

Merge pull request #114 from dminnear-rh/fix-chart-lock #5

Merge pull request #114 from dminnear-rh/fix-chart-lock

Merge pull request #114 from dminnear-rh/fix-chart-lock #5

Workflow file for this run

name: E2E Tests
on:
pull_request:
branches:
- main
paths:
- 'frontend/**'
- 'deploy/helm/**'
- 'tests/**'
- '.github/workflows/e2e-tests.yaml'
push:
branches:
- main
workflow_dispatch:
# MaaS configuration - can be overridden with repository secrets for different environments
env:
MAAS_ENDPOINT: "https://llama-3-2-3b-maas-apicast-production.apps.prod.rhoai.rh-aiservices-bu.com:443/v1"
MAAS_MODEL_ID: "llama-3-2-3b"
# MAAS_API_KEY is passed as a secret in the helm install step
jobs:
unit-tests:
name: Unit Tests
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install unit test dependencies
run: |
pip install -r tests/unit/requirements.txt
- name: Run unit tests
run: |
pytest tests/unit/ -v --tb=short --cov=frontend --cov-report=term-missing
- name: Upload unit test results
if: always()
uses: actions/upload-artifact@v4
with:
name: unit-test-results
path: |
.coverage
htmlcov/
integration-tests:
name: Integration Tests (Streamlit App)
runs-on: ubuntu-latest
timeout-minutes: 15
needs: unit-tests
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install integration test dependencies
run: |
pip install -r tests/integration/requirements.txt
- name: Run integration tests
run: |
pytest tests/integration/test_*.py -v --tb=short
- name: Upload integration test results
if: always()
uses: actions/upload-artifact@v4
with:
name: integration-test-results
path: pytest-results/
llamastack-integration-tests:
name: LlamaStack Integration Tests
runs-on: ubuntu-latest
timeout-minutes: 60
needs: unit-tests
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install test dependencies
run: |
pip install -r tests/integration/llamastack/requirements.txt
- name: Create Kind cluster config file
run: |
cat <<EOF > kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 30080
hostPort: 8501
protocol: TCP
- containerPort: 30081
hostPort: 8321
protocol: TCP
EOF
- name: Create Kind cluster
uses: helm/kind-action@v1
with:
cluster_name: rag-e2e
config: kind-config.yaml
- name: Install Required CRDs
run: |
echo "Installing CRDs required by helm chart subcomponents..."
# OpenShift Route CRD
kubectl apply -f - <<EOF
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: routes.route.openshift.io
spec:
group: route.openshift.io
names:
kind: Route
listKind: RouteList
plural: routes
singular: route
scope: Namespaced
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
x-kubernetes-preserve-unknown-fields: true
EOF
# KServe InferenceService CRD
kubectl apply -f - <<EOF
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: inferenceservices.serving.kserve.io
spec:
group: serving.kserve.io
names:
kind: InferenceService
listKind: InferenceServiceList
plural: inferenceservices
singular: inferenceservice
scope: Namespaced
versions:
- name: v1beta1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
x-kubernetes-preserve-unknown-fields: true
EOF
# KServe ServingRuntime CRD
kubectl apply -f - <<EOF
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: servingruntimes.serving.kserve.io
spec:
group: serving.kserve.io
names:
kind: ServingRuntime
listKind: ServingRuntimeList
plural: servingruntimes
singular: servingruntime
scope: Namespaced
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
x-kubernetes-preserve-unknown-fields: true
EOF
# OpenDataHub DataSciencePipelinesApplication CRD
kubectl apply -f - <<EOF
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: datasciencepipelinesapplications.datasciencepipelinesapplications.opendatahub.io
spec:
group: datasciencepipelinesapplications.opendatahub.io
names:
kind: DataSciencePipelinesApplication
listKind: DataSciencePipelinesApplicationList
plural: datasciencepipelinesapplications
singular: datasciencepipelinesapplication
scope: Namespaced
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
x-kubernetes-preserve-unknown-fields: true
EOF
# Kubeflow Notebook CRD
kubectl apply -f - <<EOF
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: notebooks.kubeflow.org
spec:
group: kubeflow.org
names:
kind: Notebook
listKind: NotebookList
plural: notebooks
singular: notebook
scope: Namespaced
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
x-kubernetes-preserve-unknown-fields: true
EOF
echo "Waiting for all CRDs to be established..."
kubectl wait --for condition=established --timeout=60s crd/routes.route.openshift.io
kubectl wait --for condition=established --timeout=60s crd/inferenceservices.serving.kserve.io
kubectl wait --for condition=established --timeout=60s crd/servingruntimes.serving.kserve.io
kubectl wait --for condition=established --timeout=60s crd/datasciencepipelinesapplications.datasciencepipelinesapplications.opendatahub.io
kubectl wait --for condition=established --timeout=60s crd/notebooks.kubeflow.org
echo "✅ All required CRDs installed successfully"
- name: Verify cluster
run: |
kubectl cluster-info
kubectl get nodes
kubectl get pods -A
kubectl get crds | grep route || echo "Route CRD check"
- name: Add Helm repository
run: |
helm repo add rag-charts https://rh-ai-quickstart.github.io/ai-architecture-charts
helm repo update
- name: Build Helm dependencies
run: |
cd deploy/helm/rag
helm dependency build
- name: Display MaaS configuration
run: |
echo "========================================="
echo "MaaS Configuration (Public)"
echo "========================================="
echo "Model ID: ${MAAS_MODEL_ID}"
echo "Endpoint: ${MAAS_ENDPOINT}"
echo "========================================="
- name: Validate MaaS API key
env:
MAAS_API_KEY: ${{ secrets.MAAS_API_KEY }}
run: |
# Check if MAAS_API_KEY secret is set
if [ -z "${MAAS_API_KEY}" ]; then
echo ""
echo "❌ ERROR: MAAS_API_KEY secret is not configured!"
echo ""
echo "To fix this, add the MAAS_API_KEY secret to your repository:"
echo "1. Go to: Settings > Secrets and variables > Actions"
echo "2. Click 'New repository secret'"
echo "3. Name: MAAS_API_KEY"
echo "4. Value: Your Red Hat MaaS API key"
echo ""
echo "For more information, see:"
echo "https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions"
echo ""
exit 1
fi
echo "✅ MaaS API key is configured"
- name: Install RAG application with MaaS
env:
MAAS_API_KEY: ${{ secrets.MAAS_API_KEY }}
run: |
# Create namespace
kubectl create namespace rag-e2e || true
echo "========================================="
echo "Installing RAG application with MaaS"
echo "========================================="
echo "Using model: ${MAAS_MODEL_ID}"
echo "Helm chart: deploy/helm/rag"
echo "Namespace: rag-e2e"
echo "Values: tests/e2e/values-e2e.yaml"
echo "========================================="
# Install the chart with e2e values
# Override MaaS configuration from environment variables
# Note: All MaaS settings (endpoint, model ID, API key) passed via --set
# Some values may appear as *** in logs due to GitHub Actions secret masking
helm install rag deploy/helm/rag \
--namespace rag-e2e \
--values tests/e2e/values-e2e.yaml \
--set global.models.${MAAS_MODEL_ID}.url="${MAAS_ENDPOINT}" \
--set global.models.${MAAS_MODEL_ID}.id="${MAAS_MODEL_ID}" \
--set global.models.${MAAS_MODEL_ID}.enabled=true \
--set global.models.${MAAS_MODEL_ID}.apiToken="${MAAS_API_KEY}" \
--set-json llama-stack.initContainers='[]' \
--skip-crds \
--timeout 20m \
--debug
- name: Wait for core services to be ready
run: |
echo "========================================="
echo "Listing all resources in namespace..."
echo "========================================="
kubectl get all -n rag-e2e
echo ""
echo "========================================="
echo "Checking deployments..."
echo "========================================="
kubectl get deployments -n rag-e2e -o wide
echo ""
echo "========================================="
echo "Checking pods..."
echo "========================================="
kubectl get pods -n rag-e2e -o wide
echo ""
echo "========================================="
echo "Waiting for Llama Stack deployment (10min timeout)..."
echo "========================================="
kubectl wait --for=condition=available --timeout=600s \
deployment/llamastack -n rag-e2e || {
echo "❌ Llama Stack deployment failed to become available"
echo "Pod status:"
kubectl get pods -l app.kubernetes.io/name=llamastack -n rag-e2e
echo "Pod logs:"
kubectl logs -l app.kubernetes.io/name=llamastack -n rag-e2e --tail=100
exit 1
}
echo ""
echo "========================================="
echo "Waiting for RAG UI deployment (5min timeout)..."
echo "========================================="
kubectl wait --for=condition=available --timeout=300s \
deployment/rag -n rag-e2e || {
echo "❌ RAG UI deployment failed to become available"
echo "Pod status:"
kubectl get pods -l app.kubernetes.io/name=rag -n rag-e2e
echo "Pod logs:"
kubectl logs -l app.kubernetes.io/name=rag -n rag-e2e --tail=100
exit 1
}
echo ""
echo "========================================="
echo "Waiting for pods to be ready..."
echo "========================================="
kubectl wait --for=condition=ready --timeout=600s \
pod -l app.kubernetes.io/name=llamastack -n rag-e2e
kubectl wait --for=condition=ready --timeout=300s \
pod -l app.kubernetes.io/name=rag -n rag-e2e
echo ""
echo "========================================="
echo "✅ ALL CORE SERVICES ARE READY!"
echo "========================================="
kubectl get pods -n rag-e2e -o wide
- name: Expose services via NodePort
run: |
# Expose RAG UI
kubectl patch service rag -n rag-e2e -p '{"spec":{"type":"NodePort","ports":[{"port":8501,"nodePort":30080}]}}'
# Expose Llama Stack
kubectl patch service llamastack -n rag-e2e -p '{"spec":{"type":"NodePort","ports":[{"port":8321,"nodePort":30081}]}}'
# Verify services
kubectl get services -n rag-e2e
- name: Port forward services
run: |
# Start port forwarding in background
kubectl port-forward -n rag-e2e svc/rag 8501:8501 &
kubectl port-forward -n rag-e2e svc/llamastack 8321:8321 &
# Wait for port forwarding to establish
sleep 10
- name: Run LlamaStack integration tests with MaaS inference
env:
LLAMA_STACK_ENDPOINT: http://localhost:8321
RAG_UI_ENDPOINT: http://localhost:8501
INFERENCE_MODEL: ${{ env.MAAS_MODEL_ID }}
SKIP_MODEL_TESTS: "false" # Enable inference tests with MaaS
run: |
echo "Starting LlamaStack integration tests with MaaS-enabled inference..."
echo "Model: ${INFERENCE_MODEL}"
echo "MaaS Endpoint: ${MAAS_ENDPOINT}"
pytest tests/integration/llamastack/ -v --tb=short
- name: Debug - Get pod logs on failure
if: failure()
run: |
echo "=== Deployment status ==="
kubectl get deployments -n rag-e2e
echo "=== Pod status ==="
kubectl get pods -n rag-e2e -o wide
echo "=== Service status ==="
kubectl get services -n rag-e2e
echo "=== Events ==="
kubectl get events -n rag-e2e --sort-by='.lastTimestamp'
echo "=== RAG UI logs ==="
kubectl logs -l app.kubernetes.io/name=rag -n rag-e2e --tail=200 || echo "No RAG UI logs available"
echo "=== Llama Stack logs (CRITICAL - Check model registration) ==="
kubectl logs -l app.kubernetes.io/name=llamastack -n rag-e2e --tail=300 || echo "No Llama Stack logs available"
echo "=== Llama Stack pod details ==="
kubectl describe pod -l app.kubernetes.io/name=llamastack -n rag-e2e || echo "No pod details"
echo "=== PGVector logs ==="
kubectl logs -l app.kubernetes.io/name=pgvector -n rag-e2e --tail=100 || echo "No PGVector logs available"
echo "=== MinIO logs ==="
kubectl logs -l app.kubernetes.io/name=minio -n rag-e2e --tail=100 || echo "No MinIO logs available"
echo "=== Ingestion Pipeline logs (if enabled) ==="
kubectl logs -l app.kubernetes.io/name=ingestion-pipeline -n rag-e2e --tail=100 || echo "No ingestion pipeline logs"
- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: llamastack-integration-test-results
path: pytest-results/
- name: Cleanup
if: always()
run: |
# Kill port-forward processes
pkill -f "kubectl port-forward" || true
# Optional: Uncomment to delete cluster
# kind delete cluster --name rag-e2e
ui-e2e-tests:
name: UI E2E Tests (Playwright)
runs-on: ubuntu-latest
timeout-minutes: 60
needs: [unit-tests, integration-tests]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install UI test dependencies
run: |
pip install -r tests/e2e_ui/requirements.txt
- name: Install Playwright browsers
run: |
playwright install chromium
- name: Create Kind cluster config file
run: |
cat <<EOF > kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 30080
hostPort: 8501
protocol: TCP
- containerPort: 30081
hostPort: 8321
protocol: TCP
EOF
- name: Create Kind cluster
uses: helm/kind-action@v1
with:
cluster_name: rag-e2e-ui
config: kind-config.yaml
- name: Install Required CRDs
run: |
echo "Installing CRDs required by helm chart subcomponents..."
# OpenShift Route CRD
kubectl apply -f - <<EOF
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: routes.route.openshift.io
spec:
group: route.openshift.io
names:
kind: Route
listKind: RouteList
plural: routes
singular: route
scope: Namespaced
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
x-kubernetes-preserve-unknown-fields: true
EOF
kubectl wait --for condition=established --timeout=60s crd/routes.route.openshift.io
echo "✅ All required CRDs installed successfully"
- name: Add Helm repository
run: |
helm repo add rag-charts https://rh-ai-quickstart.github.io/ai-architecture-charts
helm repo update
- name: Build Helm dependencies
run: |
cd deploy/helm/rag
helm dependency build
- name: Install RAG application
env:
MAAS_API_KEY: ${{ secrets.MAAS_API_KEY }}
run: |
kubectl create namespace rag-e2e-ui || true
helm install rag deploy/helm/rag \
--namespace rag-e2e-ui \
--values tests/e2e/values-e2e.yaml \
--set global.models.${MAAS_MODEL_ID}.url="${MAAS_ENDPOINT}" \
--set global.models.${MAAS_MODEL_ID}.id="${MAAS_MODEL_ID}" \
--set global.models.${MAAS_MODEL_ID}.enabled=true \
--set global.models.${MAAS_MODEL_ID}.apiToken="${MAAS_API_KEY}" \
--set-json llama-stack.initContainers='[]' \
--skip-crds \
--timeout 20m \
--debug
- name: Wait for services to be ready
run: |
kubectl wait --for=condition=available --timeout=600s \
deployment/llamastack -n rag-e2e-ui
kubectl wait --for=condition=available --timeout=300s \
deployment/rag -n rag-e2e-ui
- name: Expose services via NodePort
run: |
kubectl patch service rag -n rag-e2e-ui -p '{"spec":{"type":"NodePort","ports":[{"port":8501,"nodePort":30080}]}}'
kubectl patch service llamastack -n rag-e2e-ui -p '{"spec":{"type":"NodePort","ports":[{"port":8321,"nodePort":30081}]}}'
- name: Port forward services
run: |
kubectl port-forward -n rag-e2e-ui svc/rag 8501:8501 &
kubectl port-forward -n rag-e2e-ui svc/llamastack 8321:8321 &
sleep 10
- name: Run UI E2E tests with Playwright
env:
RAG_UI_ENDPOINT: http://localhost:8501
LLAMA_STACK_ENDPOINT: http://localhost:8321
MAAS_ENDPOINT: ${{ env.MAAS_ENDPOINT }}
MAAS_MODEL_ID: ${{ env.MAAS_MODEL_ID }}
SKIP_MODEL_TESTS: "false" # Enable MaaS inference tests in UI
run: |
echo "Running UI E2E tests with MaaS integration..."
echo "MaaS Endpoint: ${MAAS_ENDPOINT}"
echo "MaaS Model ID: ${MAAS_MODEL_ID}"
pytest tests/e2e_ui/ -v --tb=short --browser chromium
- name: Upload Playwright test results
if: always()
uses: actions/upload-artifact@v4
with:
name: playwright-test-results
path: |
test-results/
playwright-report/
- name: Upload Playwright screenshots
if: failure()
uses: actions/upload-artifact@v4
with:
name: playwright-screenshots
path: test-results/
- name: Debug - Get pod logs on failure
if: failure()
run: |
echo "=== RAG UI logs ==="
kubectl logs -l app.kubernetes.io/name=rag -n rag-e2e-ui --tail=200 || echo "No RAG UI logs"
echo "=== Llama Stack logs ==="
kubectl logs -l app.kubernetes.io/name=llamastack -n rag-e2e-ui --tail=300 || echo "No Llama Stack logs"
- name: Cleanup UI tests
if: always()
run: |
pkill -f "kubectl port-forward" || true
# kind delete cluster --name rag-e2e-ui