Merge pull request #114 from dminnear-rh/fix-chart-lock #5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |