344 lines
6.8 KiB
Go
344 lines
6.8 KiB
Go
package index
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// TestSearchIntegration tests search operations.
|
|
func TestSearchIntegration(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping integration test in short mode")
|
|
}
|
|
|
|
c := setupIntegrationTest(t)
|
|
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
|
defer cancel()
|
|
|
|
indexName := "test-search-integration"
|
|
|
|
// Setup index with mapping
|
|
config := &IndexConfig{
|
|
Mappings: map[string]any{
|
|
"properties": map[string]any{
|
|
"title": map[string]any{
|
|
"type": "text",
|
|
},
|
|
"category": map[string]any{
|
|
"type": "keyword",
|
|
},
|
|
"price": map[string]any{
|
|
"type": "integer",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
err := CreateIndex(ctx, c, indexName, config)
|
|
if err != nil {
|
|
t.Fatalf("setup: CreateIndex() error = %v", err)
|
|
}
|
|
|
|
defer func() {
|
|
_ = DeleteIndex(ctx, c, indexName)
|
|
}()
|
|
|
|
// Index test documents
|
|
docs := []*Document{
|
|
{
|
|
ID: "1",
|
|
Source: map[string]any{
|
|
"title": "Go Programming Language",
|
|
"category": "books",
|
|
"price": 50,
|
|
},
|
|
},
|
|
{
|
|
ID: "2",
|
|
Source: map[string]any{
|
|
"title": "Python for Beginners",
|
|
"category": "books",
|
|
"price": 40,
|
|
},
|
|
},
|
|
{
|
|
ID: "3",
|
|
Source: map[string]any{
|
|
"title": "JavaScript Guide",
|
|
"category": "books",
|
|
"price": 45,
|
|
},
|
|
},
|
|
}
|
|
|
|
err = BulkIndexDocuments(ctx, c, indexName, docs)
|
|
if err != nil {
|
|
t.Fatalf("setup: BulkIndexDocuments() error = %v", err)
|
|
}
|
|
|
|
// Give ES a moment to index
|
|
time.Sleep(1 * time.Second)
|
|
|
|
// Test 1: Match query
|
|
t.Run("MatchQuery", func(t *testing.T) {
|
|
query := &SearchQuery{
|
|
Query: MatchQuery("title", "Programming"),
|
|
Size: 10,
|
|
}
|
|
|
|
result, err := Search(ctx, c, indexName, query)
|
|
if err != nil {
|
|
t.Fatalf("Search() error = %v", err)
|
|
}
|
|
|
|
if result.Hits.Total.Value == 0 {
|
|
t.Error("Search() returned no results")
|
|
}
|
|
|
|
t.Logf("Match query found %d results", result.Hits.Total.Value)
|
|
})
|
|
|
|
// Test 2: Term query
|
|
t.Run("TermQuery", func(t *testing.T) {
|
|
query := &SearchQuery{
|
|
Query: TermQuery("category", "books"),
|
|
Size: 10,
|
|
}
|
|
|
|
result, err := Search(ctx, c, indexName, query)
|
|
if err != nil {
|
|
t.Fatalf("Search() error = %v", err)
|
|
}
|
|
|
|
if result.Hits.Total.Value != 3 {
|
|
t.Errorf("Term query found %d results, want 3", result.Hits.Total.Value)
|
|
}
|
|
|
|
t.Logf("Term query found %d results", result.Hits.Total.Value)
|
|
})
|
|
|
|
// Test 3: Range query
|
|
t.Run("RangeQuery", func(t *testing.T) {
|
|
query := &SearchQuery{
|
|
Query: RangeQuery("price", 40, 50),
|
|
Size: 10,
|
|
}
|
|
|
|
result, err := Search(ctx, c, indexName, query)
|
|
if err != nil {
|
|
t.Fatalf("Search() error = %v", err)
|
|
}
|
|
|
|
if result.Hits.Total.Value == 0 {
|
|
t.Error("Range query returned no results")
|
|
}
|
|
|
|
t.Logf("Range query found %d results", result.Hits.Total.Value)
|
|
})
|
|
|
|
// Test 4: Bool query
|
|
t.Run("BoolQuery", func(t *testing.T) {
|
|
boolQ := &BoolQuery{
|
|
Must: []map[string]any{
|
|
TermQuery("category", "books"),
|
|
},
|
|
Filter: []map[string]any{
|
|
RangeQuery("price", nil, 45),
|
|
},
|
|
}
|
|
|
|
query := &SearchQuery{
|
|
Query: boolQ.ToBoolQuery(),
|
|
Size: 10,
|
|
}
|
|
|
|
result, err := Search(ctx, c, indexName, query)
|
|
if err != nil {
|
|
t.Fatalf("Search() error = %v", err)
|
|
}
|
|
|
|
if result.Hits.Total.Value == 0 {
|
|
t.Error("Bool query returned no results")
|
|
}
|
|
|
|
t.Logf("Bool query found %d results", result.Hits.Total.Value)
|
|
})
|
|
|
|
// Test 5: Match all query
|
|
t.Run("MatchAllQuery", func(t *testing.T) {
|
|
query := &SearchQuery{
|
|
Query: MatchAllQuery(),
|
|
Size: 10,
|
|
}
|
|
|
|
result, err := Search(ctx, c, indexName, query)
|
|
if err != nil {
|
|
t.Fatalf("Search() error = %v", err)
|
|
}
|
|
|
|
if result.Hits.Total.Value != 3 {
|
|
t.Errorf("Match all query found %d results, want 3", result.Hits.Total.Value)
|
|
}
|
|
|
|
t.Logf("Match all query found %d results", result.Hits.Total.Value)
|
|
})
|
|
|
|
// Test 6: Pagination
|
|
t.Run("Pagination", func(t *testing.T) {
|
|
query := &SearchQuery{
|
|
Query: MatchAllQuery(),
|
|
Size: 1,
|
|
From: 1,
|
|
}
|
|
|
|
result, err := Search(ctx, c, indexName, query)
|
|
if err != nil {
|
|
t.Fatalf("Search() error = %v", err)
|
|
}
|
|
|
|
if len(result.Hits.Hits) != 1 {
|
|
t.Errorf("Pagination returned %d hits, want 1", len(result.Hits.Hits))
|
|
}
|
|
|
|
t.Log("Pagination test passed")
|
|
})
|
|
|
|
// Test 7: Multi-match query
|
|
t.Run("MultiMatchQuery", func(t *testing.T) {
|
|
query := &SearchQuery{
|
|
Query: MultiMatchQuery("Programming", "title", "category"),
|
|
Size: 10,
|
|
}
|
|
|
|
result, err := Search(ctx, c, indexName, query)
|
|
if err != nil {
|
|
t.Fatalf("Search() error = %v", err)
|
|
}
|
|
|
|
if result.Hits.Total.Value == 0 {
|
|
t.Error("Multi-match query returned no results")
|
|
}
|
|
|
|
t.Logf("Multi-match query found %d results", result.Hits.Total.Value)
|
|
})
|
|
}
|
|
|
|
func TestSearch(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping integration test in short mode")
|
|
}
|
|
|
|
c := setupIntegrationTest(t)
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer cancel()
|
|
|
|
indexName := "test-search"
|
|
|
|
// Cleanup any existing index first
|
|
_ = DeleteIndex(ctx, c, indexName)
|
|
|
|
// Setup
|
|
err := CreateIndex(ctx, c, indexName, nil)
|
|
if err != nil {
|
|
t.Fatalf("setup: CreateIndex() error = %v", err)
|
|
}
|
|
|
|
defer func() {
|
|
_ = DeleteIndex(ctx, c, indexName)
|
|
}()
|
|
|
|
// Index a document
|
|
doc := &Document{
|
|
Source: map[string]any{
|
|
"message": "test search",
|
|
},
|
|
}
|
|
|
|
_, err = IndexDocument(ctx, c, indexName, doc)
|
|
if err != nil {
|
|
t.Fatalf("setup: IndexDocument() error = %v", err)
|
|
}
|
|
|
|
// Give ES a moment
|
|
time.Sleep(1 * time.Second)
|
|
|
|
query := &SearchQuery{
|
|
Query: MatchAllQuery(),
|
|
Size: 10,
|
|
}
|
|
|
|
result, err := Search(ctx, c, indexName, query)
|
|
if err != nil {
|
|
t.Fatalf("Search() error = %v", err)
|
|
}
|
|
|
|
if result == nil {
|
|
t.Error("Search() returned nil")
|
|
}
|
|
|
|
t.Logf("Search succeeded: found %d results", result.Hits.Total.Value)
|
|
}
|
|
|
|
func TestMatchQuery(t *testing.T) {
|
|
query := MatchQuery("field", "value")
|
|
|
|
if query == nil {
|
|
t.Error("MatchQuery() returned nil")
|
|
}
|
|
|
|
if _, ok := query["match"]; !ok {
|
|
t.Error("MatchQuery() missing 'match' key")
|
|
}
|
|
|
|
t.Log("MatchQuery test passed")
|
|
}
|
|
|
|
func TestTermQuery(t *testing.T) {
|
|
query := TermQuery("field", "value")
|
|
|
|
if query == nil {
|
|
t.Error("TermQuery() returned nil")
|
|
}
|
|
|
|
if _, ok := query["term"]; !ok {
|
|
t.Error("TermQuery() missing 'term' key")
|
|
}
|
|
|
|
t.Log("TermQuery test passed")
|
|
}
|
|
|
|
func TestRangeQuery(t *testing.T) {
|
|
query := RangeQuery("age", 18, 65)
|
|
|
|
if query == nil {
|
|
t.Error("RangeQuery() returned nil")
|
|
}
|
|
|
|
if _, ok := query["range"]; !ok {
|
|
t.Error("RangeQuery() missing 'range' key")
|
|
}
|
|
|
|
t.Log("RangeQuery test passed")
|
|
}
|
|
|
|
func TestBoolQuery(t *testing.T) {
|
|
boolQ := &BoolQuery{
|
|
Must: []map[string]any{
|
|
MatchQuery("field", "value"),
|
|
},
|
|
}
|
|
|
|
query := boolQ.ToBoolQuery()
|
|
|
|
if query == nil {
|
|
t.Error("ToBoolQuery() returned nil")
|
|
}
|
|
|
|
if _, ok := query["bool"]; !ok {
|
|
t.Error("ToBoolQuery() missing 'bool' key")
|
|
}
|
|
|
|
t.Log("BoolQuery test passed")
|
|
}
|