Files
poimen-memory/k8s/test/integration-test-job.yaml
T
rock 6499dae6e5
CI / CI (pull_request) Successful in 16m41s
test: K8s Job-based integration testing with migrations
Add proper integration test infrastructure:

migrations/run_migrations.sh:
  - Database migration runner (used by K8s Job)
  - Applies all SQL migrations in order
  - Waits for DB to be ready
  - Verifies schema creation
  - Reports success/failure

k8s/test/integration-test-job.yaml:
  - Kubernetes Job manifest for E2E testing
  - Two-stage execution:
    1. migrate: Apply database migrations
    2. test: Run integration test against new pod
  - Uses new image SHA from CI build
  - Proper secret management via K8s secretKeyRef
    (passwords stored in cluster, not in manifests)
  - Resource limits and liveness probes
  - Cleanup after 1 hour (ttlSecondsAfterFinished)

.gitea/workflows/integration-test.yaml:
  - CI workflow that runs after image build
  - Validates image exists in registry
  - Deploys Job with correct image SHA
  - Waits for job completion (10 min timeout)
  - Collects pod logs on failure
  - Automatic cleanup

Security:
  • No plaintext credentials in manifests
  • Uses K8s secretKeyRef for DB password
  • All secrets encrypted with SOPS/Age (ArgoCD plugin)
  • Never embed credentials in git

Usage:
  - Automatic: Runs after each CI build on main
  - Manual: Trigger with specific image SHA via workflow_dispatch
  - Tests: Full E2E ingest + persistence + query

URGENT: Rotate memory-db-app password
  (was visible in debugging shell history)
2026-09-14 22:44:53 +09:00

262 lines
7.7 KiB
YAML

---
# Integration Test Job
#
# Runs after image build in CI/CD pipeline.
# Tests the new image SHA against actual K8s cluster.
#
# Usage:
# kubectl apply -f k8s/test/integration-test-job.yaml \
# -n poimen \
# --dry-run=client -o yaml | \
# sed "s|IMAGE_SHA|sha256:abcd1234|g" | \
# kubectl apply -f -
#
# Or via kustomize with image patch
apiVersion: batch/v1
kind: Job
metadata:
name: poimen-memory-integration-test
namespace: poimen
labels:
app: poimen-memory
test: integration
component: ci-cd
spec:
# Don't retry on failure - we want to see the actual error
backoffLimit: 0
# Timeout after 10 minutes
activeDeadlineSeconds: 600
# Keep the pod for debugging
ttlSecondsAfterFinished: 3600 # 1 hour
template:
metadata:
labels:
app: poimen-memory
test: integration
spec:
serviceAccountName: memory-app
restartPolicy: Never
containers:
# Step 1: Run migrations
- name: migrate
image: forgejo.riotpiao.com/riotpiao-poimen/poimen-memory:IMAGE_SHA
imagePullPolicy: IfNotPresent
command:
- /bin/bash
- -c
- |
set -e
# Copy migrations script from image to working dir
cp /app/migrations/run_migrations.sh /tmp/run_migrations.sh
chmod +x /tmp/run_migrations.sh
# Run migrations
/tmp/run_migrations.sh
echo ""
echo "✓ Migrations complete"
echo "Database ready for tests"
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"
# Step 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 "Integration Test: Ingest + Embedding"
echo "=========================================="
echo ""
# Start HTTP server
echo "Starting memory-service..."
mem-cli serve --port 8080 &
SERVER_PID=$!
trap "kill $SERVER_PID 2>/dev/null || true" EXIT
echo "Server PID: $SERVER_PID"
echo "Waiting for server to be ready..."
# Wait for /health endpoint
for i in {1..30}; do
if curl -s http://localhost:8080/health >/dev/null 2>&1; then
echo "✓ Server ready"
break
fi
if [ $i -eq 30 ]; then
echo "✗ Server did not start"
exit 1
fi
echo " Attempt $i/30..."
sleep 1
done
echo ""
echo "Running E2E ingest test..."
echo ""
# Send ingest request
INGEST_ID="test-$(date +%s)"
RESPONSE=$(curl -s -X POST http://localhost:8080/memory/ingest \
-H "Content-Type: application/json" \
-H "Authorization: Bearer test-key" \
-d "{
\"project\": \"integration-test\",
\"source\": \"k8s-job-test\",
\"ingest_id\": \"$INGEST_ID\",
\"records\": [
{
\"role\": \"user\",
\"text\": \"Kubernetes [[Docker]] [[Linux]] container platform\",
\"timestamp\": \"2026-09-14T13:00:00Z\",
\"source_position\": 0
},
{
\"role\": \"user\",
\"text\": \"Docker [[Container]] microservices architecture\",
\"timestamp\": \"2026-09-14T13:01:00Z\",
\"source_position\": 1
}
]
}")
# Check response
STATUS=$(echo "$RESPONSE" | jq -r '.status // "error"')
ID=$(echo "$RESPONSE" | jq -r '.ingest_id // empty')
if [ -z "$ID" ]; then
echo "✗ FAILED: No ingest_id in response"
echo "Response: $RESPONSE"
exit 1
fi
echo "Ingest ID: $ID"
echo "Status: $STATUS"
echo ""
echo "Polling for completion..."
# Poll until done
for poll in {1..60}; do
RESP=$(curl -s http://localhost:8080/memory/ingest/$ID \
-H "Authorization: Bearer test-key")
STATE=$(echo "$RESP" | jq -r '.status // "unknown"')
if [ "$STATE" = "done" ]; then
echo "Poll $poll: $STATE ✓"
echo ""
echo "✓ INGEST SUCCESSFUL"
break
elif [ "$STATE" = "failed" ] || [ "$STATE" = "error" ]; then
echo "Poll $poll: $STATE ✗"
echo "Response: $RESP"
echo "✗ INGEST FAILED"
exit 1
fi
echo "Poll $poll: $STATE"
sleep 2
done
echo ""
echo "Testing query endpoint..."
QUERY=$(curl -s "http://localhost:8080/memory/query?project=integration-test&question=what%20is%20docker" \
-H "Authorization: Bearer test-key")
ENTITY_COUNT=$(echo "$QUERY" | jq '.count.entities // 0')
echo "Entities returned: $ENTITY_COUNT"
if [ "$ENTITY_COUNT" -gt 0 ]; then
echo "✓ QUERY SUCCESSFUL"
echo ""
echo "Entities:"
echo "$QUERY" | jq '.entities[].name'
else
echo "⚠ No entities returned (schema issue)"
echo "✗ Query test FAILED"
exit 1
fi
echo ""
echo "=========================================="
echo "✓ ALL TESTS PASSED"
echo "=========================================="
env:
- name: DATABASE_URL
value: "postgresql://[email protected]:5432/memory"
- name: RUST_LOG
value: "info,mem_cli=debug,mem_ingest=debug"
- name: MEM_AUTH_MODE
value: "none"
# Password via secret
- name: PGPASSWORD
valueFrom:
secretKeyRef:
name: memory-db-app
key: password
resources:
requests:
memory: "512Mi"
cpu: "200m"
limits:
memory: "1Gi"
cpu: "1000m"
livenessProbe:
exec:
command:
- /bin/sh
- -c
- curl -s http://localhost:8080/health >/dev/null
initialDelaySeconds: 30
periodSeconds: 10
failureThreshold: 2
---
# ServiceAccount for integration test
apiVersion: v1
kind: ServiceAccount
metadata:
name: memory-app
namespace: poimen
labels:
app: poimen-memory