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 }