package praefect import ( "fmt" "net" "path/filepath" "testing" "github.com/stretchr/testify/require" "gitlab.com/gitlab-org/gitaly/v16/internal/praefect/config" "gitlab.com/gitlab-org/gitaly/v16/internal/praefect/nodes" "gitlab.com/gitlab-org/gitaly/v16/internal/testhelper" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/health" "google.golang.org/grpc/health/grpc_health_v1" "google.golang.org/grpc/status" ) func TestDialNodes(t *testing.T) { ctx := testhelper.Context(t) tmp := testhelper.TempDir(t) type nodeAssertion struct { storage string token string status grpc_health_v1.HealthCheckResponse_ServingStatus error string } expectedNodes := []nodeAssertion{ { storage: "healthy", token: "healthy-token", status: grpc_health_v1.HealthCheckResponse_SERVING, }, { storage: "unhealthy", token: "unhealthy-token", status: grpc_health_v1.HealthCheckResponse_NOT_SERVING, }, } var cfgNodes []*config.Node for _, n := range expectedNodes { socket := filepath.Join(tmp, n.storage) ln, err := net.Listen("unix", socket) require.NoError(t, err) healthSrv := health.NewServer() healthSrv.SetServingStatus("", n.status) srv := grpc.NewServer() grpc_health_v1.RegisterHealthServer(srv, healthSrv) defer srv.Stop() go testhelper.MustServe(t, srv, ln) cfgNodes = append(cfgNodes, &config.Node{ Storage: n.storage, Token: n.token, Address: fmt.Sprintf("%s://%s", ln.Addr().Network(), ln.Addr().String()), }) } expectedNodes = append(expectedNodes, nodeAssertion{ storage: "invalid", error: status.Error(codes.Unavailable, `last connection error: connection error: desc = "transport: Error while dialing: dial unix non-existent-socket: connect: no such file or directory"`).Error(), }) nodeSet, err := DialNodes(ctx, []*config.VirtualStorage{{ Name: "virtual-storage", Nodes: append(cfgNodes, &config.Node{ Storage: "invalid", Address: "unix:non-existent-socket", }), }}, nil, nil, nil, nil, testhelper.SharedLogger(t), ) require.NoError(t, err) defer nodeSet.Close() conns := nodeSet.Connections() healthClients := nodeSet.HealthClients() var actualNodes []nodeAssertion for virtualStorage, nodes := range nodeSet { for _, node := range nodes { require.NotNil(t, conns[virtualStorage][node.Storage], "connection not found for storage %q", node.Storage) resp, err := healthClients[virtualStorage][node.Storage].Check(ctx, &grpc_health_v1.HealthCheckRequest{}) var errStr string if err != nil { errStr = err.Error() } assertion := nodeAssertion{ storage: node.Storage, token: node.Token, error: errStr, } if resp != nil { assertion.status = resp.Status } actualNodes = append(actualNodes, assertion) delete(conns[virtualStorage], node.Storage) delete(healthClients[virtualStorage], node.Storage) } } require.ElementsMatch(t, expectedNodes, actualNodes) require.Equal(t, Connections{"virtual-storage": {}}, conns, "unexpected connections") require.Equal(t, nodes.HealthClients{"virtual-storage": {}}, healthClients, "unexpected health clients") }