stevenbooru/vendor/src/github.com/peterbourgon/elasticsearch/cluster_test.go

500 lines
11 KiB
Go

// +build cluster
// This file is only built and run if you specify
// -tags=cluster as part of the 'go test' invocation.
// http://golang.org/pkg/go/build/#Build_Constraints
package elasticsearch_test
import (
"bytes"
"encoding/json"
"fmt"
es "github.com/peterbourgon/elasticsearch"
"io/ioutil"
"net/http"
"testing"
"time"
)
func init() {
waitForCluster(15 * time.Second)
}
// Just tests es.Cluster internals; doesn't make any real connection.
func TestClusterShutdown(t *testing.T) {
endpoints := []string{"http://host1:9200", "http://host2:9200"}
pingInterval, pingTimeout := 30*time.Second, 3*time.Second
c := es.NewCluster(endpoints, pingInterval, pingTimeout)
e := make(chan error)
go func() {
c.Shutdown()
e <- nil
}()
go func() {
<-time.After(1 * time.Second)
e <- fmt.Errorf("timeout")
}()
if err := <-e; err != nil {
t.Fatalf("%s", err)
}
}
func TestClusterIndex(t *testing.T) {
c := newCluster(t, []string{"twitter"}, nil)
defer c.Shutdown()
defer deleteIndices(t, []string{"twitter"})
response, err := c.Index(es.IndexRequest{
es.IndexParams{
Index: "twitter",
Type: "tweet",
Id: "1",
Refresh: "true",
},
map[string]interface{}{
"name": "John",
},
})
if err != nil {
t.Fatal(err)
}
if response.Error != "" {
t.Error(response.Error)
}
if expected, got := 1, response.Version; expected != got {
t.Errorf("expected version to be %d; got %d", expected, got)
}
}
func TestClusterCreate(t *testing.T) {
c := newCluster(t, []string{"twitter"}, nil)
defer c.Shutdown()
defer deleteIndices(t, []string{"twitter"})
response, err := c.Create(es.CreateRequest{
es.IndexParams{
Index: "twitter",
Type: "tweet",
Id: "1",
Refresh: "true",
},
map[string]interface{}{
"name": "John",
},
})
if err != nil {
t.Fatal(err)
}
if response.Error != "" {
t.Error(response.Error)
}
if expected, got := 1, response.Version; expected != got {
t.Errorf("expected version to be %d; got %d", expected, got)
}
}
func TestClusterUpdate(t *testing.T) {
c := newCluster(t, []string{"twitter"}, map[string]interface{}{
"/twitter/tweet/1": map[string]string{
"name": "John",
},
})
defer c.Shutdown()
defer deleteIndices(t, []string{"twitter"})
response, err := c.Update(es.UpdateRequest{
es.IndexParams{
Index: "twitter",
Type: "tweet",
Id: "1",
Refresh: "true",
},
map[string]interface{}{
"script": `ctx._source.text = "some text"`,
},
})
if err != nil {
t.Fatal(err)
}
if response.Error != "" {
t.Error(response.Error)
}
if expected, got := 2, response.Version; expected != got {
t.Errorf("expected version to be %d; got %d", expected, got)
}
}
func TestClusterDelete(t *testing.T) {
c := newCluster(t, []string{"twitter"}, map[string]interface{}{
"/twitter/tweet/1": map[string]string{
"name": "John",
},
})
defer c.Shutdown()
defer deleteIndices(t, []string{"twitter"})
response, err := c.Delete(es.DeleteRequest{
es.IndexParams{
Index: "twitter",
Type: "tweet",
Id: "1",
Refresh: "true",
},
})
if err != nil {
t.Fatal(err)
}
if response.Error != "" {
t.Error(response.Error)
}
if expected, got := 2, response.Version; expected != got {
t.Errorf("expected version to be %d; got %d", expected, got)
}
}
func TestClusterBulk(t *testing.T) {
c := newCluster(t, []string{"twitter"}, map[string]interface{}{
"/twitter/tweet/1": map[string]string{
"name": "John",
},
})
defer c.Shutdown()
defer deleteIndices(t, []string{"twitter"})
response, err := c.Bulk(es.BulkRequest{
es.BulkParams{Refresh: "true"},
[]es.BulkIndexable{
es.IndexRequest{
es.IndexParams{Index: "twitter", Type: "tweet", Id: "1"},
map[string]interface{}{"name": "James"},
},
es.DeleteRequest{
es.IndexParams{Index: "twitter", Type: "tweet", Id: "2"},
},
es.CreateRequest{
es.IndexParams{Index: "twitter", Type: "tweet", Id: "3"},
map[string]interface{}{"name": "John"},
},
},
})
if err != nil {
t.Fatal(err)
}
if len(response.Items) != 3 {
t.Fatalf("expected 3 responses, got %d", len(response.Items))
}
if expected, got := 2, response.Items[0].Version; expected != got {
t.Errorf("expected version of doc to be %d; got %d", expected, got)
}
if expected, got := false, response.Items[1].Found; expected != got {
t.Errorf("expected delete op to return found = false")
}
if expected, got := 1, response.Items[2].Version; expected != got {
t.Errorf("expected version of doc to be %d; got %d", expected, got)
}
}
func TestSimpleTermQuery(t *testing.T) {
indices := []string{"twitter"}
c := newCluster(t, indices, map[string]interface{}{
"/twitter/tweet/1": map[string]string{
"user": "kimchy",
"post_date": "2009-11-15T14:12:12",
"message": "trying out Elastic Search",
},
})
defer c.Shutdown()
defer deleteIndices(t, indices) // comment out to leave data after test
q := es.QueryWrapper(es.TermQuery(es.TermQueryParams{
Query: &es.Wrapper{
Name: "user",
Wrapped: "kimchy",
},
}))
request := es.SearchRequest{
es.SearchParams{
Indices: []string{"twitter"},
Types: []string{"tweet"},
},
q,
}
response, err := c.Search(request)
if err != nil {
t.Error(err)
}
if response.Error != "" {
t.Error(response.Error)
}
if expected, got := 1, response.HitsWrapper.Total; expected != got {
t.Fatalf("expected %d, got %d", expected, got)
}
t.Logf("OK, %d hit(s), %dms", response.HitsWrapper.Total, response.Took)
}
func TestMultiSearch(t *testing.T) {
indices := []string{"index1", "index2"}
c := newCluster(t, indices, map[string]interface{}{
"/index1/foo/1": map[string]string{
"user": "alice",
"description": "index=index1 type=foo id=1 user=alice",
},
"/index2/bar/2": map[string]string{
"user": "bob",
"description": "index=index2 type=bar id=2 user=bob",
},
})
defer c.Shutdown()
defer deleteIndices(t, indices) // comment out to leave data after test
q1 := es.QueryWrapper(es.TermQuery(es.TermQueryParams{
Query: &es.Wrapper{
Name: "user",
Wrapped: "alice",
},
}))
q2 := es.QueryWrapper(es.TermQuery(es.TermQueryParams{
Query: &es.Wrapper{
Name: "user",
Wrapped: "bob",
},
}))
q3 := es.QueryWrapper(es.MatchAllQuery())
request := es.MultiSearchRequest{
Requests: []es.SearchRequest{
es.SearchRequest{
es.SearchParams{
Indices: []string{"index1"},
Types: []string{"foo"},
},
q1,
},
es.SearchRequest{
es.SearchParams{
Indices: []string{"index2"},
Types: []string{"bar"},
},
q2,
},
es.SearchRequest{
es.SearchParams{
Indices: []string{}, // "index1", "index2" is not supported (!)
Types: []string{}, // "type1", "type2" is not supported (!)
},
q3,
},
},
}
response, err := c.MultiSearch(request)
if err != nil {
t.Fatal(err)
}
if expected, got := 3, len(response.Responses); expected != got {
t.Fatalf("expected %d response(s), got %d", expected, got)
}
r1 := response.Responses[0]
if r1.Error != "" {
t.Fatalf("response 1: %s", r1.Error)
}
if expected, got := 1, r1.HitsWrapper.Total; expected != got {
t.Fatalf("response 1: expected %d hit(s), got %d", expected, got)
}
buf, _ := json.Marshal(r1)
t.Logf("response 1 OK: %s", buf)
r2 := response.Responses[1]
if r2.Error != "" {
t.Fatalf("response 2: %s", r1.Error)
}
if expected, got := 1, r2.HitsWrapper.Total; expected != got {
t.Fatalf("response 2: expected %d hit(s), got %d", expected, got)
}
buf, _ = json.Marshal(r2)
t.Logf("response 2 OK: %s", buf)
r3 := response.Responses[2]
if r3.Error != "" {
t.Fatalf("response 3: %s", r1.Error)
}
if expected, got := 2, r3.HitsWrapper.Total; expected != got {
t.Fatalf("response 3: expected %d hit(s), got %d", expected, got)
}
buf, _ = json.Marshal(r3)
t.Logf("response 3 OK: %s", buf)
}
func TestConstantScoreNoScore(t *testing.T) {
indices := []string{"twitter"}
c := newCluster(t, indices, map[string]interface{}{
"/twitter/tweet/1": map[string]string{
"user": "kimchy",
"post_date": "2009-11-15T14:12:12",
"message": "trying out Elastic Search",
},
})
defer c.Shutdown()
defer deleteIndices(t, indices) // comment out to leave data after test
q := map[string]interface{}{
"size": 20,
"sort": []string{"post_date"},
"filter": map[string]interface{}{
"and": []map[string]interface{}{
map[string]interface{}{
"type": map[string]string{"value": "tweet"},
},
},
},
"query": map[string]interface{}{
"constant_score": map[string]interface{}{
"filter": map[string]interface{}{
"term": map[string]string{"user": "kimchy"},
},
},
},
}
request := es.SearchRequest{
es.SearchParams{
Indices: []string{"twitter"},
Types: []string{"tweet"},
},
q,
}
response, err := c.Search(request)
if err != nil {
t.Fatalf("Search: %s", err)
}
buf, _ := json.Marshal(response)
t.Logf("got response: %s", buf)
if response.Error != "" {
t.Error(response.Error)
}
if expected, got := 1, response.HitsWrapper.Total; expected != got {
t.Fatalf("expected %d, got %d", expected, got)
}
if response.HitsWrapper.Hits[0].Score != nil {
t.Fatalf("score: expected nil, got something")
}
t.Logf("OK, %d hit(s), %dms", response.HitsWrapper.Total, response.Took)
}
//
//
//
func waitForCluster(timeout time.Duration) {
giveUp := time.After(timeout)
delay := 100 * time.Millisecond
for {
_, err := http.Get("http://127.0.0.1:9200")
if err == nil {
fmt.Printf("ElasticSearch now available\n")
return // great
}
fmt.Printf("ElasticSearch not ready yet; waiting %s\n", delay)
select {
case <-time.After(delay):
delay *= 2
case <-giveUp:
panic("ElasticSearch didn't come up in time")
}
}
}
func newCluster(t *testing.T, indices []string, m map[string]interface{}) *es.Cluster {
deleteIndices(t, indices)
loadData(t, m)
endpoints := []string{"http://localhost:9200"}
pingInterval, pingTimeout := 10*time.Second, 3*time.Second
return es.NewCluster(endpoints, pingInterval, pingTimeout)
}
func deleteIndices(t *testing.T, indices []string) {
for _, index := range indices {
// refresh=true to make document(s) immediately deleted
url := "http://127.0.0.1:9200/" + index + "?refresh=true"
req, err := http.NewRequest("DELETE", url, nil)
if err != nil {
t.Fatal(err)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
t.Fatal(err)
}
respBuf, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
t.Fatal(err)
}
t.Logf("DELETE %s: %s", index, respBuf)
}
}
func loadData(t *testing.T, m map[string]interface{}) {
for path, body := range m {
reqBytes, err := json.Marshal(body)
if err != nil {
t.Fatal(err)
}
// refresh=true to make document(s) immediately searchable
url := "http://127.0.0.1:9200" + path + "?refresh=true"
req, err := http.NewRequest("PUT", url, bytes.NewBuffer(reqBytes))
if err != nil {
t.Fatal(err)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
t.Fatal(err)
}
respBuf, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
t.Fatal(err)
}
t.Logf("PUT %s: %s", path, respBuf)
}
}