#!/usr/bin/env bash # 09_failure_modes.sh — GOLAKE-080..085. # Verifies the system fails cleanly: 4xx for malformed input, 404 for # missing resources, structured error bodies. Per the spec: "Do not # hide failures behind retries unless documented." set -uo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "${SCRIPT_DIR}/../lib/env.sh" source "${SCRIPT_DIR}/../lib/http.sh" source "${SCRIPT_DIR}/../lib/assert.sh" CASE_ID="GOLAKE-080-085" CASE_NAME="Failure modes — 4xx not 5xx, structured errors" CASE_TYPE="contract" if [ "${1:-}" = "--metadata-only" ]; then return 0 2>/dev/null || exit 0; fi # ── GOLAKE-080: malformed JSON → 4xx, never 5xx, never silent 200 ─── JUNK='not-valid-json{[]}' ENDPOINTS=( "catalog_register:${PROOF_GATEWAY_URL}/v1/catalog/register" "ingest:${PROOF_GATEWAY_URL}/v1/ingest" "sql:${PROOF_GATEWAY_URL}/v1/sql" "embed:${PROOF_GATEWAY_URL}/v1/embed" ) for spec in "${ENDPOINTS[@]}"; do IFS=':' read -r name url <<< "$spec" proof_post "$CASE_ID" "malformed_${name}" "$url" "application/json" "$JUNK" >/dev/null proof_assert_status_4xx "$CASE_ID" "${name}: malformed JSON → 4xx" "malformed_${name}" done # ── GOLAKE-081: missing required field → 400 ────────────────────── proof_post "$CASE_ID" "missing_required_catalog" \ "${PROOF_GATEWAY_URL}/v1/catalog/register" \ "application/json" '{}' >/dev/null proof_assert_status_4xx "$CASE_ID" "catalog/register: empty body → 4xx" "missing_required_catalog" proof_post "$CASE_ID" "missing_required_vector_create" \ "${PROOF_GATEWAY_URL}/v1/vectors/index" \ "application/json" '{"name":"missing_dim_test"}' >/dev/null proof_assert_status_4xx "$CASE_ID" "vectors/index: missing dimension → 4xx" "missing_required_vector_create" proof_post "$CASE_ID" "missing_required_embed" \ "${PROOF_GATEWAY_URL}/v1/embed" \ "application/json" '{}' >/dev/null proof_assert_status_4xx "$CASE_ID" "embed: missing texts → 4xx" "missing_required_embed" # ── GOLAKE-082: bad SQL → 4xx, error body present ──────────────── proof_post "$CASE_ID" "bad_sql_syntax" \ "${PROOF_GATEWAY_URL}/v1/sql" \ "application/json" '{"sql":"NOT VALID SQL HERE"}' >/dev/null proof_assert_status_4xx "$CASE_ID" "queryd: bad SQL → 4xx" "bad_sql_syntax" err_body=$(proof_body_of "$CASE_ID" "bad_sql_syntax") proof_assert_ne "$CASE_ID" "queryd: bad SQL response body non-empty" "" "$err_body" # ── GOLAKE-083: vector dim mismatch → 4xx ──────────────────────── DIM_IDX="proof_dim_mismatch_test" proof_delete "$CASE_ID" "dim_pre_clean" \ "${PROOF_GATEWAY_URL}/v1/vectors/index/${DIM_IDX}" >/dev/null proof_post "$CASE_ID" "dim_create" \ "${PROOF_GATEWAY_URL}/v1/vectors/index" \ "application/json" "{\"name\":\"${DIM_IDX}\",\"dimension\":3}" >/dev/null # Wrong-shape add — vectord wants `items` not `vectors`. Use correct # field name; the dim mismatch is the actual failure mode under test. proof_post "$CASE_ID" "dim_mismatch_add" \ "${PROOF_GATEWAY_URL}/v1/vectors/index/${DIM_IDX}/add" \ "application/json" '{"items":[{"id":"x","vector":[1,2,3,4]}]}' >/dev/null proof_assert_status_4xx "$CASE_ID" "vectord: dim mismatch on add → 4xx" "dim_mismatch_add" proof_delete "$CASE_ID" "dim_post_clean" \ "${PROOF_GATEWAY_URL}/v1/vectors/index/${DIM_IDX}" >/dev/null # ── GOLAKE-084: missing storage object → 404 ────────────────────── proof_get "$CASE_ID" "missing_object" \ "${PROOF_GATEWAY_URL}/v1/storage/get/proof_definitely_not_a_key_xyz_$(date +%N)" >/dev/null proof_assert_eq "$CASE_ID" "storage/get on missing key → 404" "404" \ "$(proof_status_of "$CASE_ID" "missing_object")" # ── GOLAKE-085: duplicate vector ID — informational ────────────── DUP_IDX="proof_dup_test" proof_delete "$CASE_ID" "dup_pre_clean" \ "${PROOF_GATEWAY_URL}/v1/vectors/index/${DUP_IDX}" >/dev/null proof_post "$CASE_ID" "dup_create" \ "${PROOF_GATEWAY_URL}/v1/vectors/index" \ "application/json" "{\"name\":\"${DUP_IDX}\",\"dimension\":2}" >/dev/null proof_post "$CASE_ID" "dup_add_first" \ "${PROOF_GATEWAY_URL}/v1/vectors/index/${DUP_IDX}/add" \ "application/json" '{"items":[{"id":"d1","vector":[1,0]}]}' >/dev/null proof_post "$CASE_ID" "dup_add_second" \ "${PROOF_GATEWAY_URL}/v1/vectors/index/${DUP_IDX}/add" \ "application/json" '{"items":[{"id":"d1","vector":[0,1]}]}' >/dev/null dup_first=$(proof_status_of "$CASE_ID" "dup_add_first") dup_second=$(proof_status_of "$CASE_ID" "dup_add_second") proof_assert_eq "$CASE_ID" "dup add first → 200" "200" "$dup_first" proof_skip "$CASE_ID" "dup-id behavior recorded (informational)" \ "first=${dup_first} second=${dup_second} — see raw/http/${CASE_ID}/dup_add_*.json for full record" proof_delete "$CASE_ID" "dup_post_clean" \ "${PROOF_GATEWAY_URL}/v1/vectors/index/${DUP_IDX}" >/dev/null