#!/usr/bin/env bash set -Eeuo pipefail # PostgREST API Testing Script # Tests the Supabase-compatible REST API for vector storage # Color codes RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # Configuration CTID="${1:-769276659}" CT_IP="${2:-192.168.45.45}" JWT_SECRET="${3:-IM9/HRQR9mw63lU/1G7vXPMe7q0n3oLcr35dryv0ToU=}" ANON_KEY="${4:-eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzAwMDAwMDAwLCJleHAiOjIwMDAwMDAwMDB9.6eAdv5-GWC35tHju8V_7is02G3HaoQfVk2UCDC1Tf5o}" SERVICE_KEY="${5:-eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoic2VydmljZV9yb2xlIiwiaXNzIjoic3VwYWJhc2UiLCJpYXQiOjE3MDAwMDAwMDAsImV4cCI6MjAwMDAwMDAwMH0.jBMTvYi7DxgwtxEmUzsDfKd66LJoFlmPAYiGCTXYKmc}" TESTS_PASSED=0 TESTS_FAILED=0 print_test() { echo -e "${BLUE}[TEST]${NC} $1"; } print_pass() { echo -e "${GREEN}[PASS]${NC} $1"; ((TESTS_PASSED++)); } print_fail() { echo -e "${RED}[FAIL]${NC} $1"; ((TESTS_FAILED++)); } print_info() { echo -e "${BLUE}[INFO]${NC} $1"; } echo -e "${BLUE}========================================${NC}" echo -e "${BLUE}PostgREST API Test Suite${NC}" echo -e "${BLUE}========================================${NC}" echo "" # Test 1: PostgREST root endpoint print_test "Testing PostgREST root endpoint..." ROOT_RESPONSE=$(curl -s -o /dev/null -w '%{http_code}' "http://${CT_IP}:3000/" 2>/dev/null || echo "000") if [[ "$ROOT_RESPONSE" == "200" ]]; then print_pass "PostgREST root endpoint accessible (HTTP ${ROOT_RESPONSE})" else print_fail "PostgREST root endpoint not accessible (HTTP ${ROOT_RESPONSE})" fi # Test 2: List tables via PostgREST print_test "Listing available tables via PostgREST..." TABLES_RESPONSE=$(curl -s "http://${CT_IP}:3000/" \ -H "apikey: ${ANON_KEY}" \ -H "Authorization: Bearer ${ANON_KEY}" 2>/dev/null || echo "") if echo "$TABLES_RESPONSE" | grep -q "documents"; then print_pass "Documents table is exposed via PostgREST" else print_fail "Documents table not found in PostgREST response" fi # Test 3: Query documents table (should be empty initially) print_test "Querying documents table..." DOCS_RESPONSE=$(curl -s "http://${CT_IP}:3000/documents?select=*" \ -H "apikey: ${ANON_KEY}" \ -H "Authorization: Bearer ${ANON_KEY}" \ -H "Content-Type: application/json" 2>/dev/null || echo "[]") if [[ "$DOCS_RESPONSE" == "[]" ]] || echo "$DOCS_RESPONSE" | grep -q '\['; then DOC_COUNT=$(echo "$DOCS_RESPONSE" | grep -o '"id"' | wc -l || echo "0") print_pass "Documents table accessible (${DOC_COUNT} documents)" else print_fail "Failed to query documents table: ${DOCS_RESPONSE}" fi # Test 4: Test with service role key (higher privileges) print_test "Testing with service role key..." SERVICE_RESPONSE=$(curl -s "http://${CT_IP}:3000/documents?select=count" \ -H "apikey: ${SERVICE_KEY}" \ -H "Authorization: Bearer ${SERVICE_KEY}" \ -H "Content-Type: application/json" 2>/dev/null || echo "error") if [[ "$SERVICE_RESPONSE" != "error" ]]; then print_pass "Service role key authentication successful" else print_fail "Service role key authentication failed" fi # Test 5: Test CORS headers print_test "Checking CORS headers..." CORS_RESPONSE=$(curl -s -I "http://${CT_IP}:3000/documents" \ -H "Origin: http://example.com" \ -H "apikey: ${ANON_KEY}" 2>/dev/null || echo "") if echo "$CORS_RESPONSE" | grep -qi "access-control-allow-origin"; then print_pass "CORS headers present" else print_info "CORS headers not found (may be expected depending on configuration)" fi # Test 6: Test RPC function (match_documents) print_test "Testing match_documents RPC function..." RPC_RESPONSE=$(curl -s -X POST "http://${CT_IP}:3000/rpc/match_documents" \ -H "apikey: ${SERVICE_KEY}" \ -H "Authorization: Bearer ${SERVICE_KEY}" \ -H "Content-Type: application/json" \ -d '{"query_embedding":"[0.1,0.2,0.3]","match_count":5}' 2>/dev/null || echo "error") # This will fail if no documents exist, but we're testing if the function is accessible if echo "$RPC_RESPONSE" | grep -q "error\|code" && ! echo "$RPC_RESPONSE" | grep -q "PGRST"; then print_info "match_documents function exists (no documents to match yet)" elif [[ "$RPC_RESPONSE" == "[]" ]]; then print_pass "match_documents function accessible (empty result)" else print_info "RPC response: ${RPC_RESPONSE:0:100}" fi # Test 7: Check PostgREST schema cache print_test "Checking PostgREST schema introspection..." SCHEMA_RESPONSE=$(curl -s "http://${CT_IP}:3000/" \ -H "apikey: ${ANON_KEY}" \ -H "Accept: application/openapi+json" 2>/dev/null || echo "{}") if echo "$SCHEMA_RESPONSE" | grep -q "openapi\|swagger"; then print_pass "PostgREST OpenAPI schema available" else print_info "OpenAPI schema not available (may require specific configuration)" fi # Test 8: Test PostgreSQL connection from PostgREST print_test "Verifying PostgREST database connection..." PG_CONN=$(pct exec "${CTID}" -- bash -lc "docker logs customer-postgrest 2>&1 | grep -i 'listening\|connection\|ready' | tail -3" || echo "") if [[ -n "$PG_CONN" ]]; then print_pass "PostgREST has database connection logs" print_info "Recent logs: ${PG_CONN:0:100}" else print_info "No connection logs found (may be normal)" fi # Test 9: Test invalid authentication print_test "Testing authentication rejection with invalid key..." INVALID_RESPONSE=$(curl -s -o /dev/null -w '%{http_code}' "http://${CT_IP}:3000/documents" \ -H "apikey: invalid_key_12345" \ -H "Authorization: Bearer invalid_key_12345" 2>/dev/null || echo "000") if [[ "$INVALID_RESPONSE" == "401" ]] || [[ "$INVALID_RESPONSE" == "403" ]]; then print_pass "Invalid authentication properly rejected (HTTP ${INVALID_RESPONSE})" else print_info "Authentication response: HTTP ${INVALID_RESPONSE}" fi # Test 10: Check PostgREST container health print_test "Checking PostgREST container health..." POSTGREST_HEALTH=$(pct exec "${CTID}" -- bash -lc "docker inspect customer-postgrest --format='{{.State.Health.Status}}'" 2>/dev/null || echo "unknown") if [[ "$POSTGREST_HEALTH" == "healthy" ]] || [[ "$POSTGREST_HEALTH" == "unknown" ]]; then print_pass "PostgREST container is healthy" else print_fail "PostgREST container health: ${POSTGREST_HEALTH}" fi # Test 11: Test content negotiation print_test "Testing content negotiation (JSON)..." JSON_RESPONSE=$(curl -s "http://${CT_IP}:3000/documents?limit=1" \ -H "apikey: ${ANON_KEY}" \ -H "Accept: application/json" 2>/dev/null || echo "") if echo "$JSON_RESPONSE" | grep -q '\[' || [[ "$JSON_RESPONSE" == "[]" ]]; then print_pass "JSON content type supported" else print_fail "JSON content negotiation failed" fi # Test 12: Check PostgREST version print_test "Checking PostgREST version..." VERSION=$(pct exec "${CTID}" -- bash -lc "docker exec customer-postgrest postgrest --version 2>/dev/null" || echo "unknown") if [[ "$VERSION" != "unknown" ]]; then print_pass "PostgREST version: ${VERSION}" else print_info "Could not determine PostgREST version" fi # Test 13: Test from inside n8n container (internal network) print_test "Testing PostgREST from n8n container (internal network)..." INTERNAL_TEST=$(pct exec "${CTID}" -- bash -lc "docker exec n8n curl -s -o /dev/null -w '%{http_code}' 'http://postgrest:3000/'" 2>/dev/null || echo "000") if [[ "$INTERNAL_TEST" == "200" ]]; then print_pass "PostgREST accessible from n8n container (HTTP ${INTERNAL_TEST})" else print_fail "PostgREST not accessible from n8n container (HTTP ${INTERNAL_TEST})" fi # Summary echo "" echo -e "${BLUE}========================================${NC}" echo -e "${BLUE}PostgREST Test Summary${NC}" echo -e "${BLUE}========================================${NC}" TOTAL=$((TESTS_PASSED + TESTS_FAILED)) echo -e "Total Tests: ${TOTAL}" echo -e "${GREEN}Passed: ${TESTS_PASSED}${NC}" echo -e "${RED}Failed: ${TESTS_FAILED}${NC}" echo "" if [[ $TESTS_FAILED -eq 0 ]]; then echo -e "${GREEN}✓ All PostgREST tests passed!${NC}" echo "" echo -e "${BLUE}API Endpoints:${NC}" echo -e " Base URL: http://${CT_IP}:3000" echo -e " Documents: http://${CT_IP}:3000/documents" echo -e " RPC: http://${CT_IP}:3000/rpc/match_documents" echo "" exit 0 else echo -e "${YELLOW}⚠ Some tests failed. Review output above.${NC}" exit 1 fi