systemtest/estest/search.go (112 lines of code) (raw):
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package estest
import (
"bytes"
"context"
"net/http"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/elastic/apm-tools/pkg/espoll"
"github.com/elastic/go-elasticsearch/v8/esapi"
)
func ExpectDocs(t testing.TB, es *espoll.Client, index string, query interface{}, opts ...espoll.RequestOption) espoll.SearchResult {
t.Helper()
return ExpectMinDocs(t, es, 1, index, query, opts...)
}
// ExpectMinDocs searches index with query, returning the results.
//
// If the search returns fewer than min results within 10 seconds
// (by default), ExpectMinDocs will call t.Error().
func ExpectMinDocs(t testing.TB, es *espoll.Client, min int, index string, query interface{}, opts ...espoll.RequestOption) espoll.SearchResult {
t.Helper()
var result espoll.SearchResult
req := es.NewSearchRequest(index)
req.ExpandWildcards = "open,hidden"
if min > 10 {
// Size defaults to 10. If the caller expects more than 10,
// return it in the search so we don't have to search again.
req = req.WithSize(min)
}
if query != nil {
req = req.WithQuery(query)
}
opts = append(opts, espoll.WithCondition(espoll.AllCondition(
result.Hits.MinHitsCondition(min),
result.Hits.TotalHitsCondition(req),
)))
// Refresh the indices before issuing the search request.
refreshReq := esapi.IndicesRefreshRequest{
Index: strings.Split(",", index),
ExpandWildcards: "all",
}
rsp, err := refreshReq.Do(context.Background(), es.Transport)
if err != nil {
t.Fatalf("failed refreshing indices: %s: %s", index, err.Error())
}
rsp.Body.Close()
if _, err := req.Do(context.Background(), &result, opts...); err != nil {
t.Fatal(err)
}
return result
}
func ExpectSourcemapError(t testing.TB, es *espoll.Client, index string, retry func(), query interface{}, updated bool) espoll.SearchResult {
t.Helper()
deadline := time.After(5 * time.Second)
ticker := time.NewTicker(100 * time.Millisecond)
defer ticker.Stop()
for {
select {
case <-deadline:
t.Fatal("timed out while querying es")
case <-ticker.C:
rsp, err := es.Do(context.Background(), &esapi.IndicesDeleteDataStreamRequest{
Name: []string{index},
ExpandWildcards: "all",
}, nil)
require.NoError(t, err)
require.NoError(t, rsp.Body.Close())
require.Equal(t, http.StatusOK, rsp.StatusCode)
retry()
result := ExpectDocs(t, es, index, query)
if isFetcherAvailable(t, result) {
assertSourcemapUpdated(t, result, updated)
return result
}
}
}
}
func isFetcherAvailable(t testing.TB, result espoll.SearchResult) bool {
t.Helper()
for _, sh := range result.Hits.Hits {
if bytes.Contains(sh.RawSource, []byte("metadata fetcher is not ready: fetcher unavailable")) {
return false
}
}
return true
}
func assertSourcemapUpdated(t testing.TB, result espoll.SearchResult, updated bool) {
t.Helper()
type StacktraceFrame struct {
Sourcemap struct {
Updated bool
}
}
type Error struct {
Exception []struct {
Stacktrace []StacktraceFrame
}
Log struct {
Stacktrace []StacktraceFrame
}
}
for _, hit := range result.Hits.Hits {
var source struct {
Error Error
}
err := hit.UnmarshalSource(&source)
require.NoError(t, err)
for _, exception := range source.Error.Exception {
for _, stacktrace := range exception.Stacktrace {
assert.Equal(t, updated, stacktrace.Sourcemap.Updated)
}
}
for _, stacktrace := range source.Error.Log.Stacktrace {
assert.Equal(t, updated, stacktrace.Sourcemap.Updated)
}
}
}