tests.sh 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. #!/usr/bin/env bash
  2. # tests.sh — mem0server endpoint tests
  3. # Usage: bash tests.sh [BASE_URL]
  4. # Default base: http://192.168.0.200:8420
  5. BASE="${1:-http://192.168.0.200:8420}"
  6. PASS=0
  7. FAIL=0
  8. LAST_JSON=""
  9. LAST_STATUS=""
  10. MEMORY_MARKER="mem0-test-case"
  11. # Colours
  12. GREEN='\033[0;32m'
  13. RED='\033[0;31m'
  14. CYAN='\033[0;36m'
  15. BOLD='\033[1m'
  16. RESET='\033[0m'
  17. sep() { echo -e "\n${CYAN}${BOLD}━━━ $* ━━━${RESET}"; }
  18. ok() { echo -e "${GREEN}✓ $*${RESET}"; ((PASS++)); }
  19. fail() { echo -e "${RED}✗ $*${RESET}"; ((FAIL++)); }
  20. run() {
  21. local label="$1"; shift
  22. local expected="200"
  23. if [[ "$1" =~ ^[0-9]{3}$ ]]; then
  24. expected="$1"
  25. shift
  26. fi
  27. echo -e "\n${BOLD}▶ $label${RESET}"
  28. local body
  29. body=$(curl -s -w "\n__STATUS__%{http_code}" "$@")
  30. local status
  31. status=$(echo "$body" | tail -1 | sed 's/__STATUS__//')
  32. local json
  33. json=$(echo "$body" | sed '$d')
  34. echo "$json" | jq . 2>/dev/null || echo "$json"
  35. LAST_STATUS="$status"
  36. LAST_JSON="$json"
  37. if [[ "$status" == "$expected" ]]; then
  38. ok "HTTP $status"
  39. else
  40. fail "HTTP $status (expected $expected)"
  41. fi
  42. }
  43. assert_json() {
  44. local label="$1" expr="$2"
  45. if echo "$LAST_JSON" | jq -e "$expr" >/dev/null 2>&1; then
  46. ok "$label"
  47. else
  48. fail "$label (jq: $expr)"
  49. fi
  50. }
  51. assert_contains() {
  52. local label="$1" substring="$2"
  53. if echo "$LAST_JSON" | grep -qF "$substring"; then
  54. ok "$label"
  55. else
  56. fail "$label (missing '$substring')"
  57. fi
  58. }
  59. sep "HEALTH"
  60. run "GET /health" "$BASE/health"
  61. assert_json "health -> collections object" '.collections | type == "object"'
  62. assert_json "health -> prompts present" '.prompts | type == "object"'
  63. sep "DASHBOARD"
  64. run "GET /dashboard" "$BASE/dashboard"
  65. assert_contains "dashboard contains HTML" "<html"
  66. sep "/memories (conversational)"
  67. run "POST /memories — plain text" \
  68. -X POST "$BASE/memories" \
  69. -H "Content-Type: application/json" \
  70. -d "{\"text\": \"${MEMORY_MARKER} plain text entry for testing\", \"user_id\": \"testuser\"}"
  71. run "POST /memories — messages array" \
  72. -X POST "$BASE/memories" \
  73. -H "Content-Type: application/json" \
  74. -d "{\"messages\": [{\"role\": \"user\", \"content\": \"${MEMORY_MARKER} message entry for testing\"}], \"user_id\": \"testuser\"}"
  75. run "POST /memories/all" \
  76. -X POST "$BASE/memories/all" \
  77. -H "Content-Type: application/json" \
  78. -d '{"user_id": "testuser"}'
  79. assert_json "memories/all returns array" '.results | type == "array"'
  80. run "POST /memories/search — capture marker" \
  81. -X POST "$BASE/memories/search" \
  82. -H "Content-Type: application/json" \
  83. -d "{\"query\": \"${MEMORY_MARKER}\", \"user_id\": \"testuser\", \"limit\": 5}"
  84. assert_json "memories marker search returns array" '.results | type == "array"'
  85. MEMORY_IDS=$(echo "$LAST_JSON" | jq -r '.results[] | .id')
  86. if [[ -z "$MEMORY_IDS" ]]; then
  87. fail "no test memory IDs captured"
  88. else
  89. ok "captured conversational memory IDs"
  90. fi
  91. run "POST /memories/search" \
  92. -X POST "$BASE/memories/search" \
  93. -H "Content-Type: application/json" \
  94. -d '{"query": "programming preferences", "user_id": "testuser", "limit": 5 }'
  95. assert_json "memories search returns array" '.results | type == "array"'
  96. run "POST /memories/recent" \
  97. -X POST "$BASE/memories/recent" \
  98. -H "Content-Type: application/json" \
  99. -d '{"user_id": "testuser", "limit": 5}'
  100. assert_json "memories recent returns array" '.results | type == "array"'
  101. if [[ -n "$MEMORY_IDS" ]]; then
  102. for id in $MEMORY_IDS; do
  103. run "DELETE /memory/$id" \
  104. -X DELETE "$BASE/memory/$id" \
  105. -H "Content-Type: application/json" \
  106. -d '{"collection": "conversational"}'
  107. done
  108. else
  109. fail "conversational memory IDs missing before cleanup"
  110. fi
  111. sep "/knowledge (knowledge base)"
  112. run "POST /knowledge — Gesell metadata" \
  113. -X POST "$BASE/knowledge" \
  114. -H "Content-Type: application/json" \
  115. -d '{"text": "Silvio Gesell proposed demurrage to discourage hoarding of currency.", "user_id": "knowledge_base", "metadata": {"source_file": "gesell_neo.pdf", "chapter": 3, "page": 47}}'
  116. run "POST /knowledge — MIDI verbatim" \
  117. -X POST "$BASE/knowledge" \
  118. -H "Content-Type: application/json" \
  119. -d '{"text": "MIDI SysEx uses a 7-bit checksum.", "user_id": "knowledge_base", "infer": false, "metadata": {"source_file": "midi_spec.pdf", "chapter": 9, "page": 112}}'
  120. run "POST /knowledge/search — Gesell demurrage" \
  121. -X POST "$BASE/knowledge/search" \
  122. -H "Content-Type: application/json" \
  123. -d '{"query": "Gesell demurrage", "user_id": "knowledge_base", "limit": 5}'
  124. assert_json "knowledge search results array" '.results | type == "array"'
  125. run "POST /knowledge/recent" \
  126. -X POST "$BASE/knowledge/recent" \
  127. -H "Content-Type: application/json" \
  128. -d '{"user_id": "knowledge_base", "limit": 5}'
  129. assert_json "knowledge recent returns array" '.results | type == "array"'
  130. run "POST /knowledge/sources" \
  131. -X POST "$BASE/knowledge/sources" \
  132. -H "Content-Type: application/json" \
  133. -d '{"user_id": "knowledge_base"}'
  134. assert_json "knowledge sources array" '.sources | type == "array"'
  135. assert_json "knowledge sources include Gesell" '.sources | any(.source_file == "gesell_neo.pdf")'
  136. run "DELETE /knowledge/by-source — gesell_neo.pdf" \
  137. -X DELETE "$BASE/knowledge/by-source" \
  138. -H "Content-Type: application/json" \
  139. -d '{"source_file": "gesell_neo.pdf", "user_id": "knowledge_base"}'
  140. assert_json "knowledge by-source removed entries" '.deleted | tonumber > 0'
  141. run "DELETE /knowledge/by-source — midi_spec.pdf" \
  142. -X DELETE "$BASE/knowledge/by-source" \
  143. -H "Content-Type: application/json" \
  144. -d '{"source_file": "midi_spec.pdf", "user_id": "knowledge_base"}'
  145. assert_json "knowledge by-source removed MIDI entries" '.deleted | tonumber > 0'
  146. sep "/search (merged)"
  147. run "POST /search — Python programming" \
  148. -X POST "$BASE/search" \
  149. -H "Content-Type: application/json" \
  150. -d '{"query": "Python programming", "user_id": "testuser", "limit": 8}'
  151. assert_json "merged search results array" '.results | type == "array"'
  152. assert_json "merged search items have _source" 'if (.results | length) == 0 then true else (.results[] | has("_source")) end'
  153. run "POST /search — Gesell economic theory" \
  154. -X POST "$BASE/search" \
  155. -H "Content-Type: application/json" \
  156. -d '{"query": "Gesell economic theory", "user_id": "knowledge_base", "limit": 5}'
  157. assert_json "merged search results array (Gesell)" '.results | type == "array"'
  158. assert_json "merged Gesell results tag _source" 'if (.results | length) == 0 then true else (.results[] | has("_source")) end'
  159. sep "ERROR HANDLING"
  160. run "POST /memories — missing text" 400 \
  161. -X POST "$BASE/memories" \
  162. -H "Content-Type: application/json" \
  163. -d '{"user_id": "testuser"}'
  164. run "POST /memories — infer:false ignored" \
  165. -X POST "$BASE/memories" \
  166. -H "Content-Type: application/json" \
  167. -d '{"text": "This should still go through LLM extraction", "user_id": "testuser", "infer": false}'
  168. run "POST /search — empty query" \
  169. -X POST "$BASE/search" \
  170. -H "Content-Type: application/json" \
  171. -d '{"query": "", "user_id": "testuser"}'
  172. assert_json "empty search returns results array" '.results | type == "array"'
  173. assert_json "empty search returns zero results" '.results | length == 0'
  174. sep "RESULTS"
  175. echo -e "\n${BOLD}Passed: ${GREEN}$PASS${RESET} ${BOLD}Failed: ${RED}$FAIL${RESET}\n"