Path: blob/main/pkg/metrics/instance/configstore/remote_test.go
5340 views
package configstore12import (3"context"4"fmt"5"sort"6"strings"7"testing"8"time"910"github.com/go-kit/log"11"github.com/grafana/agent/pkg/metrics/instance"12"github.com/grafana/agent/pkg/util"13"github.com/grafana/dskit/kv"14"github.com/prometheus/client_golang/prometheus"15"github.com/stretchr/testify/require"16)1718func TestRemote_List(t *testing.T) {19remote, err := NewRemote(log.NewNopLogger(), prometheus.NewRegistry(), kv.Config{20Store: "inmemory",21Prefix: "configs/",22}, true)23require.NoError(t, err)24t.Cleanup(func() {25err := remote.Close()26require.NoError(t, err)27})2829cfgs := []string{"a", "b", "c"}30for _, cfg := range cfgs {31err := remote.kv.CAS(context.Background(), cfg, func(in interface{}) (out interface{}, retry bool, err error) {32return fmt.Sprintf("name: %s", cfg), false, nil33})34require.NoError(t, err)35}3637list, err := remote.List(context.Background())38require.NoError(t, err)39sort.Strings(list)40require.Equal(t, cfgs, list)41}4243func TestRemote_Get(t *testing.T) {44remote, err := NewRemote(log.NewNopLogger(), prometheus.NewRegistry(), kv.Config{45Store: "inmemory",46Prefix: "configs/",47}, true)48require.NoError(t, err)49t.Cleanup(func() {50err := remote.Close()51require.NoError(t, err)52})5354err = remote.kv.CAS(context.Background(), "someconfig", func(in interface{}) (out interface{}, retry bool, err error) {55return "name: someconfig", false, nil56})57require.NoError(t, err)5859cfg, err := remote.Get(context.Background(), "someconfig")60require.NoError(t, err)6162expect := instance.DefaultConfig63expect.Name = "someconfig"64require.Equal(t, expect, cfg)65}6667func TestRemote_Put(t *testing.T) {68remote, err := NewRemote(log.NewNopLogger(), prometheus.NewRegistry(), kv.Config{69Store: "inmemory",70Prefix: "configs/",71}, true)72require.NoError(t, err)73t.Cleanup(func() {74err := remote.Close()75require.NoError(t, err)76})7778cfg := instance.DefaultConfig79cfg.Name = "newconfig"8081created, err := remote.Put(context.Background(), cfg)82require.NoError(t, err)83require.True(t, created)8485actual, err := remote.Get(context.Background(), "newconfig")86require.NoError(t, err)87require.Equal(t, cfg, actual)8889t.Run("Updating", func(t *testing.T) {90cfg := instance.DefaultConfig91cfg.Name = "newconfig"92cfg.HostFilter = true9394created, err := remote.Put(context.Background(), cfg)95require.NoError(t, err)96require.False(t, created)97})98}99100func TestRemote_Put_NonUnique(t *testing.T) {101var (102conflictingA = util.Untab(`103name: conflicting-a104scrape_configs:105- job_name: foobar106`)107conflictingB = util.Untab(`108name: conflicting-b109scrape_configs:110- job_name: fizzbuzz111- job_name: foobar112`)113)114115conflictingACfg, err := instance.UnmarshalConfig(strings.NewReader(conflictingA))116require.NoError(t, err)117118conflictingBCfg, err := instance.UnmarshalConfig(strings.NewReader(conflictingB))119require.NoError(t, err)120121remote, err := NewRemote(log.NewNopLogger(), prometheus.NewRegistry(), kv.Config{122Store: "inmemory",123Prefix: "configs/",124}, true)125require.NoError(t, err)126t.Cleanup(func() {127err := remote.Close()128require.NoError(t, err)129})130131created, err := remote.Put(context.Background(), *conflictingACfg)132require.NoError(t, err)133require.True(t, created)134135_, err = remote.Put(context.Background(), *conflictingBCfg)136require.EqualError(t, err, fmt.Sprintf("failed to check uniqueness of config: found multiple scrape configs in config store with job name %q", "foobar"))137}138139func TestRemote_Delete(t *testing.T) {140remote, err := NewRemote(log.NewNopLogger(), prometheus.NewRegistry(), kv.Config{141Store: "inmemory",142Prefix: "configs/",143}, true)144require.NoError(t, err)145t.Cleanup(func() {146err := remote.Close()147require.NoError(t, err)148})149150var cfg instance.Config151cfg.Name = "deleteme"152153created, err := remote.Put(context.Background(), cfg)154require.NoError(t, err)155require.True(t, created)156157err = remote.Delete(context.Background(), "deleteme")158require.NoError(t, err)159160_, err = remote.Get(context.Background(), "deleteme")161require.EqualError(t, err, "configuration deleteme does not exist")162163err = remote.Delete(context.Background(), "deleteme")164require.EqualError(t, err, "configuration deleteme does not exist")165}166167func TestRemote_All(t *testing.T) {168remote, err := NewRemote(log.NewNopLogger(), prometheus.NewRegistry(), kv.Config{169Store: "inmemory",170Prefix: "all-configs/",171}, true)172require.NoError(t, err)173t.Cleanup(func() {174err := remote.Close()175require.NoError(t, err)176})177178cfgs := []string{"a", "b", "c"}179for _, cfg := range cfgs {180err := remote.kv.CAS(context.Background(), cfg, func(in interface{}) (out interface{}, retry bool, err error) {181return fmt.Sprintf("name: %s", cfg), false, nil182})183require.NoError(t, err)184}185186configCh, err := remote.All(context.Background(), nil)187require.NoError(t, err)188189var gotConfigs []string190for gotConfig := range configCh {191gotConfigs = append(gotConfigs, gotConfig.Name)192}193sort.Strings(gotConfigs)194195require.Equal(t, cfgs, gotConfigs)196}197198func TestRemote_Watch(t *testing.T) {199remote, err := NewRemote(log.NewNopLogger(), prometheus.NewRegistry(), kv.Config{200Store: "inmemory",201Prefix: "watch-configs/",202}, true)203require.NoError(t, err)204t.Cleanup(func() {205err := remote.Close()206require.NoError(t, err)207})208209_, err = remote.Put(context.Background(), instance.Config{Name: "watch"})210require.NoError(t, err)211212select {213case cfg := <-remote.Watch():214require.Equal(t, "watch", cfg.Key)215require.NotNil(t, cfg.Config)216require.Equal(t, "watch", cfg.Config.Name)217case <-time.After(3 * time.Second):218require.FailNow(t, "failed to watch for config")219}220221// Make sure Watch gets other updates.222_, err = remote.Put(context.Background(), instance.Config{Name: "watch2"})223require.NoError(t, err)224225select {226case cfg := <-remote.Watch():227require.Equal(t, "watch2", cfg.Key)228require.NotNil(t, cfg.Config)229require.Equal(t, "watch2", cfg.Config.Name)230case <-time.After(3 * time.Second):231require.FailNow(t, "failed to watch for config")232}233}234235func TestRemote_ApplyConfig(t *testing.T) {236remote, err := NewRemote(log.NewNopLogger(), prometheus.NewRegistry(), kv.Config{237Store: "inmemory",238Prefix: "test-applyconfig/",239}, true)240require.NoError(t, err)241t.Cleanup(func() {242err := remote.Close()243require.NoError(t, err)244})245246err = remote.ApplyConfig(kv.Config{247Store: "inmemory",248Prefix: "test-applyconfig2/",249}, true)250require.NoError(t, err, "failed to apply a new config")251252err = remote.ApplyConfig(kv.Config{253Store: "inmemory",254Prefix: "test-applyconfig2/",255}, true)256require.NoError(t, err, "failed to re-apply the current config")257258// Make sure watch still works259_, err = remote.Put(context.Background(), instance.Config{Name: "watch"})260require.NoError(t, err)261262select {263case cfg := <-remote.Watch():264require.Equal(t, "watch", cfg.Key)265require.NotNil(t, cfg.Config)266require.Equal(t, "watch", cfg.Config.Name)267case <-time.After(3 * time.Second):268require.FailNow(t, "failed to watch for config")269}270}271272273