github.com/grafana/pyroscope@v1.18.0/pkg/metastore/test/create.go (about) 1 package test 2 3 import ( 4 "context" 5 "fmt" 6 "testing" 7 "time" 8 9 "github.com/go-kit/log" 10 "github.com/grafana/dskit/services" 11 "github.com/hashicorp/raft" 12 "github.com/prometheus/client_golang/prometheus" 13 "github.com/stretchr/testify/assert" 14 "github.com/stretchr/testify/mock" 15 "github.com/stretchr/testify/require" 16 "github.com/thanos-io/objstore" 17 "google.golang.org/grpc" 18 19 metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" 20 "github.com/grafana/pyroscope/pkg/metastore" 21 metastoreclient "github.com/grafana/pyroscope/pkg/metastore/client" 22 "github.com/grafana/pyroscope/pkg/metastore/discovery" 23 "github.com/grafana/pyroscope/pkg/metastore/raftnode/raftnodepb" 24 placement "github.com/grafana/pyroscope/pkg/segmentwriter/client/distributor/placement/adaptiveplacement" 25 "github.com/grafana/pyroscope/pkg/test" 26 "github.com/grafana/pyroscope/pkg/test/mocks/mockdiscovery" 27 "github.com/grafana/pyroscope/pkg/util/health" 28 "github.com/grafana/pyroscope/pkg/validation" 29 ) 30 31 func NewMetastoreSet(t *testing.T, cfg *metastore.Config, n int, bucket objstore.Bucket) MetastoreSet { 32 l := test.NewTestingLogger(t) 33 34 grpcAddresses := make([]string, n) 35 raftAddresses := make([]string, n) 36 raftIds := make([]string, n) 37 bootstrapPeers := make([]string, n) 38 for i := 0; i < n; i++ { 39 grpcAddresses[i] = fmt.Sprintf("localhost:%d", 10500+i) 40 raftAddresses[i] = fmt.Sprintf("localhost:%d", 10500+2*i) 41 raftIds[i] = fmt.Sprintf("node-%d", i) 42 bootstrapPeers[i] = fmt.Sprintf("%s/%s", raftAddresses[i], raftIds[i]) 43 } 44 l.Log("grpcAddresses", fmt.Sprintf("%+v", grpcAddresses), "raftAddresses", fmt.Sprintf("%+v", raftAddresses)) 45 46 configs := make([]metastore.Config, n) 47 for i := 0; i < n; i++ { 48 icfg := *cfg 49 icfg.MinReadyDuration = 0 50 icfg.Address = grpcAddresses[i] 51 icfg.FSM.DataDir = t.TempDir() 52 icfg.Raft.ServerID = raftIds[i] 53 icfg.Raft.Dir = t.TempDir() 54 icfg.Raft.AdvertiseAddress = raftAddresses[i] 55 icfg.Raft.BindAddress = raftAddresses[i] 56 icfg.Raft.BootstrapPeers = bootstrapPeers 57 icfg.Raft.BootstrapExpectPeers = n 58 configs[i] = icfg 59 } 60 61 servers := make([]discovery.Server, n) 62 for i := 0; i < n; i++ { 63 srv := discovery.Server{ 64 Raft: raft.Server{ 65 ID: raft.ServerID(raftIds[i]), 66 Address: raft.ServerAddress(raftAddresses[i]), 67 }, 68 ResolvedAddress: grpcAddresses[i], 69 } 70 servers[i] = srv 71 } 72 73 listeners, dialOpt := test.CreateInMemoryListeners(grpcAddresses) 74 d := MockStaticDiscovery(t, servers) 75 client := metastoreclient.New(l, cfg.GRPCClientConfig, d, dialOpt) 76 err := client.Service().StartAsync(context.Background()) 77 require.NoError(t, err) 78 79 res := MetastoreSet{ 80 t: t, 81 } 82 83 for i := 0; i < n; i++ { 84 options, err := cfg.GRPCClientConfig.DialOption(nil, nil, nil) 85 require.NoError(t, err) 86 options = append(options, dialOpt) 87 cc, err := grpc.Dial(grpcAddresses[i], options...) 88 require.NoError(t, err) 89 logger := log.With(l, "idx", bootstrapPeers[i]) 90 server := grpc.NewServer() 91 registry := prometheus.NewRegistry() 92 placementManager := placement.NewManager( 93 logger, 94 registry, 95 placement.DefaultConfig(), 96 validation.MockDefaultOverrides(), 97 placement.NewStore(bucket), 98 ) 99 m, err := metastore.New(configs[i], validation.MockDefaultOverrides(), logger, registry, health.NoOpService, client, bucket, placementManager) 100 require.NoError(t, err) 101 m.Register(server) 102 103 lis := listeners[grpcAddresses[i]] 104 go func() { 105 err := server.Serve(lis) 106 assert.NoError(t, err) 107 }() 108 res.Instances = append(res.Instances, MetastoreInstance{ 109 Metastore: m, 110 Connection: cc, 111 Server: server, 112 113 IndexServiceClient: metastorev1.NewIndexServiceClient(cc), 114 CompactionServiceClient: metastorev1.NewCompactionServiceClient(cc), 115 MetadataQueryServiceClient: metastorev1.NewMetadataQueryServiceClient(cc), 116 TenantServiceClient: metastorev1.NewTenantServiceClient(cc), 117 RaftNodeServiceClient: raftnodepb.NewRaftNodeServiceClient(cc), 118 }) 119 service := m.Service() 120 ctx := context.Background() 121 require.NoError(t, service.StartAsync(ctx)) 122 require.NoError(t, service.AwaitRunning(ctx)) 123 logger.Log("msg", "service started") 124 } 125 126 require.Eventually(t, func() bool { 127 for i := 0; i < n; i++ { 128 if res.Instances[i].Metastore.Service().State() != services.Running { 129 return false 130 } 131 if res.Instances[i].Metastore.CheckReady(context.Background()) != nil { 132 return false 133 } 134 } 135 return true 136 }, 10*time.Second, 100*time.Millisecond) 137 138 res.Client = client 139 140 return res 141 } 142 143 func MockStaticDiscovery(t *testing.T, servers []discovery.Server) *mockdiscovery.MockDiscovery { 144 d := mockdiscovery.NewMockDiscovery(t) 145 d.On("Subscribe", mock.Anything).Run(func(args mock.Arguments) { 146 upd := args.Get(0).(discovery.Updates) 147 upd.Servers(servers) 148 }) 149 d.On("Rediscover", mock.Anything).Return() 150 d.On("Close").Return(nil) 151 return d 152 } 153 154 type MetastoreInstance struct { 155 Metastore *metastore.Metastore 156 Server *grpc.Server 157 Connection *grpc.ClientConn 158 159 metastorev1.IndexServiceClient 160 metastorev1.CompactionServiceClient 161 metastorev1.MetadataQueryServiceClient 162 metastorev1.TenantServiceClient 163 raftnodepb.RaftNodeServiceClient 164 } 165 166 type MetastoreSet struct { 167 t *testing.T 168 Instances []MetastoreInstance 169 Client *metastoreclient.Client 170 } 171 172 func (m *MetastoreSet) Close() { 173 for _, i := range m.Instances { 174 i.Metastore.Service().StopAsync() 175 err := i.Metastore.Service().AwaitTerminated(context.Background()) 176 require.NoError(m.t, err) 177 i.Connection.Close() 178 i.Server.Stop() 179 } 180 m.Client.Service().StopAsync() 181 err := m.Client.Service().AwaitTerminated(context.Background()) 182 require.NoError(m.t, err) 183 }