mirror of
https://github.com/Luzifer/nginx-sso.git
synced 2024-12-30 09:41:19 +00:00
686 lines
26 KiB
Go
686 lines
26 KiB
Go
/*
|
|
*
|
|
* Copyright 2018 gRPC authors.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*/
|
|
|
|
package service
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net"
|
|
"reflect"
|
|
"strconv"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/golang/protobuf/proto"
|
|
"github.com/golang/protobuf/ptypes"
|
|
channelzpb "google.golang.org/grpc/channelz/grpc_channelz_v1"
|
|
"google.golang.org/grpc/connectivity"
|
|
"google.golang.org/grpc/credentials"
|
|
"google.golang.org/grpc/internal/channelz"
|
|
)
|
|
|
|
func init() {
|
|
channelz.TurnOn()
|
|
}
|
|
|
|
type protoToSocketOptFunc func([]*channelzpb.SocketOption) *channelz.SocketOptionData
|
|
|
|
// protoToSocketOpt is used in function socketProtoToStruct to extract socket option
|
|
// data from unmarshaled proto message.
|
|
// It is only defined under linux, non-appengine environment on x86 architecture.
|
|
var protoToSocketOpt protoToSocketOptFunc
|
|
|
|
// emptyTime is used for detecting unset value of time.Time type.
|
|
// For go1.7 and earlier, ptypes.Timestamp will fill in the loc field of time.Time
|
|
// with &utcLoc. However zero value of a time.Time type value loc field is nil.
|
|
// This behavior will make reflect.DeepEqual fail upon unset time.Time field,
|
|
// and cause false positive fatal error.
|
|
// TODO: Go1.7 is no longer supported - does this need a change?
|
|
var emptyTime time.Time
|
|
|
|
type dummyChannel struct {
|
|
state connectivity.State
|
|
target string
|
|
callsStarted int64
|
|
callsSucceeded int64
|
|
callsFailed int64
|
|
lastCallStartedTimestamp time.Time
|
|
}
|
|
|
|
func (d *dummyChannel) ChannelzMetric() *channelz.ChannelInternalMetric {
|
|
return &channelz.ChannelInternalMetric{
|
|
State: d.state,
|
|
Target: d.target,
|
|
CallsStarted: d.callsStarted,
|
|
CallsSucceeded: d.callsSucceeded,
|
|
CallsFailed: d.callsFailed,
|
|
LastCallStartedTimestamp: d.lastCallStartedTimestamp,
|
|
}
|
|
}
|
|
|
|
type dummyServer struct {
|
|
callsStarted int64
|
|
callsSucceeded int64
|
|
callsFailed int64
|
|
lastCallStartedTimestamp time.Time
|
|
}
|
|
|
|
func (d *dummyServer) ChannelzMetric() *channelz.ServerInternalMetric {
|
|
return &channelz.ServerInternalMetric{
|
|
CallsStarted: d.callsStarted,
|
|
CallsSucceeded: d.callsSucceeded,
|
|
CallsFailed: d.callsFailed,
|
|
LastCallStartedTimestamp: d.lastCallStartedTimestamp,
|
|
}
|
|
}
|
|
|
|
type dummySocket struct {
|
|
streamsStarted int64
|
|
streamsSucceeded int64
|
|
streamsFailed int64
|
|
messagesSent int64
|
|
messagesReceived int64
|
|
keepAlivesSent int64
|
|
lastLocalStreamCreatedTimestamp time.Time
|
|
lastRemoteStreamCreatedTimestamp time.Time
|
|
lastMessageSentTimestamp time.Time
|
|
lastMessageReceivedTimestamp time.Time
|
|
localFlowControlWindow int64
|
|
remoteFlowControlWindow int64
|
|
socketOptions *channelz.SocketOptionData
|
|
localAddr net.Addr
|
|
remoteAddr net.Addr
|
|
security credentials.ChannelzSecurityValue
|
|
remoteName string
|
|
}
|
|
|
|
func (d *dummySocket) ChannelzMetric() *channelz.SocketInternalMetric {
|
|
return &channelz.SocketInternalMetric{
|
|
StreamsStarted: d.streamsStarted,
|
|
StreamsSucceeded: d.streamsSucceeded,
|
|
StreamsFailed: d.streamsFailed,
|
|
MessagesSent: d.messagesSent,
|
|
MessagesReceived: d.messagesReceived,
|
|
KeepAlivesSent: d.keepAlivesSent,
|
|
LastLocalStreamCreatedTimestamp: d.lastLocalStreamCreatedTimestamp,
|
|
LastRemoteStreamCreatedTimestamp: d.lastRemoteStreamCreatedTimestamp,
|
|
LastMessageSentTimestamp: d.lastMessageSentTimestamp,
|
|
LastMessageReceivedTimestamp: d.lastMessageReceivedTimestamp,
|
|
LocalFlowControlWindow: d.localFlowControlWindow,
|
|
RemoteFlowControlWindow: d.remoteFlowControlWindow,
|
|
SocketOptions: d.socketOptions,
|
|
LocalAddr: d.localAddr,
|
|
RemoteAddr: d.remoteAddr,
|
|
Security: d.security,
|
|
RemoteName: d.remoteName,
|
|
}
|
|
}
|
|
|
|
func channelProtoToStruct(c *channelzpb.Channel) *dummyChannel {
|
|
dc := &dummyChannel{}
|
|
pdata := c.GetData()
|
|
switch pdata.GetState().GetState() {
|
|
case channelzpb.ChannelConnectivityState_UNKNOWN:
|
|
// TODO: what should we set here?
|
|
case channelzpb.ChannelConnectivityState_IDLE:
|
|
dc.state = connectivity.Idle
|
|
case channelzpb.ChannelConnectivityState_CONNECTING:
|
|
dc.state = connectivity.Connecting
|
|
case channelzpb.ChannelConnectivityState_READY:
|
|
dc.state = connectivity.Ready
|
|
case channelzpb.ChannelConnectivityState_TRANSIENT_FAILURE:
|
|
dc.state = connectivity.TransientFailure
|
|
case channelzpb.ChannelConnectivityState_SHUTDOWN:
|
|
dc.state = connectivity.Shutdown
|
|
}
|
|
dc.target = pdata.GetTarget()
|
|
dc.callsStarted = pdata.CallsStarted
|
|
dc.callsSucceeded = pdata.CallsSucceeded
|
|
dc.callsFailed = pdata.CallsFailed
|
|
if t, err := ptypes.Timestamp(pdata.GetLastCallStartedTimestamp()); err == nil {
|
|
if !t.Equal(emptyTime) {
|
|
dc.lastCallStartedTimestamp = t
|
|
}
|
|
}
|
|
return dc
|
|
}
|
|
|
|
func serverProtoToStruct(s *channelzpb.Server) *dummyServer {
|
|
ds := &dummyServer{}
|
|
pdata := s.GetData()
|
|
ds.callsStarted = pdata.CallsStarted
|
|
ds.callsSucceeded = pdata.CallsSucceeded
|
|
ds.callsFailed = pdata.CallsFailed
|
|
if t, err := ptypes.Timestamp(pdata.GetLastCallStartedTimestamp()); err == nil {
|
|
if !t.Equal(emptyTime) {
|
|
ds.lastCallStartedTimestamp = t
|
|
}
|
|
}
|
|
return ds
|
|
}
|
|
|
|
func socketProtoToStruct(s *channelzpb.Socket) *dummySocket {
|
|
ds := &dummySocket{}
|
|
pdata := s.GetData()
|
|
ds.streamsStarted = pdata.GetStreamsStarted()
|
|
ds.streamsSucceeded = pdata.GetStreamsSucceeded()
|
|
ds.streamsFailed = pdata.GetStreamsFailed()
|
|
ds.messagesSent = pdata.GetMessagesSent()
|
|
ds.messagesReceived = pdata.GetMessagesReceived()
|
|
ds.keepAlivesSent = pdata.GetKeepAlivesSent()
|
|
if t, err := ptypes.Timestamp(pdata.GetLastLocalStreamCreatedTimestamp()); err == nil {
|
|
if !t.Equal(emptyTime) {
|
|
ds.lastLocalStreamCreatedTimestamp = t
|
|
}
|
|
}
|
|
if t, err := ptypes.Timestamp(pdata.GetLastRemoteStreamCreatedTimestamp()); err == nil {
|
|
if !t.Equal(emptyTime) {
|
|
ds.lastRemoteStreamCreatedTimestamp = t
|
|
}
|
|
}
|
|
if t, err := ptypes.Timestamp(pdata.GetLastMessageSentTimestamp()); err == nil {
|
|
if !t.Equal(emptyTime) {
|
|
ds.lastMessageSentTimestamp = t
|
|
}
|
|
}
|
|
if t, err := ptypes.Timestamp(pdata.GetLastMessageReceivedTimestamp()); err == nil {
|
|
if !t.Equal(emptyTime) {
|
|
ds.lastMessageReceivedTimestamp = t
|
|
}
|
|
}
|
|
if v := pdata.GetLocalFlowControlWindow(); v != nil {
|
|
ds.localFlowControlWindow = v.Value
|
|
}
|
|
if v := pdata.GetRemoteFlowControlWindow(); v != nil {
|
|
ds.remoteFlowControlWindow = v.Value
|
|
}
|
|
if v := pdata.GetOption(); v != nil && protoToSocketOpt != nil {
|
|
ds.socketOptions = protoToSocketOpt(v)
|
|
}
|
|
if v := s.GetSecurity(); v != nil {
|
|
ds.security = protoToSecurity(v)
|
|
}
|
|
if local := s.GetLocal(); local != nil {
|
|
ds.localAddr = protoToAddr(local)
|
|
}
|
|
if remote := s.GetRemote(); remote != nil {
|
|
ds.remoteAddr = protoToAddr(remote)
|
|
}
|
|
ds.remoteName = s.GetRemoteName()
|
|
return ds
|
|
}
|
|
|
|
func protoToSecurity(protoSecurity *channelzpb.Security) credentials.ChannelzSecurityValue {
|
|
switch v := protoSecurity.Model.(type) {
|
|
case *channelzpb.Security_Tls_:
|
|
return &credentials.TLSChannelzSecurityValue{StandardName: v.Tls.GetStandardName(), LocalCertificate: v.Tls.GetLocalCertificate(), RemoteCertificate: v.Tls.GetRemoteCertificate()}
|
|
case *channelzpb.Security_Other:
|
|
sv := &credentials.OtherChannelzSecurityValue{Name: v.Other.GetName()}
|
|
var x ptypes.DynamicAny
|
|
if err := ptypes.UnmarshalAny(v.Other.GetValue(), &x); err == nil {
|
|
sv.Value = x.Message
|
|
}
|
|
return sv
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func protoToAddr(a *channelzpb.Address) net.Addr {
|
|
switch v := a.Address.(type) {
|
|
case *channelzpb.Address_TcpipAddress:
|
|
if port := v.TcpipAddress.GetPort(); port != 0 {
|
|
return &net.TCPAddr{IP: v.TcpipAddress.GetIpAddress(), Port: int(port)}
|
|
}
|
|
return &net.IPAddr{IP: v.TcpipAddress.GetIpAddress()}
|
|
case *channelzpb.Address_UdsAddress_:
|
|
return &net.UnixAddr{Name: v.UdsAddress.GetFilename(), Net: "unix"}
|
|
case *channelzpb.Address_OtherAddress_:
|
|
// TODO:
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func convertSocketRefSliceToMap(sktRefs []*channelzpb.SocketRef) map[int64]string {
|
|
m := make(map[int64]string)
|
|
for _, sr := range sktRefs {
|
|
m[sr.SocketId] = sr.Name
|
|
}
|
|
return m
|
|
}
|
|
|
|
type OtherSecurityValue struct {
|
|
LocalCertificate []byte `protobuf:"bytes,1,opt,name=local_certificate,json=localCertificate,proto3" json:"local_certificate,omitempty"`
|
|
RemoteCertificate []byte `protobuf:"bytes,2,opt,name=remote_certificate,json=remoteCertificate,proto3" json:"remote_certificate,omitempty"`
|
|
}
|
|
|
|
func (m *OtherSecurityValue) Reset() { *m = OtherSecurityValue{} }
|
|
func (m *OtherSecurityValue) String() string { return proto.CompactTextString(m) }
|
|
func (*OtherSecurityValue) ProtoMessage() {}
|
|
|
|
func init() {
|
|
// Ad-hoc registering the proto type here to facilitate UnmarshalAny of OtherSecurityValue.
|
|
proto.RegisterType((*OtherSecurityValue)(nil), "grpc.credentials.OtherChannelzSecurityValue")
|
|
}
|
|
|
|
func TestGetTopChannels(t *testing.T) {
|
|
tcs := []*dummyChannel{
|
|
{
|
|
state: connectivity.Connecting,
|
|
target: "test.channelz:1234",
|
|
callsStarted: 6,
|
|
callsSucceeded: 2,
|
|
callsFailed: 3,
|
|
lastCallStartedTimestamp: time.Now().UTC(),
|
|
},
|
|
{
|
|
state: connectivity.Connecting,
|
|
target: "test.channelz:1234",
|
|
callsStarted: 1,
|
|
callsSucceeded: 2,
|
|
callsFailed: 3,
|
|
lastCallStartedTimestamp: time.Now().UTC(),
|
|
},
|
|
{
|
|
state: connectivity.Shutdown,
|
|
target: "test.channelz:8888",
|
|
callsStarted: 0,
|
|
callsSucceeded: 0,
|
|
callsFailed: 0,
|
|
},
|
|
{},
|
|
}
|
|
channelz.NewChannelzStorage()
|
|
for _, c := range tcs {
|
|
channelz.RegisterChannel(c, 0, "")
|
|
}
|
|
s := newCZServer()
|
|
resp, _ := s.GetTopChannels(context.Background(), &channelzpb.GetTopChannelsRequest{StartChannelId: 0})
|
|
if !resp.GetEnd() {
|
|
t.Fatalf("resp.GetEnd() want true, got %v", resp.GetEnd())
|
|
}
|
|
for i, c := range resp.GetChannel() {
|
|
if !reflect.DeepEqual(channelProtoToStruct(c), tcs[i]) {
|
|
t.Fatalf("dummyChannel: %d, want: %#v, got: %#v", i, tcs[i], channelProtoToStruct(c))
|
|
}
|
|
}
|
|
for i := 0; i < 50; i++ {
|
|
channelz.RegisterChannel(tcs[0], 0, "")
|
|
}
|
|
resp, _ = s.GetTopChannels(context.Background(), &channelzpb.GetTopChannelsRequest{StartChannelId: 0})
|
|
if resp.GetEnd() {
|
|
t.Fatalf("resp.GetEnd() want false, got %v", resp.GetEnd())
|
|
}
|
|
}
|
|
|
|
func TestGetServers(t *testing.T) {
|
|
ss := []*dummyServer{
|
|
{
|
|
callsStarted: 6,
|
|
callsSucceeded: 2,
|
|
callsFailed: 3,
|
|
lastCallStartedTimestamp: time.Now().UTC(),
|
|
},
|
|
{
|
|
callsStarted: 1,
|
|
callsSucceeded: 2,
|
|
callsFailed: 3,
|
|
lastCallStartedTimestamp: time.Now().UTC(),
|
|
},
|
|
{
|
|
callsStarted: 1,
|
|
callsSucceeded: 0,
|
|
callsFailed: 0,
|
|
lastCallStartedTimestamp: time.Now().UTC(),
|
|
},
|
|
}
|
|
channelz.NewChannelzStorage()
|
|
for _, s := range ss {
|
|
channelz.RegisterServer(s, "")
|
|
}
|
|
svr := newCZServer()
|
|
resp, _ := svr.GetServers(context.Background(), &channelzpb.GetServersRequest{StartServerId: 0})
|
|
if !resp.GetEnd() {
|
|
t.Fatalf("resp.GetEnd() want true, got %v", resp.GetEnd())
|
|
}
|
|
for i, s := range resp.GetServer() {
|
|
if !reflect.DeepEqual(serverProtoToStruct(s), ss[i]) {
|
|
t.Fatalf("dummyServer: %d, want: %#v, got: %#v", i, ss[i], serverProtoToStruct(s))
|
|
}
|
|
}
|
|
for i := 0; i < 50; i++ {
|
|
channelz.RegisterServer(ss[0], "")
|
|
}
|
|
resp, _ = svr.GetServers(context.Background(), &channelzpb.GetServersRequest{StartServerId: 0})
|
|
if resp.GetEnd() {
|
|
t.Fatalf("resp.GetEnd() want false, got %v", resp.GetEnd())
|
|
}
|
|
}
|
|
|
|
func TestGetServerSockets(t *testing.T) {
|
|
channelz.NewChannelzStorage()
|
|
svrID := channelz.RegisterServer(&dummyServer{}, "")
|
|
refNames := []string{"listen socket 1", "normal socket 1", "normal socket 2"}
|
|
ids := make([]int64, 3)
|
|
ids[0] = channelz.RegisterListenSocket(&dummySocket{}, svrID, refNames[0])
|
|
ids[1] = channelz.RegisterNormalSocket(&dummySocket{}, svrID, refNames[1])
|
|
ids[2] = channelz.RegisterNormalSocket(&dummySocket{}, svrID, refNames[2])
|
|
svr := newCZServer()
|
|
resp, _ := svr.GetServerSockets(context.Background(), &channelzpb.GetServerSocketsRequest{ServerId: svrID, StartSocketId: 0})
|
|
if !resp.GetEnd() {
|
|
t.Fatalf("resp.GetEnd() want: true, got: %v", resp.GetEnd())
|
|
}
|
|
// GetServerSockets only return normal sockets.
|
|
want := map[int64]string{
|
|
ids[1]: refNames[1],
|
|
ids[2]: refNames[2],
|
|
}
|
|
if !reflect.DeepEqual(convertSocketRefSliceToMap(resp.GetSocketRef()), want) {
|
|
t.Fatalf("GetServerSockets want: %#v, got: %#v", want, resp.GetSocketRef())
|
|
}
|
|
|
|
for i := 0; i < 50; i++ {
|
|
channelz.RegisterNormalSocket(&dummySocket{}, svrID, "")
|
|
}
|
|
resp, _ = svr.GetServerSockets(context.Background(), &channelzpb.GetServerSocketsRequest{ServerId: svrID, StartSocketId: 0})
|
|
if resp.GetEnd() {
|
|
t.Fatalf("resp.GetEnd() want false, got %v", resp.GetEnd())
|
|
}
|
|
}
|
|
|
|
// This test makes a GetServerSockets with a non-zero start ID, and expect only
|
|
// sockets with ID >= the given start ID.
|
|
func TestGetServerSocketsNonZeroStartID(t *testing.T) {
|
|
channelz.NewChannelzStorage()
|
|
svrID := channelz.RegisterServer(&dummyServer{}, "")
|
|
refNames := []string{"listen socket 1", "normal socket 1", "normal socket 2"}
|
|
ids := make([]int64, 3)
|
|
ids[0] = channelz.RegisterListenSocket(&dummySocket{}, svrID, refNames[0])
|
|
ids[1] = channelz.RegisterNormalSocket(&dummySocket{}, svrID, refNames[1])
|
|
ids[2] = channelz.RegisterNormalSocket(&dummySocket{}, svrID, refNames[2])
|
|
svr := newCZServer()
|
|
// Make GetServerSockets with startID = ids[1]+1, so socket-1 won't be
|
|
// included in the response.
|
|
resp, _ := svr.GetServerSockets(context.Background(), &channelzpb.GetServerSocketsRequest{ServerId: svrID, StartSocketId: ids[1] + 1})
|
|
if !resp.GetEnd() {
|
|
t.Fatalf("resp.GetEnd() want: true, got: %v", resp.GetEnd())
|
|
}
|
|
// GetServerSockets only return normal socket-2, socket-1 should be
|
|
// filtered by start ID.
|
|
want := map[int64]string{
|
|
ids[2]: refNames[2],
|
|
}
|
|
if !reflect.DeepEqual(convertSocketRefSliceToMap(resp.GetSocketRef()), want) {
|
|
t.Fatalf("GetServerSockets want: %#v, got: %#v", want, resp.GetSocketRef())
|
|
}
|
|
}
|
|
|
|
func TestGetChannel(t *testing.T) {
|
|
channelz.NewChannelzStorage()
|
|
refNames := []string{"top channel 1", "nested channel 1", "sub channel 2", "nested channel 3"}
|
|
ids := make([]int64, 4)
|
|
ids[0] = channelz.RegisterChannel(&dummyChannel{}, 0, refNames[0])
|
|
channelz.AddTraceEvent(ids[0], &channelz.TraceEventDesc{
|
|
Desc: "Channel Created",
|
|
Severity: channelz.CtINFO,
|
|
})
|
|
ids[1] = channelz.RegisterChannel(&dummyChannel{}, ids[0], refNames[1])
|
|
channelz.AddTraceEvent(ids[1], &channelz.TraceEventDesc{
|
|
Desc: "Channel Created",
|
|
Severity: channelz.CtINFO,
|
|
Parent: &channelz.TraceEventDesc{
|
|
Desc: fmt.Sprintf("Nested Channel(id:%d) created", ids[1]),
|
|
Severity: channelz.CtINFO,
|
|
},
|
|
})
|
|
|
|
ids[2] = channelz.RegisterSubChannel(&dummyChannel{}, ids[0], refNames[2])
|
|
channelz.AddTraceEvent(ids[2], &channelz.TraceEventDesc{
|
|
Desc: "SubChannel Created",
|
|
Severity: channelz.CtINFO,
|
|
Parent: &channelz.TraceEventDesc{
|
|
Desc: fmt.Sprintf("SubChannel(id:%d) created", ids[2]),
|
|
Severity: channelz.CtINFO,
|
|
},
|
|
})
|
|
ids[3] = channelz.RegisterChannel(&dummyChannel{}, ids[1], refNames[3])
|
|
channelz.AddTraceEvent(ids[3], &channelz.TraceEventDesc{
|
|
Desc: "Channel Created",
|
|
Severity: channelz.CtINFO,
|
|
Parent: &channelz.TraceEventDesc{
|
|
Desc: fmt.Sprintf("Nested Channel(id:%d) created", ids[3]),
|
|
Severity: channelz.CtINFO,
|
|
},
|
|
})
|
|
channelz.AddTraceEvent(ids[0], &channelz.TraceEventDesc{
|
|
Desc: fmt.Sprintf("Channel Connectivity change to %v", connectivity.Ready),
|
|
Severity: channelz.CtINFO,
|
|
})
|
|
channelz.AddTraceEvent(ids[0], &channelz.TraceEventDesc{
|
|
Desc: "Resolver returns an empty address list",
|
|
Severity: channelz.CtWarning,
|
|
})
|
|
svr := newCZServer()
|
|
resp, _ := svr.GetChannel(context.Background(), &channelzpb.GetChannelRequest{ChannelId: ids[0]})
|
|
metrics := resp.GetChannel()
|
|
subChans := metrics.GetSubchannelRef()
|
|
if len(subChans) != 1 || subChans[0].GetName() != refNames[2] || subChans[0].GetSubchannelId() != ids[2] {
|
|
t.Fatalf("metrics.GetSubChannelRef() want %#v, got %#v", []*channelzpb.SubchannelRef{{SubchannelId: ids[2], Name: refNames[2]}}, subChans)
|
|
}
|
|
nestedChans := metrics.GetChannelRef()
|
|
if len(nestedChans) != 1 || nestedChans[0].GetName() != refNames[1] || nestedChans[0].GetChannelId() != ids[1] {
|
|
t.Fatalf("metrics.GetChannelRef() want %#v, got %#v", []*channelzpb.ChannelRef{{ChannelId: ids[1], Name: refNames[1]}}, nestedChans)
|
|
}
|
|
trace := metrics.GetData().GetTrace()
|
|
want := []struct {
|
|
desc string
|
|
severity channelzpb.ChannelTraceEvent_Severity
|
|
childID int64
|
|
childRef string
|
|
}{
|
|
{desc: "Channel Created", severity: channelzpb.ChannelTraceEvent_CT_INFO},
|
|
{desc: fmt.Sprintf("Nested Channel(id:%d) created", ids[1]), severity: channelzpb.ChannelTraceEvent_CT_INFO, childID: ids[1], childRef: refNames[1]},
|
|
{desc: fmt.Sprintf("SubChannel(id:%d) created", ids[2]), severity: channelzpb.ChannelTraceEvent_CT_INFO, childID: ids[2], childRef: refNames[2]},
|
|
{desc: fmt.Sprintf("Channel Connectivity change to %v", connectivity.Ready), severity: channelzpb.ChannelTraceEvent_CT_INFO},
|
|
{desc: "Resolver returns an empty address list", severity: channelzpb.ChannelTraceEvent_CT_WARNING},
|
|
}
|
|
|
|
for i, e := range trace.Events {
|
|
if e.GetDescription() != want[i].desc {
|
|
t.Fatalf("trace: GetDescription want %#v, got %#v", want[i].desc, e.GetDescription())
|
|
}
|
|
if e.GetSeverity() != want[i].severity {
|
|
t.Fatalf("trace: GetSeverity want %#v, got %#v", want[i].severity, e.GetSeverity())
|
|
}
|
|
if want[i].childID == 0 && (e.GetChannelRef() != nil || e.GetSubchannelRef() != nil) {
|
|
t.Fatalf("trace: GetChannelRef() should return nil, as there is no reference")
|
|
}
|
|
if e.GetChannelRef().GetChannelId() != want[i].childID || e.GetChannelRef().GetName() != want[i].childRef {
|
|
if e.GetSubchannelRef().GetSubchannelId() != want[i].childID || e.GetSubchannelRef().GetName() != want[i].childRef {
|
|
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())
|
|
}
|
|
}
|
|
}
|
|
resp, _ = svr.GetChannel(context.Background(), &channelzpb.GetChannelRequest{ChannelId: ids[1]})
|
|
metrics = resp.GetChannel()
|
|
nestedChans = metrics.GetChannelRef()
|
|
if len(nestedChans) != 1 || nestedChans[0].GetName() != refNames[3] || nestedChans[0].GetChannelId() != ids[3] {
|
|
t.Fatalf("metrics.GetChannelRef() want %#v, got %#v", []*channelzpb.ChannelRef{{ChannelId: ids[3], Name: refNames[3]}}, nestedChans)
|
|
}
|
|
}
|
|
|
|
func TestGetSubChannel(t *testing.T) {
|
|
var (
|
|
subchanCreated = "SubChannel Created"
|
|
subchanConnectivityChange = fmt.Sprintf("Subchannel Connectivity change to %v", connectivity.Ready)
|
|
subChanPickNewAddress = fmt.Sprintf("Subchannel picks a new address %q to connect", "0.0.0.0")
|
|
)
|
|
channelz.NewChannelzStorage()
|
|
refNames := []string{"top channel 1", "sub channel 1", "socket 1", "socket 2"}
|
|
ids := make([]int64, 4)
|
|
ids[0] = channelz.RegisterChannel(&dummyChannel{}, 0, refNames[0])
|
|
channelz.AddTraceEvent(ids[0], &channelz.TraceEventDesc{
|
|
Desc: "Channel Created",
|
|
Severity: channelz.CtINFO,
|
|
})
|
|
ids[1] = channelz.RegisterSubChannel(&dummyChannel{}, ids[0], refNames[1])
|
|
channelz.AddTraceEvent(ids[1], &channelz.TraceEventDesc{
|
|
Desc: subchanCreated,
|
|
Severity: channelz.CtINFO,
|
|
Parent: &channelz.TraceEventDesc{
|
|
Desc: fmt.Sprintf("Nested Channel(id:%d) created", ids[0]),
|
|
Severity: channelz.CtINFO,
|
|
},
|
|
})
|
|
ids[2] = channelz.RegisterNormalSocket(&dummySocket{}, ids[1], refNames[2])
|
|
ids[3] = channelz.RegisterNormalSocket(&dummySocket{}, ids[1], refNames[3])
|
|
channelz.AddTraceEvent(ids[1], &channelz.TraceEventDesc{
|
|
Desc: subchanConnectivityChange,
|
|
Severity: channelz.CtINFO,
|
|
})
|
|
channelz.AddTraceEvent(ids[1], &channelz.TraceEventDesc{
|
|
Desc: subChanPickNewAddress,
|
|
Severity: channelz.CtINFO,
|
|
})
|
|
svr := newCZServer()
|
|
resp, _ := svr.GetSubchannel(context.Background(), &channelzpb.GetSubchannelRequest{SubchannelId: ids[1]})
|
|
metrics := resp.GetSubchannel()
|
|
want := map[int64]string{
|
|
ids[2]: refNames[2],
|
|
ids[3]: refNames[3],
|
|
}
|
|
if !reflect.DeepEqual(convertSocketRefSliceToMap(metrics.GetSocketRef()), want) {
|
|
t.Fatalf("metrics.GetSocketRef() want %#v: got: %#v", want, metrics.GetSocketRef())
|
|
}
|
|
|
|
trace := metrics.GetData().GetTrace()
|
|
wantTrace := []struct {
|
|
desc string
|
|
severity channelzpb.ChannelTraceEvent_Severity
|
|
childID int64
|
|
childRef string
|
|
}{
|
|
{desc: subchanCreated, severity: channelzpb.ChannelTraceEvent_CT_INFO},
|
|
{desc: subchanConnectivityChange, severity: channelzpb.ChannelTraceEvent_CT_INFO},
|
|
{desc: subChanPickNewAddress, severity: channelzpb.ChannelTraceEvent_CT_INFO},
|
|
}
|
|
for i, e := range trace.Events {
|
|
if e.GetDescription() != wantTrace[i].desc {
|
|
t.Fatalf("trace: GetDescription want %#v, got %#v", wantTrace[i].desc, e.GetDescription())
|
|
}
|
|
if e.GetSeverity() != wantTrace[i].severity {
|
|
t.Fatalf("trace: GetSeverity want %#v, got %#v", wantTrace[i].severity, e.GetSeverity())
|
|
}
|
|
if wantTrace[i].childID == 0 && (e.GetChannelRef() != nil || e.GetSubchannelRef() != nil) {
|
|
t.Fatalf("trace: GetChannelRef() should return nil, as there is no reference")
|
|
}
|
|
if e.GetChannelRef().GetChannelId() != wantTrace[i].childID || e.GetChannelRef().GetName() != wantTrace[i].childRef {
|
|
if e.GetSubchannelRef().GetSubchannelId() != wantTrace[i].childID || e.GetSubchannelRef().GetName() != wantTrace[i].childRef {
|
|
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())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGetSocket(t *testing.T) {
|
|
channelz.NewChannelzStorage()
|
|
ss := []*dummySocket{
|
|
{
|
|
streamsStarted: 10,
|
|
streamsSucceeded: 2,
|
|
streamsFailed: 3,
|
|
messagesSent: 20,
|
|
messagesReceived: 10,
|
|
keepAlivesSent: 2,
|
|
lastLocalStreamCreatedTimestamp: time.Now().UTC(),
|
|
lastRemoteStreamCreatedTimestamp: time.Now().UTC(),
|
|
lastMessageSentTimestamp: time.Now().UTC(),
|
|
lastMessageReceivedTimestamp: time.Now().UTC(),
|
|
localFlowControlWindow: 65536,
|
|
remoteFlowControlWindow: 1024,
|
|
localAddr: &net.TCPAddr{IP: net.ParseIP("1.0.0.1"), Port: 10001},
|
|
remoteAddr: &net.TCPAddr{IP: net.ParseIP("12.0.0.1"), Port: 10002},
|
|
remoteName: "remote.remote",
|
|
},
|
|
{
|
|
streamsStarted: 10,
|
|
streamsSucceeded: 2,
|
|
streamsFailed: 3,
|
|
messagesSent: 20,
|
|
messagesReceived: 10,
|
|
keepAlivesSent: 2,
|
|
lastRemoteStreamCreatedTimestamp: time.Now().UTC(),
|
|
lastMessageSentTimestamp: time.Now().UTC(),
|
|
lastMessageReceivedTimestamp: time.Now().UTC(),
|
|
localFlowControlWindow: 65536,
|
|
remoteFlowControlWindow: 1024,
|
|
localAddr: &net.UnixAddr{Name: "file.path", Net: "unix"},
|
|
remoteAddr: &net.UnixAddr{Name: "another.path", Net: "unix"},
|
|
remoteName: "remote.remote",
|
|
},
|
|
{
|
|
streamsStarted: 5,
|
|
streamsSucceeded: 2,
|
|
streamsFailed: 3,
|
|
messagesSent: 20,
|
|
messagesReceived: 10,
|
|
keepAlivesSent: 2,
|
|
lastLocalStreamCreatedTimestamp: time.Now().UTC(),
|
|
lastMessageSentTimestamp: time.Now().UTC(),
|
|
lastMessageReceivedTimestamp: time.Now().UTC(),
|
|
localFlowControlWindow: 65536,
|
|
remoteFlowControlWindow: 10240,
|
|
localAddr: &net.IPAddr{IP: net.ParseIP("1.0.0.1")},
|
|
remoteAddr: &net.IPAddr{IP: net.ParseIP("9.0.0.1")},
|
|
remoteName: "",
|
|
},
|
|
{
|
|
localAddr: &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 10001},
|
|
},
|
|
{
|
|
security: &credentials.TLSChannelzSecurityValue{
|
|
StandardName: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
|
RemoteCertificate: []byte{48, 130, 2, 156, 48, 130, 2, 5, 160},
|
|
},
|
|
},
|
|
{
|
|
security: &credentials.OtherChannelzSecurityValue{
|
|
Name: "XXXX",
|
|
},
|
|
},
|
|
{
|
|
security: &credentials.OtherChannelzSecurityValue{
|
|
Name: "YYYY",
|
|
Value: &OtherSecurityValue{LocalCertificate: []byte{1, 2, 3}, RemoteCertificate: []byte{4, 5, 6}},
|
|
},
|
|
},
|
|
}
|
|
svr := newCZServer()
|
|
ids := make([]int64, len(ss))
|
|
svrID := channelz.RegisterServer(&dummyServer{}, "")
|
|
for i, s := range ss {
|
|
ids[i] = channelz.RegisterNormalSocket(s, svrID, strconv.Itoa(i))
|
|
}
|
|
for i, s := range ss {
|
|
resp, _ := svr.GetSocket(context.Background(), &channelzpb.GetSocketRequest{SocketId: ids[i]})
|
|
metrics := resp.GetSocket()
|
|
if !reflect.DeepEqual(metrics.GetRef(), &channelzpb.SocketRef{SocketId: ids[i], Name: strconv.Itoa(i)}) || !reflect.DeepEqual(socketProtoToStruct(metrics), s) {
|
|
t.Fatalf("resp.GetSocket() want: metrics.GetRef() = %#v and %#v, got: metrics.GetRef() = %#v and %#v", &channelzpb.SocketRef{SocketId: ids[i], Name: strconv.Itoa(i)}, s, metrics.GetRef(), socketProtoToStruct(metrics))
|
|
}
|
|
}
|
|
}
|