diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml index d03e7db..472e470 100644 --- a/.gitea/workflows/build.yaml +++ b/.gitea/workflows/build.yaml @@ -71,7 +71,100 @@ jobs: docker push "${IMAGE}:${{ steps.sha.outputs.short_sha }}" echo "Pushed: ${IMAGE}:${{ steps.sha.outputs.short_sha }}" - - name: Prune unused images and cleanup + - name: Install kubectl + run: | + apt-get update + apt-get install -y kubectl + + - name: Setup kubeconfig for Tekton + run: | + mkdir -p ~/.kube + echo "${KUBECONFIG_B64}" | base64 -d > ~/.kube/config + chmod 600 ~/.kube/config + kubectl cluster-info 2>&1 | head -3 + echo "✓ kubeconfig ready" + env: + KUBECONFIG_B64: ${{ secrets.KUBECONFIG_B64 }} + + - name: Trigger Tekton TaskRun (integration tests) + id: tekton + run: | + SHA="${{ steps.sha.outputs.short_sha }}" + RUN_NAME="integration-test-${SHA}" + NAMESPACE="poimen" + IMAGE="${REGISTRY}/riotpiao-poimen/poimen-memory:${SHA}" + + echo "Triggering Tekton TaskRun: ${RUN_NAME}" + echo "Image: ${IMAGE}" + echo "" + + # Create TaskRun + cat </dev/null; then + echo "result=pass" >> $GITHUB_OUTPUT + echo "✓ Tests passed" + else + echo "result=fail" >> $GITHUB_OUTPUT + echo "✗ Tests failed or timed out" + fi + + # Print test summary + echo "" + echo "=== TaskRun Status ===" + REASON=$(kubectl get taskrun ${RUN_NAME} -n ${NAMESPACE} \ + -o jsonpath='{.status.conditions[0].reason}') + SUMMARY=$(kubectl get taskrun ${RUN_NAME} -n ${NAMESPACE} \ + -o jsonpath='{.status.results[?(@.name=="summary")].value}') + echo "Status: ${REASON}" + echo "Summary: ${SUMMARY}" + + # Print logs + echo "" + echo "=== Test Logs ===" + POD=$(kubectl get pod -n ${NAMESPACE} \ + -l tekton.dev/taskRun=${RUN_NAME} -o name | head -1) + kubectl logs -n ${NAMESPACE} "${POD}" -c step-test 2>/dev/null | tail -200 || true + + - name: Gate on test result + if: steps.tekton.outputs.result != 'pass' + run: | + echo "✗ Integration tests FAILED" + echo "Image NOT promoted to :latest" + exit 1 + + - name: Promote image to latest + run: | + docker login -u "${REGISTRY_USER}" -p "${REGISTRY_TOKEN}" "${REGISTRY}" + docker tag "${IMAGE}:${{ steps.sha.outputs.short_sha }}" "${IMAGE}:latest" + docker push "${IMAGE}:latest" + echo "✓ Promoted to :latest" + env: + REGISTRY_USER: ${{ secrets.FORGEJO_REGISTRY_USER }} + REGISTRY_TOKEN: ${{ secrets.FORGEJO_REGISTRY_TOKEN }} + + - name: Cleanup + if: always() run: | docker image prune -a --force 2>&1 | tail -3 || true cargo clean || true diff --git a/.gitea/workflows/integration-test.yaml b/.gitea/workflows/integration-test.yaml deleted file mode 100644 index 20607ca..0000000 --- a/.gitea/workflows/integration-test.yaml +++ /dev/null @@ -1,133 +0,0 @@ -name: Integration Test - -on: - workflow_run: - workflows: [CI] - types: [completed] - branches: [main] - workflow_dispatch: - inputs: - image_sha: - description: 'Image SHA to test (defaults to latest on main)' - required: false - -env: - REGISTRY: forgejo.riotpiao.com - IMAGE: forgejo.riotpiao.com/riotpiao-poimen/poimen-memory - NAMESPACE: poimen - -jobs: - integration-test: - name: K8s Integration Test - runs-on: rust - if: github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Get image SHA - id: image - run: | - if [ -n "${{ github.event.inputs.image_sha }}" ]; then - SHA="${{ github.event.inputs.image_sha }}" - else - SHA="$(git rev-parse --short HEAD)" - fi - echo "sha=$SHA" >> $GITHUB_OUTPUT - echo "Image SHA: $SHA" - - - name: Install kubectl - run: | - apt-get update - apt-get install -y kubectl postgresql-client - - - name: Setup kubeconfig - run: | - mkdir -p ~/.kube - echo "${{ secrets.KUBECONFIG_B64 }}" | base64 -d > ~/.kube/config - chmod 600 ~/.kube/config - - # Verify cluster access - kubectl cluster-info - kubectl get nodes - - - name: Verify image exists in registry - run: | - IMAGE="${{ env.IMAGE }}:${{ steps.image.outputs.sha }}" - echo "Checking if image exists: $IMAGE" - - # Use registry API to verify image exists - if docker pull "$IMAGE" 2>/dev/null; then - echo "✓ Image found in registry" - else - echo "✗ Image not found" - exit 1 - fi - env: - DOCKER_CONFIG: /tmp/docker - continue-on-error: true - - - name: Apply integration test Job - run: | - IMAGE_SHA="${{ steps.image.outputs.sha }}" - - echo "Creating integration test Job with image: $IMAGE_SHA" - echo "" - - # Substitute image SHA in manifest - cat k8s/test/integration-test-job.yaml | \ - sed "s|IMAGE_SHA|$IMAGE_SHA|g" | \ - kubectl apply -f - -n ${{ env.NAMESPACE }} - - echo "✓ Job submitted" - echo "" - - # Wait for job to complete - kubectl wait --for=condition=complete job/poimen-memory-integration-test \ - -n ${{ env.NAMESPACE }} \ - --timeout=600s || { - echo "" - echo "✗ Job did not complete in time" - echo "" - echo "Pod logs:" - kubectl logs -l test=integration -n ${{ env.NAMESPACE }} --all-containers=true --tail=100 - exit 1 - } - - - name: Collect test results - if: always() - run: | - echo "==========================================" - echo "Integration Test Results" - echo "==========================================" - echo "" - - echo "Job status:" - kubectl describe job poimen-memory-integration-test -n ${{ env.NAMESPACE }} | tail -20 - echo "" - - echo "Pod logs:" - kubectl logs -l test=integration -n ${{ env.NAMESPACE }} --all-containers=true || true - echo "" - - # Get job status - STATUS=$(kubectl get job poimen-memory-integration-test \ - -n ${{ env.NAMESPACE }} \ - -o jsonpath='{.status.succeeded}') - - if [ "$STATUS" = "1" ]; then - echo "✓ Integration test PASSED" - exit 0 - else - echo "✗ Integration test FAILED" - exit 1 - fi - - - name: Cleanup test Job - if: always() - run: | - echo "Cleaning up test resources..." - kubectl delete job poimen-memory-integration-test \ - -n ${{ env.NAMESPACE }} \ - --ignore-not-found=true - echo "✓ Cleanup complete" diff --git a/k8s/tekton/integration-test-task.yaml b/k8s/tekton/integration-test-task.yaml new file mode 100644 index 0000000..1bc283d --- /dev/null +++ b/k8s/tekton/integration-test-task.yaml @@ -0,0 +1,150 @@ +--- +# Tekton Task: Integration Tests for Poimen Memory Service +# +# Executes: +# 1. Database migrations +# 2. Integration test suites (cargo test) +# 3. Reports results +# +# Parameters: +# - image: Docker image with SHA to test +# +# Results: +# - summary: Test summary (pass/fail + count) + +apiVersion: tekton.dev/v1 +kind: Task +metadata: + name: poimen-integration-test + namespace: poimen +spec: + params: + - name: image + type: string + description: "Docker image SHA to test (e.g., forgejo.riotpiao.com/riotpiao-poimen/poimen-memory:abc123)" + + results: + - name: summary + description: "Test summary: PASS or FAIL + test count" + + steps: + # Step 1: Apply database migrations + - name: migrate + image: $(params.image) + env: + - name: DB_HOST + value: "memory-db-rw.poimen.svc.cluster.local" + - name: DB_PORT + value: "5432" + - name: DB_NAME + value: "memory" + - name: DB_USER + value: "app" + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: memory-db-app + key: password + + script: | + #!/bin/bash + set -e + + echo "==========================================" + echo "Step 1: Database Migrations" + echo "==========================================" + echo "" + + # Run migrations + /app/migrations/run_migrations.sh + + echo "" + echo "✓ Migrations complete" + + # Step 2: Run integration tests + - name: test + image: $(params.image) + env: + - name: DATABASE_URL + value: "postgresql://app@memory-db-rw.poimen.svc.cluster.local:5432/memory" + - name: RUST_LOG + value: "info,mem_cli=debug,mem_ingest=debug,mem_store=debug" + - name: MEM_AUTH_MODE + value: "none" + - name: SQLX_OFFLINE + value: "true" + - name: PGPASSWORD + valueFrom: + secretKeyRef: + name: memory-db-app + key: password + + script: | + #!/bin/bash + set -e + + echo "==========================================" + echo "Step 2: Integration Tests" + echo "==========================================" + echo "" + + TEST_SUITES=( + "it_phase3_phase4" + "it_unified_query_4_6" + "it_temporal_filtering_4_2_fixed" + ) + + PASSED=0 + FAILED=0 + + for suite in "${TEST_SUITES[@]}"; do + echo "Running: $suite" + if cargo test --test "$suite" --lib 2>&1 | tail -50; then + ((PASSED++)) + echo "✓ $suite passed" + else + ((FAILED++)) + echo "✗ $suite failed" + fi + echo "" + done + + # Run unit tests + echo "Running unit tests..." + if cargo test --lib mem_ingest 2>&1 | tail -100; then + echo "✓ mem_ingest passed" + else + ((FAILED++)) + echo "✗ mem_ingest failed" + fi + echo "" + + if cargo test --lib mem_cli::query 2>&1 | tail -100; then + echo "✓ mem_cli::query passed" + else + ((FAILED++)) + echo "✗ mem_cli::query failed" + fi + + echo "" + echo "==========================================" + echo "Test Summary: $PASSED passed, $FAILED failed" + echo "==========================================" + + if [ $FAILED -eq 0 ]; then + echo "PASS: All integration tests passed" + echo "PASS: All integration tests passed" > /tekton/results/summary + exit 0 + else + echo "FAIL: $FAILED test suite(s) failed" + echo "FAIL: $FAILED test suite(s) failed" > /tekton/results/summary + exit 1 + fi + + resources: + requests: + memory: "1Gi" + cpu: "500m" + limits: + memory: "2Gi" + cpu: "2000m" diff --git a/k8s/test/db-credentials.enc.yaml b/k8s/test/db-credentials.enc.yaml deleted file mode 100644 index ded676b..0000000 --- a/k8s/test/db-credentials.enc.yaml +++ /dev/null @@ -1,23 +0,0 @@ -apiVersion: ENC[AES256_GCM,data:rSo=,iv:bdZ6ucHQdbMkAYckaHgPX1O37sNpRzemzgtZWnNvuyc=,tag:NnqNKDxkgVuMSJCjUz9d/A==,type:str] -kind: ENC[AES256_GCM,data:i8C5n+0g,iv:1hgoEM2lCfFJybqqu+LKLcPb0oDVBbZfaO4hNU2IHCM=,tag:DgArPgsw6T0CzbKVmkNFlQ==,type:str] -metadata: - name: ENC[AES256_GCM,data:hS5ed588kPm8qyKEk48JbnSAOA==,iv:Icy0jUqXw0kaeliFYReCrX/4CvJybWSALLt1vVOqDJ0=,tag:3eJJXmWynVA7ynRA7tIODw==,type:str] - namespace: ENC[AES256_GCM,data:TaDa/Qh4,iv:wQelDyrVDxNslhz7GBFA6LhziZ7jFUGMIzT4ymYolJI=,tag:rtZ755RHlseJvgWslzim1Q==,type:str] -type: ENC[AES256_GCM,data:FhwlDJfv,iv:5ne0JFyExRdmrhuG1A37FThKpFEhUhrJeFnFOvpgHcM=,tag:lQ/RbeQJ/x/3nnhKLcB20A==,type:str] -stringData: - DATABASE_URL: ENC[AES256_GCM,data:1OmlGtPPtpocOr1U9aW76+z20TKtGvC7M6IIEFmACjdhcascOoHuGAVWlUxjGDrqM6w5DF+zXvR43E49ZsSnTvorGH+abCIfn3SpsYo21YazgBKt3A/ewu2bnjIw/RPfJ6AB7FRPdg==,iv:A1eytAyxTH5u0Hy6kThxiuwweOozyE8fiXl1JdH6vD4=,tag:D5I5Eg2Zbivm12YCvgpPGw==,type:str] -sops: - age: - - enc: | - -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBLQXA5RWh3aEFCNDZGT3dR - L2FGckR3MGFodzRqUDRodDRHdTdUOWV0SGhVCk92bnl1SjdSQUl5QTFQanVRSzR1 - SFp2MXhUbEdpUm1ES21mdHlPdHg2dlUKLS0tIFNjbXVHNHZONS9UZVNnU0IvQ1J5 - clovQ0NRVytGcG1oaktWc25SVmhyK2cKZ11ZIXu3wEGUsuXkrwDG+jGjb6a9xrVc - 1r8PWJYj5VwcT0HZO+le3A6wfmNZgCzZY6pIYE9rIHexUXcEUZiSug== - -----END AGE ENCRYPTED FILE----- - recipient: age1e5fq3hwxy78psus2nfvmtmua36g0u3suk78ephw6246l974d2utsvn0hla - lastmodified: "2026-09-14T13:48:10Z" - mac: ENC[AES256_GCM,data:aYO2ghlPJn5cq82i4hLBoAa4j5nxt4pekhoHB4OPAeZDbMXipgXa0Ha+HJtPreHh/w/6VaXnEGFtWujKHwvIoL8c5ffQK6Mqw9DSYVV0OnSFJ50/JgRvMLVFLqoqUBoiwQOyYopVjIEeqMFNslN7WvpsHCK9NRxgO1Klf97rE0w=,iv:gWlQ1VseNC/rxp7X/N8tTNRtTIckwMbrMNODQ1mHSj4=,tag:wxhucPCkXrhyvhfwwAgRbw==,type:str] - unencrypted_suffix: _unencrypted - version: 3.13.2 diff --git a/k8s/test/integration-test-job.yaml b/k8s/test/integration-test-job.yaml deleted file mode 100644 index 8f9cd44..0000000 --- a/k8s/test/integration-test-job.yaml +++ /dev/null @@ -1,171 +0,0 @@ ---- -# Integration Test Job - Runs existing Rust integration tests in K8s -# -# Two-stage execution: -# 1. migrate: Apply database migrations -# 2. test: Run existing integration tests (cargo test) -# -# Tests executed: -# - it_phase3_phase4: Ingest + persistence tests -# - it_unified_query_4_6: Query endpoint tests -# - it_temporal_filtering_4_2_fixed: Temporal query tests -# - mem_ingest: Extraction pipeline tests -# - mem_cli::query: Query handler tests - -apiVersion: batch/v1 -kind: Job -metadata: - name: poimen-memory-integration-test - namespace: poimen - labels: - app: poimen-memory - test: integration - component: ci-cd -spec: - backoffLimit: 0 - activeDeadlineSeconds: 600 - ttlSecondsAfterFinished: 3600 - - template: - metadata: - labels: - app: poimen-memory - test: integration - spec: - serviceAccountName: memory-app - restartPolicy: Never - - containers: - # Stage 1: Apply migrations - - name: migrate - image: forgejo.riotpiao.com/riotpiao-poimen/poimen-memory:IMAGE_SHA - imagePullPolicy: IfNotPresent - - command: - - /bin/bash - - -c - - | - set -e - - echo "==========================================" - echo "Applying Database Migrations" - echo "==========================================" - echo "" - - # Run migrations script - /app/migrations/run_migrations.sh - - echo "" - echo "✓ Migrations complete" - - env: - - name: DB_HOST - value: "memory-db-rw.poimen.svc.cluster.local" - - name: DB_PORT - value: "5432" - - name: DB_NAME - value: "memory" - - name: DB_USER - value: "app" - - name: DB_PASSWORD - valueFrom: - secretKeyRef: - name: memory-db-app - key: password - - resources: - requests: - memory: "256Mi" - cpu: "100m" - limits: - memory: "512Mi" - cpu: "500m" - - # Stage 2: Run integration tests - - name: test - image: forgejo.riotpiao.com/riotpiao-poimen/poimen-memory:IMAGE_SHA - imagePullPolicy: IfNotPresent - - command: - - /bin/bash - - -c - - | - set -e - - echo "==========================================" - echo "Running Integration Tests" - echo "==========================================" - echo "" - - # Run existing integration tests - echo "Test Suite 1: Ingest + Persistence (it_phase3_phase4)" - cargo test --test it_phase3_phase4 --lib 2>&1 | tail -50 || TEST_FAILED=1 - - echo "" - echo "Test Suite 2: Unified Query (it_unified_query_4_6)" - cargo test --test it_unified_query_4_6 --lib 2>&1 | tail -50 || TEST_FAILED=1 - - echo "" - echo "Test Suite 3: Temporal Filtering (it_temporal_filtering_4_2_fixed)" - cargo test --test it_temporal_filtering_4_2_fixed --lib 2>&1 | tail -50 || TEST_FAILED=1 - - echo "" - echo "Test Suite 4: Ingest Pipeline Unit Tests" - cargo test --lib mem_ingest 2>&1 | tail -100 || TEST_FAILED=1 - - echo "" - echo "Test Suite 5: Query Handler Tests" - cargo test --lib mem_cli::query 2>&1 | tail -100 || TEST_FAILED=1 - - echo "" - echo "==========================================" - echo "Integration Tests Complete" - echo "==========================================" - - if [ -n "$TEST_FAILED" ]; then - echo "✗ Some tests failed" - exit 1 - fi - - echo "✓ All tests passed" - - env: - - name: DATABASE_URL - value: "postgresql://app@memory-db-rw.poimen.svc.cluster.local:5432/memory" - - name: RUST_LOG - value: "info,mem_cli=debug,mem_ingest=debug,mem_store=debug" - - name: MEM_AUTH_MODE - value: "none" - - name: SQLX_OFFLINE - value: "true" - - name: PGPASSWORD - valueFrom: - secretKeyRef: - name: memory-db-app - key: password - - resources: - requests: - memory: "1Gi" - cpu: "500m" - limits: - memory: "2Gi" - cpu: "2000m" - - livenessProbe: - exec: - command: - - /bin/sh - - -c - - test -f /proc/self/status - initialDelaySeconds: 10 - periodSeconds: 30 - ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: memory-app - namespace: poimen - labels: - app: poimen-memory diff --git a/k8s/test/integration-test-secrets.enc.yaml b/k8s/test/integration-test-secrets.enc.yaml deleted file mode 100644 index e69de29..0000000