google.golang.org/grpc@v1.72.2/channelz/service/service_test.go (about)

     1  /*
     2   *
     3   * Copyright 2018 gRPC authors.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   */
    18  
    19  package service
    20  
    21  import (
    22  	"context"
    23  	"fmt"
    24  	"net"
    25  	"net/netip"
    26  	"strconv"
    27  	"strings"
    28  	"testing"
    29  	"time"
    30  
    31  	"github.com/google/go-cmp/cmp"
    32  	"google.golang.org/grpc/connectivity"
    33  	"google.golang.org/grpc/credentials"
    34  	"google.golang.org/grpc/grpclog"
    35  	"google.golang.org/grpc/internal/channelz"
    36  	"google.golang.org/grpc/internal/grpctest"
    37  	"google.golang.org/protobuf/encoding/prototext"
    38  	"google.golang.org/protobuf/reflect/protodesc"
    39  	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
    40  	"google.golang.org/protobuf/testing/protocmp"
    41  	"google.golang.org/protobuf/types/descriptorpb"
    42  	"google.golang.org/protobuf/types/dynamicpb"
    43  	"google.golang.org/protobuf/types/known/anypb"
    44  	"google.golang.org/protobuf/types/known/timestamppb"
    45  
    46  	channelzpb "google.golang.org/grpc/channelz/grpc_channelz_v1"
    47  )
    48  
    49  func init() {
    50  	channelz.TurnOn()
    51  }
    52  
    53  type s struct {
    54  	grpctest.Tester
    55  }
    56  
    57  func Test(t *testing.T) {
    58  	grpctest.RunSubTests(t, s{})
    59  }
    60  
    61  const defaultTestTimeout = 10 * time.Second
    62  
    63  func channelProtoToStruct(c *channelzpb.Channel) (*channelz.ChannelMetrics, error) {
    64  	cm := &channelz.ChannelMetrics{}
    65  	pdata := c.GetData()
    66  	var s connectivity.State
    67  	switch pdata.GetState().GetState() {
    68  	case channelzpb.ChannelConnectivityState_UNKNOWN:
    69  		// TODO: what should we set here?
    70  	case channelzpb.ChannelConnectivityState_IDLE:
    71  		s = connectivity.Idle
    72  	case channelzpb.ChannelConnectivityState_CONNECTING:
    73  		s = connectivity.Connecting
    74  	case channelzpb.ChannelConnectivityState_READY:
    75  		s = connectivity.Ready
    76  	case channelzpb.ChannelConnectivityState_TRANSIENT_FAILURE:
    77  		s = connectivity.TransientFailure
    78  	case channelzpb.ChannelConnectivityState_SHUTDOWN:
    79  		s = connectivity.Shutdown
    80  	}
    81  	cm.State.Store(&s)
    82  	tgt := pdata.GetTarget()
    83  	cm.Target.Store(&tgt)
    84  	cm.CallsStarted.Store(pdata.CallsStarted)
    85  	cm.CallsSucceeded.Store(pdata.CallsSucceeded)
    86  	cm.CallsFailed.Store(pdata.CallsFailed)
    87  	if err := pdata.GetLastCallStartedTimestamp().CheckValid(); err != nil {
    88  		return nil, err
    89  	}
    90  	cm.LastCallStartedTimestamp.Store(int64(pdata.GetLastCallStartedTimestamp().AsTime().UnixNano()))
    91  	return cm, nil
    92  }
    93  
    94  func convertSocketRefSliceToMap(sktRefs []*channelzpb.SocketRef) map[int64]string {
    95  	m := make(map[int64]string)
    96  	for _, sr := range sktRefs {
    97  		m[sr.SocketId] = sr.Name
    98  	}
    99  	return m
   100  }
   101  
   102  func (s) TestGetTopChannels(t *testing.T) {
   103  	tcs := []*channelz.ChannelMetrics{
   104  		channelz.NewChannelMetricForTesting(
   105  			connectivity.Connecting,
   106  			"test.channelz:1234",
   107  			6,
   108  			2,
   109  			3,
   110  			time.Now().UTC().UnixNano(),
   111  		),
   112  		channelz.NewChannelMetricForTesting(
   113  			connectivity.Connecting,
   114  			"test.channelz:1234",
   115  			1,
   116  			2,
   117  			3,
   118  			time.Now().UTC().UnixNano(),
   119  		),
   120  		channelz.NewChannelMetricForTesting(
   121  			connectivity.Shutdown,
   122  			"test.channelz:8888",
   123  			0,
   124  			0,
   125  			0,
   126  			0,
   127  		),
   128  	}
   129  
   130  	for _, c := range tcs {
   131  		cz := channelz.RegisterChannel(nil, "test channel")
   132  		cz.ChannelMetrics.CopyFrom(c)
   133  		defer channelz.RemoveEntry(cz.ID)
   134  	}
   135  	s := newCZServer()
   136  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   137  	defer cancel()
   138  	resp, _ := s.GetTopChannels(ctx, &channelzpb.GetTopChannelsRequest{StartChannelId: 0})
   139  	if !resp.GetEnd() {
   140  		t.Fatalf("resp.GetEnd() want true, got %v", resp.GetEnd())
   141  	}
   142  	for i, c := range resp.GetChannel() {
   143  		channel, err := channelProtoToStruct(c)
   144  		if err != nil {
   145  			t.Fatal(err)
   146  		}
   147  		if diff := cmp.Diff(tcs[i], channel, protocmp.Transform()); diff != "" {
   148  			t.Fatalf("unexpected channel, diff (-want +got):\n%s", diff)
   149  		}
   150  	}
   151  	for i := 0; i < 50; i++ {
   152  		cz := channelz.RegisterChannel(nil, "")
   153  		defer channelz.RemoveEntry(cz.ID)
   154  	}
   155  	resp, _ = s.GetTopChannels(ctx, &channelzpb.GetTopChannelsRequest{StartChannelId: 0})
   156  	if resp.GetEnd() {
   157  		t.Fatalf("resp.GetEnd() want false, got %v", resp.GetEnd())
   158  	}
   159  }
   160  
   161  func (s) TestGetServers(t *testing.T) {
   162  	ss := []*channelz.ServerMetrics{
   163  		channelz.NewServerMetricsForTesting(
   164  			6,
   165  			2,
   166  			3,
   167  			time.Now().UnixNano(),
   168  		),
   169  		channelz.NewServerMetricsForTesting(
   170  			1,
   171  			2,
   172  			3,
   173  			time.Now().UnixNano(),
   174  		),
   175  		channelz.NewServerMetricsForTesting(
   176  			1,
   177  			0,
   178  			0,
   179  			time.Now().UnixNano(),
   180  		),
   181  	}
   182  
   183  	firstID := int64(0)
   184  	for i, s := range ss {
   185  		svr := channelz.RegisterServer("")
   186  		if i == 0 {
   187  			firstID = svr.ID
   188  		}
   189  		svr.ServerMetrics.CopyFrom(s)
   190  		defer channelz.RemoveEntry(svr.ID)
   191  	}
   192  	svr := newCZServer()
   193  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   194  	defer cancel()
   195  	resp, _ := svr.GetServers(ctx, &channelzpb.GetServersRequest{StartServerId: 0})
   196  	if !resp.GetEnd() {
   197  		t.Fatalf("resp.GetEnd() want true, got %v", resp.GetEnd())
   198  	}
   199  	serversWant := []*channelzpb.Server{
   200  		{
   201  			Ref: &channelzpb.ServerRef{ServerId: firstID, Name: ""},
   202  			Data: &channelzpb.ServerData{
   203  				CallsStarted:             6,
   204  				CallsSucceeded:           2,
   205  				CallsFailed:              3,
   206  				LastCallStartedTimestamp: timestamppb.New(time.Unix(0, ss[0].LastCallStartedTimestamp.Load())),
   207  			},
   208  		},
   209  		{
   210  			Ref: &channelzpb.ServerRef{ServerId: firstID + 1, Name: ""},
   211  			Data: &channelzpb.ServerData{
   212  				CallsStarted:             1,
   213  				CallsSucceeded:           2,
   214  				CallsFailed:              3,
   215  				LastCallStartedTimestamp: timestamppb.New(time.Unix(0, ss[1].LastCallStartedTimestamp.Load())),
   216  			},
   217  		},
   218  		{
   219  			Ref: &channelzpb.ServerRef{ServerId: firstID + 2, Name: ""},
   220  			Data: &channelzpb.ServerData{
   221  				CallsStarted:             1,
   222  				CallsSucceeded:           0,
   223  				CallsFailed:              0,
   224  				LastCallStartedTimestamp: timestamppb.New(time.Unix(0, ss[2].LastCallStartedTimestamp.Load())),
   225  			},
   226  		},
   227  	}
   228  	if diff := cmp.Diff(serversWant, resp.GetServer(), protocmp.Transform()); diff != "" {
   229  		t.Fatalf("unexpected server, diff (-want +got):\n%s", diff)
   230  	}
   231  	for i := 0; i < 50; i++ {
   232  		id := channelz.RegisterServer("").ID
   233  		defer channelz.RemoveEntry(id)
   234  	}
   235  	resp, _ = svr.GetServers(ctx, &channelzpb.GetServersRequest{StartServerId: 0})
   236  	if resp.GetEnd() {
   237  		t.Fatalf("resp.GetEnd() want false, got %v", resp.GetEnd())
   238  	}
   239  }
   240  
   241  func (s) TestGetServerSockets(t *testing.T) {
   242  	svrID := channelz.RegisterServer("")
   243  	defer channelz.RemoveEntry(svrID.ID)
   244  	refNames := []string{"listen socket 1", "normal socket 1", "normal socket 2"}
   245  	ids := make([]int64, 3)
   246  	ids[0] = channelz.RegisterSocket(&channelz.Socket{SocketType: channelz.SocketTypeListen, Parent: svrID, RefName: refNames[0]}).ID
   247  	ids[1] = channelz.RegisterSocket(&channelz.Socket{SocketType: channelz.SocketTypeNormal, Parent: svrID, RefName: refNames[1]}).ID
   248  	ids[2] = channelz.RegisterSocket(&channelz.Socket{SocketType: channelz.SocketTypeNormal, Parent: svrID, RefName: refNames[2]}).ID
   249  	for _, id := range ids {
   250  		defer channelz.RemoveEntry(id)
   251  	}
   252  	svr := newCZServer()
   253  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   254  	defer cancel()
   255  	resp, _ := svr.GetServerSockets(ctx, &channelzpb.GetServerSocketsRequest{ServerId: svrID.ID, StartSocketId: 0})
   256  	if !resp.GetEnd() {
   257  		t.Fatalf("resp.GetEnd() want: true, got: %v", resp.GetEnd())
   258  	}
   259  	// GetServerSockets only return normal sockets.
   260  	want := map[int64]string{
   261  		ids[1]: refNames[1],
   262  		ids[2]: refNames[2],
   263  	}
   264  	if got := convertSocketRefSliceToMap(resp.GetSocketRef()); !cmp.Equal(got, want) {
   265  		t.Fatalf("GetServerSockets want: %#v, got: %#v (resp=%v)", want, got, prototext.Format(resp))
   266  	}
   267  
   268  	for i := 0; i < 50; i++ {
   269  		id := channelz.RegisterSocket(&channelz.Socket{SocketType: channelz.SocketTypeNormal, Parent: svrID})
   270  		defer channelz.RemoveEntry(id.ID)
   271  	}
   272  	resp, _ = svr.GetServerSockets(ctx, &channelzpb.GetServerSocketsRequest{ServerId: svrID.ID, StartSocketId: 0})
   273  	if resp.GetEnd() {
   274  		t.Fatalf("resp.GetEnd() want false, got %v", resp.GetEnd())
   275  	}
   276  }
   277  
   278  // This test makes a GetServerSockets with a non-zero start ID, and expect only
   279  // sockets with ID >= the given start ID.
   280  func (s) TestGetServerSocketsNonZeroStartID(t *testing.T) {
   281  	svrID := channelz.RegisterServer("test server")
   282  	defer channelz.RemoveEntry(svrID.ID)
   283  	refNames := []string{"listen socket 1", "normal socket 1", "normal socket 2"}
   284  	ids := make([]int64, 3)
   285  	ids[0] = channelz.RegisterSocket(&channelz.Socket{SocketType: channelz.SocketTypeListen, Parent: svrID, RefName: refNames[0]}).ID
   286  	ids[1] = channelz.RegisterSocket(&channelz.Socket{SocketType: channelz.SocketTypeNormal, Parent: svrID, RefName: refNames[1]}).ID
   287  	ids[2] = channelz.RegisterSocket(&channelz.Socket{SocketType: channelz.SocketTypeNormal, Parent: svrID, RefName: refNames[2]}).ID
   288  	for _, id := range ids {
   289  		defer channelz.RemoveEntry(id)
   290  	}
   291  	svr := newCZServer()
   292  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   293  	defer cancel()
   294  	// Make GetServerSockets with startID = ids[1]+1, so socket-1 won't be
   295  	// included in the response.
   296  	resp, _ := svr.GetServerSockets(ctx, &channelzpb.GetServerSocketsRequest{ServerId: svrID.ID, StartSocketId: ids[1] + 1})
   297  	if !resp.GetEnd() {
   298  		t.Fatalf("resp.GetEnd() want: true, got: %v", resp.GetEnd())
   299  	}
   300  	// GetServerSockets only return normal socket-2, socket-1 should be
   301  	// filtered by start ID.
   302  	want := map[int64]string{
   303  		ids[2]: refNames[2],
   304  	}
   305  	if !cmp.Equal(convertSocketRefSliceToMap(resp.GetSocketRef()), want) {
   306  		t.Fatalf("GetServerSockets want: %#v, got: %#v", want, resp.GetSocketRef())
   307  	}
   308  }
   309  
   310  var logger = grpclog.Component("channelz")
   311  
   312  func (s) TestGetChannel(t *testing.T) {
   313  	refNames := []string{"top channel 1", "nested channel 1", "sub channel 2", "nested channel 3"}
   314  	cids := make([]*channelz.Channel, 3)
   315  	cids[0] = channelz.RegisterChannel(nil, refNames[0])
   316  	channelz.AddTraceEvent(logger, cids[0], 0, &channelz.TraceEvent{
   317  		Desc:     "Channel Created",
   318  		Severity: channelz.CtInfo,
   319  	})
   320  
   321  	cids[1] = channelz.RegisterChannel(cids[0], refNames[1])
   322  	channelz.AddTraceEvent(logger, cids[1], 0, &channelz.TraceEvent{
   323  		Desc:     "Channel Created",
   324  		Severity: channelz.CtInfo,
   325  		Parent: &channelz.TraceEvent{
   326  			Desc:     fmt.Sprintf("Nested Channel(id:%d) created", cids[1].ID),
   327  			Severity: channelz.CtInfo,
   328  		},
   329  	})
   330  
   331  	subChan := channelz.RegisterSubChannel(cids[0], refNames[2])
   332  	channelz.AddTraceEvent(logger, subChan, 0, &channelz.TraceEvent{
   333  		Desc:     "SubChannel Created",
   334  		Severity: channelz.CtInfo,
   335  		Parent: &channelz.TraceEvent{
   336  			Desc:     fmt.Sprintf("SubChannel(id:%d) created", subChan.ID),
   337  			Severity: channelz.CtInfo,
   338  		},
   339  	})
   340  	defer channelz.RemoveEntry(subChan.ID)
   341  
   342  	cids[2] = channelz.RegisterChannel(cids[1], refNames[3])
   343  	channelz.AddTraceEvent(logger, cids[2], 0, &channelz.TraceEvent{
   344  		Desc:     "Channel Created",
   345  		Severity: channelz.CtInfo,
   346  		Parent: &channelz.TraceEvent{
   347  			Desc:     fmt.Sprintf("Nested Channel(id:%d) created", cids[2].ID),
   348  			Severity: channelz.CtInfo,
   349  		},
   350  	})
   351  	channelz.AddTraceEvent(logger, cids[0], 0, &channelz.TraceEvent{
   352  		Desc:     fmt.Sprintf("Channel Connectivity change to %v", connectivity.Ready),
   353  		Severity: channelz.CtInfo,
   354  	})
   355  	channelz.AddTraceEvent(logger, cids[0], 0, &channelz.TraceEvent{
   356  		Desc:     "Resolver returns an empty address list",
   357  		Severity: channelz.CtWarning,
   358  	})
   359  
   360  	for _, id := range cids {
   361  		defer channelz.RemoveEntry(id.ID)
   362  	}
   363  
   364  	svr := newCZServer()
   365  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   366  	defer cancel()
   367  	resp, _ := svr.GetChannel(ctx, &channelzpb.GetChannelRequest{ChannelId: cids[0].ID})
   368  	metrics := resp.GetChannel()
   369  	subChans := metrics.GetSubchannelRef()
   370  	if len(subChans) != 1 || subChans[0].GetName() != refNames[2] || subChans[0].GetSubchannelId() != subChan.ID {
   371  		t.Fatalf("metrics.GetSubChannelRef() want %#v, got %#v", []*channelzpb.SubchannelRef{{SubchannelId: subChan.ID, Name: refNames[2]}}, subChans)
   372  	}
   373  	nestedChans := metrics.GetChannelRef()
   374  	if len(nestedChans) != 1 || nestedChans[0].GetName() != refNames[1] || nestedChans[0].GetChannelId() != cids[1].ID {
   375  		t.Fatalf("metrics.GetChannelRef() want %#v, got %#v", []*channelzpb.ChannelRef{{ChannelId: cids[1].ID, Name: refNames[1]}}, nestedChans)
   376  	}
   377  	trace := metrics.GetData().GetTrace()
   378  	want := []struct {
   379  		desc     string
   380  		severity channelzpb.ChannelTraceEvent_Severity
   381  		childID  int64
   382  		childRef string
   383  	}{
   384  		{desc: "Channel Created", severity: channelzpb.ChannelTraceEvent_CT_INFO},
   385  		{desc: fmt.Sprintf("Nested Channel(id:%d) created", cids[1].ID), severity: channelzpb.ChannelTraceEvent_CT_INFO, childID: cids[1].ID, childRef: refNames[1]},
   386  		{desc: fmt.Sprintf("SubChannel(id:%d) created", subChan.ID), severity: channelzpb.ChannelTraceEvent_CT_INFO, childID: subChan.ID, childRef: refNames[2]},
   387  		{desc: fmt.Sprintf("Channel Connectivity change to %v", connectivity.Ready), severity: channelzpb.ChannelTraceEvent_CT_INFO},
   388  		{desc: "Resolver returns an empty address list", severity: channelzpb.ChannelTraceEvent_CT_WARNING},
   389  	}
   390  
   391  	for i, e := range trace.Events {
   392  		if !strings.Contains(e.GetDescription(), want[i].desc) {
   393  			t.Fatalf("trace: GetDescription want %#v, got %#v", want[i].desc, e.GetDescription())
   394  		}
   395  		if e.GetSeverity() != want[i].severity {
   396  			t.Fatalf("trace: GetSeverity want %#v, got %#v", want[i].severity, e.GetSeverity())
   397  		}
   398  		if want[i].childID == 0 && (e.GetChannelRef() != nil || e.GetSubchannelRef() != nil) {
   399  			t.Fatalf("trace: GetChannelRef() should return nil, as there is no reference")
   400  		}
   401  		if e.GetChannelRef().GetChannelId() != want[i].childID || e.GetChannelRef().GetName() != want[i].childRef {
   402  			if e.GetSubchannelRef().GetSubchannelId() != want[i].childID || e.GetSubchannelRef().GetName() != want[i].childRef {
   403  				t.Fatalf("trace: GetChannelRef/GetSubchannelRef want (child ID: %d, child name: %q), got %#v and %#v", want[i].childID, want[i].childRef, e.GetChannelRef(), e.GetSubchannelRef())
   404  			}
   405  		}
   406  	}
   407  	resp, _ = svr.GetChannel(ctx, &channelzpb.GetChannelRequest{ChannelId: cids[1].ID})
   408  	metrics = resp.GetChannel()
   409  	nestedChans = metrics.GetChannelRef()
   410  	if len(nestedChans) != 1 || nestedChans[0].GetName() != refNames[3] || nestedChans[0].GetChannelId() != cids[2].ID {
   411  		t.Fatalf("metrics.GetChannelRef() want %#v, got %#v", []*channelzpb.ChannelRef{{ChannelId: cids[2].ID, Name: refNames[3]}}, nestedChans)
   412  	}
   413  }
   414  
   415  func (s) TestGetSubChannel(t *testing.T) {
   416  	var (
   417  		subchanCreated            = "SubChannel Created"
   418  		subchanConnectivityChange = fmt.Sprintf("Subchannel Connectivity change to %v", connectivity.Ready)
   419  		subChanPickNewAddress     = fmt.Sprintf("Subchannel picks a new address %q to connect", "0.0.0.0")
   420  	)
   421  
   422  	refNames := []string{"top channel 1", "sub channel 1", "socket 1", "socket 2"}
   423  	chann := channelz.RegisterChannel(nil, refNames[0])
   424  	defer channelz.RemoveEntry(chann.ID)
   425  	channelz.AddTraceEvent(logger, chann, 0, &channelz.TraceEvent{
   426  		Desc:     "Channel Created",
   427  		Severity: channelz.CtInfo,
   428  	})
   429  	subChan := channelz.RegisterSubChannel(chann, refNames[1])
   430  	defer channelz.RemoveEntry(subChan.ID)
   431  	channelz.AddTraceEvent(logger, subChan, 0, &channelz.TraceEvent{
   432  		Desc:     subchanCreated,
   433  		Severity: channelz.CtInfo,
   434  		Parent: &channelz.TraceEvent{
   435  			Desc:     fmt.Sprintf("Nested Channel(id:%d) created", chann.ID),
   436  			Severity: channelz.CtInfo,
   437  		},
   438  	})
   439  	skt1 := channelz.RegisterSocket(&channelz.Socket{SocketType: channelz.SocketTypeNormal, Parent: subChan, RefName: refNames[2]})
   440  	defer channelz.RemoveEntry(skt1.ID)
   441  	skt2 := channelz.RegisterSocket(&channelz.Socket{SocketType: channelz.SocketTypeNormal, Parent: subChan, RefName: refNames[3]})
   442  	defer channelz.RemoveEntry(skt2.ID)
   443  	channelz.AddTraceEvent(logger, subChan, 0, &channelz.TraceEvent{
   444  		Desc:     subchanConnectivityChange,
   445  		Severity: channelz.CtInfo,
   446  	})
   447  	channelz.AddTraceEvent(logger, subChan, 0, &channelz.TraceEvent{
   448  		Desc:     subChanPickNewAddress,
   449  		Severity: channelz.CtInfo,
   450  	})
   451  	svr := newCZServer()
   452  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   453  	defer cancel()
   454  	resp, _ := svr.GetSubchannel(ctx, &channelzpb.GetSubchannelRequest{SubchannelId: subChan.ID})
   455  	metrics := resp.GetSubchannel()
   456  	want := map[int64]string{
   457  		skt1.ID: refNames[2],
   458  		skt2.ID: refNames[3],
   459  	}
   460  	if !cmp.Equal(convertSocketRefSliceToMap(metrics.GetSocketRef()), want) {
   461  		t.Fatalf("metrics.GetSocketRef() want %#v: got: %#v", want, metrics.GetSocketRef())
   462  	}
   463  
   464  	trace := metrics.GetData().GetTrace()
   465  	wantTrace := []struct {
   466  		desc     string
   467  		severity channelzpb.ChannelTraceEvent_Severity
   468  		childID  int64
   469  		childRef string
   470  	}{
   471  		{desc: subchanCreated, severity: channelzpb.ChannelTraceEvent_CT_INFO},
   472  		{desc: subchanConnectivityChange, severity: channelzpb.ChannelTraceEvent_CT_INFO},
   473  		{desc: subChanPickNewAddress, severity: channelzpb.ChannelTraceEvent_CT_INFO},
   474  	}
   475  	for i, e := range trace.Events {
   476  		if e.GetDescription() != wantTrace[i].desc {
   477  			t.Fatalf("trace: GetDescription want %#v, got %#v", wantTrace[i].desc, e.GetDescription())
   478  		}
   479  		if e.GetSeverity() != wantTrace[i].severity {
   480  			t.Fatalf("trace: GetSeverity want %#v, got %#v", wantTrace[i].severity, e.GetSeverity())
   481  		}
   482  		if wantTrace[i].childID == 0 && (e.GetChannelRef() != nil || e.GetSubchannelRef() != nil) {
   483  			t.Fatalf("trace: GetChannelRef() should return nil, as there is no reference")
   484  		}
   485  		if e.GetChannelRef().GetChannelId() != wantTrace[i].childID || e.GetChannelRef().GetName() != wantTrace[i].childRef {
   486  			if e.GetSubchannelRef().GetSubchannelId() != wantTrace[i].childID || e.GetSubchannelRef().GetName() != wantTrace[i].childRef {
   487  				t.Fatalf("trace: GetChannelRef/GetSubchannelRef want (child ID: %d, child name: %q), got %#v and %#v", wantTrace[i].childID, wantTrace[i].childRef, e.GetChannelRef(), e.GetSubchannelRef())
   488  			}
   489  		}
   490  	}
   491  }
   492  
   493  type czSocket struct {
   494  	streamsStarted                   int64
   495  	streamsSucceeded                 int64
   496  	streamsFailed                    int64
   497  	messagesSent                     int64
   498  	messagesReceived                 int64
   499  	keepAlivesSent                   int64
   500  	lastLocalStreamCreatedTimestamp  time.Time
   501  	lastRemoteStreamCreatedTimestamp time.Time
   502  	lastMessageSentTimestamp         time.Time
   503  	lastMessageReceivedTimestamp     time.Time
   504  	localFlowControlWindow           int64
   505  	remoteFlowControlWindow          int64
   506  
   507  	localAddr     net.Addr
   508  	remoteAddr    net.Addr
   509  	remoteName    string
   510  	socketOptions *channelz.SocketOptionData
   511  	security      credentials.ChannelzSecurityValue
   512  }
   513  
   514  func newSocket(cs czSocket) *channelz.Socket {
   515  	if cs.lastLocalStreamCreatedTimestamp.IsZero() {
   516  		cs.lastLocalStreamCreatedTimestamp = time.Unix(0, 0)
   517  	}
   518  	if cs.lastRemoteStreamCreatedTimestamp.IsZero() {
   519  		cs.lastRemoteStreamCreatedTimestamp = time.Unix(0, 0)
   520  	}
   521  	if cs.lastMessageSentTimestamp.IsZero() {
   522  		cs.lastMessageSentTimestamp = time.Unix(0, 0)
   523  	}
   524  	if cs.lastMessageReceivedTimestamp.IsZero() {
   525  		cs.lastMessageReceivedTimestamp = time.Unix(0, 0)
   526  	}
   527  
   528  	s := &channelz.Socket{
   529  		LocalAddr:     cs.localAddr,
   530  		RemoteAddr:    cs.remoteAddr,
   531  		RemoteName:    cs.remoteName,
   532  		SocketOptions: cs.socketOptions,
   533  		Security:      cs.security,
   534  	}
   535  	s.SocketMetrics.StreamsStarted.Store(cs.streamsStarted)
   536  	s.SocketMetrics.StreamsSucceeded.Store(cs.streamsSucceeded)
   537  	s.SocketMetrics.StreamsFailed.Store(cs.streamsFailed)
   538  	s.SocketMetrics.MessagesSent.Store(cs.messagesSent)
   539  	s.SocketMetrics.MessagesReceived.Store(cs.messagesReceived)
   540  	s.SocketMetrics.KeepAlivesSent.Store(cs.keepAlivesSent)
   541  	s.SocketMetrics.LastLocalStreamCreatedTimestamp.Store(cs.lastLocalStreamCreatedTimestamp.UnixNano())
   542  	s.SocketMetrics.LastRemoteStreamCreatedTimestamp.Store(cs.lastRemoteStreamCreatedTimestamp.UnixNano())
   543  	s.SocketMetrics.LastMessageSentTimestamp.Store(cs.lastMessageSentTimestamp.UnixNano())
   544  	s.SocketMetrics.LastMessageReceivedTimestamp.Store(cs.lastMessageReceivedTimestamp.UnixNano())
   545  	s.EphemeralMetrics = func() *channelz.EphemeralSocketMetrics {
   546  		return &channelz.EphemeralSocketMetrics{
   547  			LocalFlowControlWindow:  cs.localFlowControlWindow,
   548  			RemoteFlowControlWindow: cs.remoteFlowControlWindow,
   549  		}
   550  	}
   551  	return s
   552  }
   553  
   554  type OtherChannelzSecurityValue struct {
   555  	LocalCertificate  []byte `protobuf:"bytes,1,opt,name=local_certificate,json=localCertificate,proto3" json:"local_certificate,omitempty"`
   556  	RemoteCertificate []byte `protobuf:"bytes,2,opt,name=remote_certificate,json=remoteCertificate,proto3" json:"remote_certificate,omitempty"`
   557  }
   558  
   559  func (x *OtherChannelzSecurityValue) Reset() {
   560  	*x = OtherChannelzSecurityValue{}
   561  }
   562  
   563  func (x *OtherChannelzSecurityValue) String() string {
   564  	return prototext.Format(x)
   565  }
   566  
   567  func (*OtherChannelzSecurityValue) ProtoMessage() {}
   568  
   569  func (x OtherChannelzSecurityValue) ProtoReflect() protoreflect.Message {
   570  	const s = `
   571  		name:   "service_test.proto"
   572  		syntax: "proto3"
   573  		package: "grpc.credentials",
   574  		message_type: [{
   575  			name: "OtherChannelzSecurityValue"
   576  			field: [
   577  				{name:"local_certificate"  number:1 type:TYPE_BYTES},
   578  				{name:"remote_certificate"  number:2 type:TYPE_BYTES}
   579  			]
   580  		}]
   581  	`
   582  	pb := new(descriptorpb.FileDescriptorProto)
   583  	if err := prototext.Unmarshal([]byte(s), pb); err != nil {
   584  		panic(err)
   585  	}
   586  	fd, err := protodesc.NewFile(pb, nil)
   587  	if err != nil {
   588  		panic(err)
   589  	}
   590  	md := fd.Messages().Get(0)
   591  	mt := dynamicpb.NewMessageType(md)
   592  	return mt.New()
   593  }
   594  
   595  func (s) TestGetSocket(t *testing.T) {
   596  	ss := []*channelz.Socket{newSocket(czSocket{
   597  		streamsStarted:                   10,
   598  		streamsSucceeded:                 2,
   599  		streamsFailed:                    3,
   600  		messagesSent:                     20,
   601  		messagesReceived:                 10,
   602  		keepAlivesSent:                   2,
   603  		lastLocalStreamCreatedTimestamp:  time.Unix(0, 0),
   604  		lastRemoteStreamCreatedTimestamp: time.Unix(1, 0),
   605  		lastMessageSentTimestamp:         time.Unix(2, 0),
   606  		lastMessageReceivedTimestamp:     time.Unix(3, 0),
   607  		localFlowControlWindow:           65536,
   608  		remoteFlowControlWindow:          1024,
   609  		localAddr:                        &net.TCPAddr{IP: netip.MustParseAddr("1.0.0.1").AsSlice(), Port: 10001},
   610  		remoteAddr:                       &net.TCPAddr{IP: netip.MustParseAddr("12.0.0.1").AsSlice(), Port: 10002},
   611  		remoteName:                       "remote.remote",
   612  	}), newSocket(czSocket{
   613  		streamsStarted:                   10,
   614  		streamsSucceeded:                 2,
   615  		streamsFailed:                    3,
   616  		messagesSent:                     20,
   617  		messagesReceived:                 10,
   618  		keepAlivesSent:                   2,
   619  		lastLocalStreamCreatedTimestamp:  time.Unix(0, 0),
   620  		lastRemoteStreamCreatedTimestamp: time.Unix(5, 0),
   621  		lastMessageSentTimestamp:         time.Unix(6, 0),
   622  		lastMessageReceivedTimestamp:     time.Unix(7, 0),
   623  		localFlowControlWindow:           65536,
   624  		remoteFlowControlWindow:          1024,
   625  		localAddr:                        &net.UnixAddr{Name: "file.path", Net: "unix"},
   626  		remoteAddr:                       &net.UnixAddr{Name: "another.path", Net: "unix"},
   627  		remoteName:                       "remote.remote",
   628  	}), newSocket(czSocket{
   629  		streamsStarted:                   5,
   630  		streamsSucceeded:                 2,
   631  		streamsFailed:                    3,
   632  		messagesSent:                     20,
   633  		messagesReceived:                 10,
   634  		keepAlivesSent:                   2,
   635  		lastLocalStreamCreatedTimestamp:  time.Unix(10, 10),
   636  		lastRemoteStreamCreatedTimestamp: time.Unix(0, 0),
   637  		lastMessageSentTimestamp:         time.Unix(0, 0),
   638  		lastMessageReceivedTimestamp:     time.Unix(0, 0),
   639  		localFlowControlWindow:           65536,
   640  		remoteFlowControlWindow:          10240,
   641  		localAddr:                        &net.IPAddr{IP: netip.MustParseAddr("1.0.0.1").AsSlice()},
   642  		remoteAddr:                       &net.IPAddr{IP: netip.MustParseAddr("9.0.0.1").AsSlice()},
   643  		remoteName:                       "",
   644  	}), newSocket(czSocket{
   645  		localAddr: &net.TCPAddr{IP: netip.MustParseAddr("127.0.0.1").AsSlice(), Port: 10001},
   646  	}), newSocket(czSocket{
   647  		security: &credentials.TLSChannelzSecurityValue{
   648  			StandardName:      "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
   649  			RemoteCertificate: []byte{48, 130, 2, 156, 48, 130, 2, 5, 160},
   650  		},
   651  	}), newSocket(czSocket{
   652  		security: &credentials.OtherChannelzSecurityValue{
   653  			Name: "XXXX",
   654  		},
   655  	}), newSocket(czSocket{
   656  		security: &credentials.OtherChannelzSecurityValue{
   657  			Name: "YYYY",
   658  			Value: OtherChannelzSecurityValue{
   659  				LocalCertificate:  []byte{1, 2, 3},
   660  				RemoteCertificate: []byte{4, 5, 6},
   661  			},
   662  		},
   663  	}),
   664  	}
   665  	otherSecVal, err := anypb.New(ss[6].Security.(*credentials.OtherChannelzSecurityValue).Value)
   666  	if err != nil {
   667  		t.Fatal("Error marshalling proto:", err)
   668  	}
   669  
   670  	svr := newCZServer()
   671  	skts := make([]*channelz.Socket, len(ss))
   672  	svrID := channelz.RegisterServer("")
   673  	defer channelz.RemoveEntry(svrID.ID)
   674  	for i, s := range ss {
   675  		s.Parent = svrID
   676  		s.RefName = strconv.Itoa(i)
   677  		skts[i] = channelz.RegisterSocket(s)
   678  		defer channelz.RemoveEntry(skts[i].ID)
   679  	}
   680  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   681  	defer cancel()
   682  
   683  	emptyData := `data: {
   684  		last_local_stream_created_timestamp: {seconds: 0 nanos: 0}
   685  		last_remote_stream_created_timestamp: {seconds: 0 nanos: 0}
   686  		last_message_sent_timestamp: {seconds: 0 nanos: 0}
   687  		last_message_received_timestamp: {seconds: 0 nanos: 0}
   688  		local_flow_control_window: { value: 0 }
   689  		remote_flow_control_window: { value: 0 }
   690  	}`
   691  	want := []string{`
   692  		ref: {socket_id: ` + fmt.Sprint(skts[0].ID) + ` name: "0" }
   693  		data: {
   694  			streams_started: 10
   695  			streams_succeeded: 2
   696  			streams_failed: 3
   697  			messages_sent: 20
   698  			messages_received: 10
   699  			keep_alives_sent: 2
   700  			last_local_stream_created_timestamp: {seconds: 0 nanos: 0}
   701  			last_remote_stream_created_timestamp: {seconds: 1 nanos: 0}
   702  			last_message_sent_timestamp: {seconds: 2 nanos: 0}
   703  			last_message_received_timestamp: {seconds: 3 nanos: 0}
   704  			local_flow_control_window: { value: 65536 }
   705  			remote_flow_control_window: { value: 1024 }
   706  		}
   707  		local: { tcpip_address: { ip_address: "` + addr(skts[0].LocalAddr) + `" port: 10001 } }
   708  		remote: { tcpip_address: { ip_address: "` + addr(skts[0].RemoteAddr) + `" port: 10002 } }
   709  		remote_name: "remote.remote"`,
   710  		`
   711  		ref: {socket_id: ` + fmt.Sprint(skts[1].ID) + ` name: "1" }
   712  		data: {
   713  			streams_started: 10
   714  			streams_succeeded: 2
   715  			streams_failed: 3
   716  			messages_sent: 20
   717  			messages_received: 10
   718  			keep_alives_sent: 2
   719  			last_local_stream_created_timestamp: {seconds: 0 nanos: 0}
   720  			last_remote_stream_created_timestamp: {seconds: 5 nanos: 0}
   721  			last_message_sent_timestamp: {seconds: 6 nanos: 0}
   722  			last_message_received_timestamp: {seconds: 7 nanos: 0}
   723  			local_flow_control_window: { value: 65536 }
   724  			remote_flow_control_window: { value: 1024 }
   725  		}
   726  		local: { uds_address { filename: "file.path" } }
   727  		remote: { uds_address { filename: "another.path" } }
   728  		remote_name: "remote.remote"`,
   729  		`
   730  		ref: {socket_id: ` + fmt.Sprint(skts[2].ID) + ` name: "2" }
   731  		data: {
   732  			streams_started: 5
   733  			streams_succeeded: 2
   734  			streams_failed: 3
   735  			messages_sent: 20
   736  			messages_received: 10
   737  			keep_alives_sent: 2
   738  			last_local_stream_created_timestamp: {seconds: 10 nanos: 10}
   739  			last_remote_stream_created_timestamp: {seconds: 0 nanos: 0}
   740  			last_message_sent_timestamp: {seconds: 0 nanos: 0}
   741  			last_message_received_timestamp: {seconds: 0 nanos: 0}
   742  			local_flow_control_window: { value: 65536 }
   743  			remote_flow_control_window: { value: 10240 }
   744  		}
   745  		local: { tcpip_address: { ip_address: "` + addr(skts[2].LocalAddr) + `" } }
   746  		remote: { tcpip_address: { ip_address: "` + addr(skts[2].RemoteAddr) + `" } }
   747  		remote_name: ""`,
   748  		`
   749  		ref: {socket_id: ` + fmt.Sprint(skts[3].ID) + ` name: "3" }
   750  		local: { tcpip_address: { ip_address: "` + addr(skts[3].LocalAddr) + `" port: 10001 } }
   751  		` + emptyData,
   752  		`
   753  		ref: {socket_id: ` + fmt.Sprint(skts[4].ID) + ` name: "4" }
   754  		security: { tls: {
   755  			standard_name: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
   756  			remote_certificate: "\x30\x82\x02\x9c\x30\x82\x02\x05\xa0"
   757  		} }
   758  		` + emptyData,
   759  		`
   760  		ref: {socket_id: ` + fmt.Sprint(skts[5].ID) + ` name: "5" }
   761  		security: { other: { name: "XXXX" } }
   762  		` + emptyData,
   763  		`
   764  		ref: {socket_id: ` + fmt.Sprint(skts[6].ID) + ` name: "6" }
   765  		security: { other: {
   766  			name: "YYYY"
   767  			value: {
   768  				type_url: "type.googleapis.com/grpc.credentials.OtherChannelzSecurityValue"
   769  				value: "` + escape(otherSecVal.Value) + `"
   770  			}
   771  		} }
   772  		` + emptyData,
   773  	}
   774  
   775  	for i := range ss {
   776  		resp, _ := svr.GetSocket(ctx, &channelzpb.GetSocketRequest{SocketId: skts[i].ID})
   777  		w := &channelzpb.Socket{}
   778  		if err := prototext.Unmarshal([]byte(want[i]), w); err != nil {
   779  			t.Fatalf("Error unmarshalling %q: %v", want[i], err)
   780  		}
   781  		if diff := cmp.Diff(resp.GetSocket(), w, protocmp.Transform()); diff != "" {
   782  			t.Fatalf("Socket %v did not match expected.  -got +want: %v", i, diff)
   783  		}
   784  	}
   785  }
   786  
   787  func escape(bs []byte) string {
   788  	ret := ""
   789  	for _, b := range bs {
   790  		ret += fmt.Sprintf("\\x%02x", b)
   791  	}
   792  	return ret
   793  }
   794  
   795  func addr(a net.Addr) string {
   796  	switch a := a.(type) {
   797  	case *net.TCPAddr:
   798  		return escape([]byte(a.IP))
   799  	case *net.IPAddr:
   800  		return escape([]byte(a.IP))
   801  	}
   802  	return ""
   803  }