* feat: Read/write validation working, simple search * feat: WIP on adding search for each trace * feat: exposed port 4317 * feat: Extracted write, read, search into separate methods * feat: Updated to use new service code * feat: Added MockClock; fixed an error in a prev mock * feat: Added tests for the three parts of the validation * feat: Added runValidation test * docs: Updated changelog * docs: CHANGELOG.md without Prettier LOL * fix: Updates for linter * fix: more linter changes * feat: Added new methods to create OTLP exporters with auth enabled Also updated old functions to call the new, for backward compatibility * feat: Added TempoBasicAuthToken to ValidationConfig * feat: Updated to use new auth-enabled versions * feat: Added EmitBatchesWithContext * feat: Moved validationConfig setup to its own function * chore: lowercase errors * feat: Added context-aware methods * feat: Added methods to mocks * fix: return 1 rather than exit * renamed sleep method * fix: linter issue * WIP on validateTraceSearch * feat: Set ingester rf to 3; formatting * feat: Test updates * fix: linter issues * fix: moar linter issues * feat: Made TEMPO_ACCESS_POLICY_TOKEN a const * feat: Also moved defer() statement * feat: PR comment fixes - Use debug level in that debug function - return err instead of ctx.Err() - Update vs.sleepWithContext to use the vs.clock so it's faster in tests * feat: Add constants for headers * feat: Refactor for withContext Merged all of my new 'withContext' metjods with their originals, and updated all the callers to pass in context.Background() so it would compile * feat: Update to use the new const * docs: Changelog formatting * feat: rename header
193 lines
6.1 KiB
Go
193 lines
6.1 KiB
Go
package deployments
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/grafana/e2e"
|
|
e2edb "github.com/grafana/e2e/db"
|
|
"github.com/grafana/tempo/integration/util"
|
|
"github.com/grafana/tempo/pkg/httpclient"
|
|
tempoUtil "github.com/grafana/tempo/pkg/util"
|
|
"github.com/prometheus/prometheus/model/labels"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
const configMicroservices = "config-microservices.tmpl.yaml"
|
|
|
|
func TestMicroservicesWithKVStores(t *testing.T) {
|
|
testKVStores := []struct {
|
|
name string
|
|
kvconfig func(hostname string, port int) string
|
|
}{
|
|
{
|
|
name: "memberlist",
|
|
kvconfig: func(string, int) string {
|
|
return `
|
|
store: memberlist`
|
|
},
|
|
},
|
|
{
|
|
name: "etcd",
|
|
kvconfig: func(hostname string, port int) string {
|
|
return fmt.Sprintf(`
|
|
store: etcd
|
|
etcd:
|
|
endpoints:
|
|
- http://%s:%d`, hostname, port)
|
|
},
|
|
},
|
|
{
|
|
name: "consul",
|
|
kvconfig: func(hostname string, port int) string {
|
|
return fmt.Sprintf(`
|
|
store: consul
|
|
consul:
|
|
host: http://%s:%d`, hostname, port)
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range testKVStores {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
s, err := e2e.NewScenario("tempo_e2e")
|
|
require.NoError(t, err)
|
|
defer s.Close()
|
|
|
|
// Set up KVStore
|
|
var kvstore *e2e.HTTPService
|
|
switch tc.name {
|
|
case "etcd":
|
|
kvstore = e2edb.NewETCD()
|
|
require.NoError(t, s.StartAndWaitReady(kvstore))
|
|
case "consul":
|
|
kvstore = e2edb.NewConsul()
|
|
require.NoError(t, s.StartAndWaitReady(kvstore))
|
|
case "memberlist":
|
|
default:
|
|
t.Errorf("unknown KVStore %s", tc.name)
|
|
}
|
|
|
|
KVStoreConfig := tc.kvconfig("", 0)
|
|
if kvstore != nil {
|
|
KVStoreConfig = tc.kvconfig(kvstore.Name(), kvstore.HTTPPort())
|
|
}
|
|
|
|
// copy config template to shared directory and expand template variables
|
|
tmplConfig := map[string]any{"KVStore": KVStoreConfig}
|
|
_, err = util.CopyTemplateToSharedDir(s, configMicroservices, "config.yaml", tmplConfig)
|
|
require.NoError(t, err)
|
|
|
|
minio := e2edb.NewMinio(9000, "tempo")
|
|
require.NotNil(t, minio)
|
|
require.NoError(t, s.StartAndWaitReady(minio))
|
|
|
|
tempoIngester1 := util.NewTempoIngester(1)
|
|
tempoIngester2 := util.NewTempoIngester(2)
|
|
tempoIngester3 := util.NewTempoIngester(3)
|
|
|
|
tempoDistributor := util.NewTempoDistributor()
|
|
tempoQueryFrontend := util.NewTempoQueryFrontend()
|
|
tempoQuerier := util.NewTempoQuerier()
|
|
require.NoError(t, s.StartAndWaitReady(tempoIngester1, tempoIngester2, tempoIngester3, tempoDistributor, tempoQueryFrontend, tempoQuerier))
|
|
|
|
// wait for active ingesters
|
|
time.Sleep(1 * time.Second)
|
|
matchers := []*labels.Matcher{
|
|
{
|
|
Type: labels.MatchEqual,
|
|
Name: "name",
|
|
Value: "ingester",
|
|
},
|
|
{
|
|
Type: labels.MatchEqual,
|
|
Name: "state",
|
|
Value: "ACTIVE",
|
|
},
|
|
}
|
|
require.NoError(t, tempoDistributor.WaitSumMetricsWithOptions(e2e.Equals(3), []string{`tempo_ring_members`}, e2e.WithLabelMatchers(matchers...), e2e.WaitMissingMetrics))
|
|
|
|
// Get port for the Jaeger gRPC receiver endpoint
|
|
c, err := util.NewJaegerToOTLPExporter(tempoDistributor.Endpoint(4317))
|
|
require.NoError(t, err)
|
|
require.NotNil(t, c)
|
|
|
|
info := tempoUtil.NewTraceInfo(time.Now(), "")
|
|
require.NoError(t, info.EmitAllBatches(c))
|
|
|
|
expected, err := info.ConstructTraceFromEpoch()
|
|
require.NoError(t, err)
|
|
|
|
// test metrics
|
|
require.NoError(t, tempoDistributor.WaitSumMetrics(e2e.Equals(util.SpanCount(expected)), "tempo_distributor_spans_received_total"))
|
|
|
|
// test echo
|
|
util.AssertEcho(t, "http://"+tempoQueryFrontend.Endpoint(3200)+"/api/echo")
|
|
|
|
apiClient := httpclient.New("http://"+tempoQueryFrontend.Endpoint(3200), "")
|
|
|
|
// query an in-memory trace
|
|
util.QueryAndAssertTrace(t, apiClient, info)
|
|
|
|
// wait trace_idle_time and ensure trace is created in ingester
|
|
require.NoError(t, tempoIngester1.WaitSumMetricsWithOptions(e2e.Less(3), []string{"tempo_ingester_traces_created_total"}, e2e.WaitMissingMetrics))
|
|
require.NoError(t, tempoIngester2.WaitSumMetricsWithOptions(e2e.Less(3), []string{"tempo_ingester_traces_created_total"}, e2e.WaitMissingMetrics))
|
|
require.NoError(t, tempoIngester3.WaitSumMetricsWithOptions(e2e.Less(3), []string{"tempo_ingester_traces_created_total"}, e2e.WaitMissingMetrics))
|
|
|
|
// flush trace to backend
|
|
util.CallFlush(t, tempoIngester1)
|
|
util.CallFlush(t, tempoIngester2)
|
|
util.CallFlush(t, tempoIngester3)
|
|
|
|
// search for trace
|
|
util.SearchAndAssertTrace(t, apiClient, info)
|
|
util.SearchTraceQLAndAssertTrace(t, apiClient, info)
|
|
|
|
// sleep for one maintenance cycle
|
|
time.Sleep(5 * time.Second)
|
|
|
|
// test metrics
|
|
for _, i := range []*e2e.HTTPService{tempoIngester1, tempoIngester2, tempoIngester3} {
|
|
require.NoError(t, i.WaitSumMetrics(e2e.Equals(1), "tempo_ingester_blocks_flushed_total"))
|
|
}
|
|
require.NoError(t, tempoQuerier.WaitSumMetrics(e2e.Equals(3), "tempodb_blocklist_length"))
|
|
require.NoError(t, tempoQueryFrontend.WaitSumMetrics(e2e.Equals(4), "tempo_query_frontend_queries_total"))
|
|
|
|
// query trace - should fetch from backend
|
|
util.QueryAndAssertTrace(t, apiClient, info)
|
|
|
|
// stop an ingester and confirm we can still write and query
|
|
err = tempoIngester2.Kill()
|
|
require.NoError(t, err)
|
|
|
|
// sleep for heartbeat timeout
|
|
time.Sleep(1 * time.Second)
|
|
|
|
info = tempoUtil.NewTraceInfo(time.Now(), "")
|
|
require.NoError(t, info.EmitAllBatches(c))
|
|
|
|
// query by id
|
|
util.QueryAndAssertTrace(t, apiClient, info)
|
|
|
|
// wait trace_idle_time and ensure trace is created in ingester
|
|
require.NoError(t, tempoIngester1.WaitSumMetricsWithOptions(e2e.Less(4), []string{"tempo_ingester_traces_created_total"}, e2e.WaitMissingMetrics))
|
|
require.NoError(t, tempoIngester3.WaitSumMetricsWithOptions(e2e.Less(4), []string{"tempo_ingester_traces_created_total"}, e2e.WaitMissingMetrics))
|
|
|
|
// flush trace to backend
|
|
util.CallFlush(t, tempoIngester1)
|
|
util.CallFlush(t, tempoIngester3)
|
|
|
|
// search for trace
|
|
util.SearchAndAssertTrace(t, apiClient, info)
|
|
|
|
// stop another ingester and confirm things fail
|
|
err = tempoIngester1.Kill()
|
|
require.NoError(t, err)
|
|
|
|
require.Error(t, info.EmitBatches(context.Background(), c))
|
|
})
|
|
}
|
|
}
|