google.golang.org/grpc@v1.72.2/internal/binarylog/method_logger_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 binarylog
    20  
    21  import (
    22  	"bytes"
    23  	"context"
    24  	"fmt"
    25  	"net"
    26  	"testing"
    27  	"time"
    28  
    29  	binlogpb "google.golang.org/grpc/binarylog/grpc_binarylog_v1"
    30  	"google.golang.org/grpc/codes"
    31  	"google.golang.org/grpc/status"
    32  	"google.golang.org/protobuf/proto"
    33  	"google.golang.org/protobuf/types/known/durationpb"
    34  )
    35  
    36  const defaultTestTimeout = 10 * time.Second
    37  
    38  func (s) TestLog(t *testing.T) {
    39  	idGen.reset()
    40  	ml := NewTruncatingMethodLogger(10, 10)
    41  	// Set sink to testing buffer.
    42  	buf := bytes.NewBuffer(nil)
    43  	ml.sink = newWriterSink(buf)
    44  
    45  	addr := "1.2.3.4"
    46  	port := 790
    47  	tcpAddr, _ := net.ResolveTCPAddr("tcp", fmt.Sprintf("%v:%d", addr, port))
    48  	addr6 := "2001:1db8:85a3::8a2e:1370:7334"
    49  	port6 := 796
    50  	tcpAddr6, _ := net.ResolveTCPAddr("tcp", fmt.Sprintf("[%v]:%d", addr6, port6))
    51  
    52  	testProtoMsg := &binlogpb.Message{
    53  		Length: 1,
    54  		Data:   []byte{'a'},
    55  	}
    56  	testProtoBytes, _ := proto.Marshal(testProtoMsg)
    57  
    58  	testCases := []struct {
    59  		config LogEntryConfig
    60  		want   *binlogpb.GrpcLogEntry
    61  	}{
    62  		{
    63  			config: &ClientHeader{
    64  				OnClientSide: false,
    65  				Header: map[string][]string{
    66  					"a": {"b", "bb"},
    67  				},
    68  				MethodName: "testservice/testmethod",
    69  				Authority:  "test.service.io",
    70  				Timeout:    2*time.Second + 3*time.Nanosecond,
    71  				PeerAddr:   tcpAddr,
    72  			},
    73  			want: &binlogpb.GrpcLogEntry{
    74  				Timestamp:            nil,
    75  				CallId:               1,
    76  				SequenceIdWithinCall: 0,
    77  				Type:                 binlogpb.GrpcLogEntry_EVENT_TYPE_CLIENT_HEADER,
    78  				Logger:               binlogpb.GrpcLogEntry_LOGGER_SERVER,
    79  				Payload: &binlogpb.GrpcLogEntry_ClientHeader{
    80  					ClientHeader: &binlogpb.ClientHeader{
    81  						Metadata: &binlogpb.Metadata{
    82  							Entry: []*binlogpb.MetadataEntry{
    83  								{Key: "a", Value: []byte{'b'}},
    84  								{Key: "a", Value: []byte{'b', 'b'}},
    85  							},
    86  						},
    87  						MethodName: "testservice/testmethod",
    88  						Authority:  "test.service.io",
    89  						Timeout: &durationpb.Duration{
    90  							Seconds: 2,
    91  							Nanos:   3,
    92  						},
    93  					},
    94  				},
    95  				PayloadTruncated: false,
    96  				Peer: &binlogpb.Address{
    97  					Type:    binlogpb.Address_TYPE_IPV4,
    98  					Address: addr,
    99  					IpPort:  uint32(port),
   100  				},
   101  			},
   102  		},
   103  		{
   104  			config: &ClientHeader{
   105  				OnClientSide: false,
   106  				MethodName:   "testservice/testmethod",
   107  				Authority:    "test.service.io",
   108  			},
   109  			want: &binlogpb.GrpcLogEntry{
   110  				Timestamp:            nil,
   111  				CallId:               1,
   112  				SequenceIdWithinCall: 0,
   113  				Type:                 binlogpb.GrpcLogEntry_EVENT_TYPE_CLIENT_HEADER,
   114  				Logger:               binlogpb.GrpcLogEntry_LOGGER_SERVER,
   115  				Payload: &binlogpb.GrpcLogEntry_ClientHeader{
   116  					ClientHeader: &binlogpb.ClientHeader{
   117  						Metadata:   &binlogpb.Metadata{},
   118  						MethodName: "testservice/testmethod",
   119  						Authority:  "test.service.io",
   120  					},
   121  				},
   122  				PayloadTruncated: false,
   123  			},
   124  		},
   125  		{
   126  			config: &ServerHeader{
   127  				OnClientSide: true,
   128  				Header: map[string][]string{
   129  					"a": {"b", "bb"},
   130  				},
   131  				PeerAddr: tcpAddr6,
   132  			},
   133  			want: &binlogpb.GrpcLogEntry{
   134  				Timestamp:            nil,
   135  				CallId:               1,
   136  				SequenceIdWithinCall: 0,
   137  				Type:                 binlogpb.GrpcLogEntry_EVENT_TYPE_SERVER_HEADER,
   138  				Logger:               binlogpb.GrpcLogEntry_LOGGER_CLIENT,
   139  				Payload: &binlogpb.GrpcLogEntry_ServerHeader{
   140  					ServerHeader: &binlogpb.ServerHeader{
   141  						Metadata: &binlogpb.Metadata{
   142  							Entry: []*binlogpb.MetadataEntry{
   143  								{Key: "a", Value: []byte{'b'}},
   144  								{Key: "a", Value: []byte{'b', 'b'}},
   145  							},
   146  						},
   147  					},
   148  				},
   149  				PayloadTruncated: false,
   150  				Peer: &binlogpb.Address{
   151  					Type:    binlogpb.Address_TYPE_IPV6,
   152  					Address: addr6,
   153  					IpPort:  uint32(port6),
   154  				},
   155  			},
   156  		},
   157  		{
   158  			config: &ClientMessage{
   159  				OnClientSide: true,
   160  				Message:      testProtoMsg,
   161  			},
   162  			want: &binlogpb.GrpcLogEntry{
   163  				Timestamp:            nil,
   164  				CallId:               1,
   165  				SequenceIdWithinCall: 0,
   166  				Type:                 binlogpb.GrpcLogEntry_EVENT_TYPE_CLIENT_MESSAGE,
   167  				Logger:               binlogpb.GrpcLogEntry_LOGGER_CLIENT,
   168  				Payload: &binlogpb.GrpcLogEntry_Message{
   169  					Message: &binlogpb.Message{
   170  						Length: uint32(len(testProtoBytes)),
   171  						Data:   testProtoBytes,
   172  					},
   173  				},
   174  				PayloadTruncated: false,
   175  				Peer:             nil,
   176  			},
   177  		},
   178  		{
   179  			config: &ServerMessage{
   180  				OnClientSide: false,
   181  				Message:      testProtoMsg,
   182  			},
   183  			want: &binlogpb.GrpcLogEntry{
   184  				Timestamp:            nil,
   185  				CallId:               1,
   186  				SequenceIdWithinCall: 0,
   187  				Type:                 binlogpb.GrpcLogEntry_EVENT_TYPE_SERVER_MESSAGE,
   188  				Logger:               binlogpb.GrpcLogEntry_LOGGER_SERVER,
   189  				Payload: &binlogpb.GrpcLogEntry_Message{
   190  					Message: &binlogpb.Message{
   191  						Length: uint32(len(testProtoBytes)),
   192  						Data:   testProtoBytes,
   193  					},
   194  				},
   195  				PayloadTruncated: false,
   196  				Peer:             nil,
   197  			},
   198  		},
   199  		{
   200  			config: &ClientHalfClose{
   201  				OnClientSide: false,
   202  			},
   203  			want: &binlogpb.GrpcLogEntry{
   204  				Timestamp:            nil,
   205  				CallId:               1,
   206  				SequenceIdWithinCall: 0,
   207  				Type:                 binlogpb.GrpcLogEntry_EVENT_TYPE_CLIENT_HALF_CLOSE,
   208  				Logger:               binlogpb.GrpcLogEntry_LOGGER_SERVER,
   209  				Payload:              nil,
   210  				PayloadTruncated:     false,
   211  				Peer:                 nil,
   212  			},
   213  		},
   214  		{
   215  			config: &ServerTrailer{
   216  				OnClientSide: true,
   217  				Err:          status.Errorf(codes.Unavailable, "test"),
   218  				PeerAddr:     tcpAddr,
   219  			},
   220  			want: &binlogpb.GrpcLogEntry{
   221  				Timestamp:            nil,
   222  				CallId:               1,
   223  				SequenceIdWithinCall: 0,
   224  				Type:                 binlogpb.GrpcLogEntry_EVENT_TYPE_SERVER_TRAILER,
   225  				Logger:               binlogpb.GrpcLogEntry_LOGGER_CLIENT,
   226  				Payload: &binlogpb.GrpcLogEntry_Trailer{
   227  					Trailer: &binlogpb.Trailer{
   228  						Metadata:      &binlogpb.Metadata{},
   229  						StatusCode:    uint32(codes.Unavailable),
   230  						StatusMessage: "test",
   231  						StatusDetails: nil,
   232  					},
   233  				},
   234  				PayloadTruncated: false,
   235  				Peer: &binlogpb.Address{
   236  					Type:    binlogpb.Address_TYPE_IPV4,
   237  					Address: addr,
   238  					IpPort:  uint32(port),
   239  				},
   240  			},
   241  		},
   242  		{ // Err is nil, Log OK status.
   243  			config: &ServerTrailer{
   244  				OnClientSide: true,
   245  			},
   246  			want: &binlogpb.GrpcLogEntry{
   247  				Timestamp:            nil,
   248  				CallId:               1,
   249  				SequenceIdWithinCall: 0,
   250  				Type:                 binlogpb.GrpcLogEntry_EVENT_TYPE_SERVER_TRAILER,
   251  				Logger:               binlogpb.GrpcLogEntry_LOGGER_CLIENT,
   252  				Payload: &binlogpb.GrpcLogEntry_Trailer{
   253  					Trailer: &binlogpb.Trailer{
   254  						Metadata:      &binlogpb.Metadata{},
   255  						StatusCode:    uint32(codes.OK),
   256  						StatusMessage: "",
   257  						StatusDetails: nil,
   258  					},
   259  				},
   260  				PayloadTruncated: false,
   261  				Peer:             nil,
   262  			},
   263  		},
   264  		{
   265  			config: &Cancel{
   266  				OnClientSide: true,
   267  			},
   268  			want: &binlogpb.GrpcLogEntry{
   269  				Timestamp:            nil,
   270  				CallId:               1,
   271  				SequenceIdWithinCall: 0,
   272  				Type:                 binlogpb.GrpcLogEntry_EVENT_TYPE_CANCEL,
   273  				Logger:               binlogpb.GrpcLogEntry_LOGGER_CLIENT,
   274  				Payload:              nil,
   275  				PayloadTruncated:     false,
   276  				Peer:                 nil,
   277  			},
   278  		},
   279  
   280  		// gRPC headers should be omitted.
   281  		{
   282  			config: &ClientHeader{
   283  				OnClientSide: false,
   284  				Header: map[string][]string{
   285  					"grpc-reserved": {"to be omitted"},
   286  					":authority":    {"to be omitted"},
   287  					"a":             {"b", "bb"},
   288  				},
   289  			},
   290  			want: &binlogpb.GrpcLogEntry{
   291  				Timestamp:            nil,
   292  				CallId:               1,
   293  				SequenceIdWithinCall: 0,
   294  				Type:                 binlogpb.GrpcLogEntry_EVENT_TYPE_CLIENT_HEADER,
   295  				Logger:               binlogpb.GrpcLogEntry_LOGGER_SERVER,
   296  				Payload: &binlogpb.GrpcLogEntry_ClientHeader{
   297  					ClientHeader: &binlogpb.ClientHeader{
   298  						Metadata: &binlogpb.Metadata{
   299  							Entry: []*binlogpb.MetadataEntry{
   300  								{Key: "a", Value: []byte{'b'}},
   301  								{Key: "a", Value: []byte{'b', 'b'}},
   302  							},
   303  						},
   304  					},
   305  				},
   306  				PayloadTruncated: false,
   307  			},
   308  		},
   309  		{
   310  			config: &ServerHeader{
   311  				OnClientSide: true,
   312  				Header: map[string][]string{
   313  					"grpc-reserved": {"to be omitted"},
   314  					":authority":    {"to be omitted"},
   315  					"a":             {"b", "bb"},
   316  				},
   317  			},
   318  			want: &binlogpb.GrpcLogEntry{
   319  				Timestamp:            nil,
   320  				CallId:               1,
   321  				SequenceIdWithinCall: 0,
   322  				Type:                 binlogpb.GrpcLogEntry_EVENT_TYPE_SERVER_HEADER,
   323  				Logger:               binlogpb.GrpcLogEntry_LOGGER_CLIENT,
   324  				Payload: &binlogpb.GrpcLogEntry_ServerHeader{
   325  					ServerHeader: &binlogpb.ServerHeader{
   326  						Metadata: &binlogpb.Metadata{
   327  							Entry: []*binlogpb.MetadataEntry{
   328  								{Key: "a", Value: []byte{'b'}},
   329  								{Key: "a", Value: []byte{'b', 'b'}},
   330  							},
   331  						},
   332  					},
   333  				},
   334  				PayloadTruncated: false,
   335  			},
   336  		},
   337  	}
   338  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   339  	defer cancel()
   340  	for i, tc := range testCases {
   341  		buf.Reset()
   342  		tc.want.SequenceIdWithinCall = uint64(i + 1)
   343  		ml.Log(ctx, tc.config)
   344  		inSink := new(binlogpb.GrpcLogEntry)
   345  		if err := proto.Unmarshal(buf.Bytes()[4:], inSink); err != nil {
   346  			t.Errorf("failed to unmarshal bytes in sink to proto: %v", err)
   347  			continue
   348  		}
   349  		inSink.Timestamp = nil // Strip timestamp before comparing.
   350  		if !proto.Equal(inSink, tc.want) {
   351  			t.Errorf("Log(%+v), in sink: %+v, want %+v", tc.config, inSink, tc.want)
   352  		}
   353  	}
   354  }
   355  
   356  func (s) TestTruncateMetadataNotTruncated(t *testing.T) {
   357  	testCases := []struct {
   358  		ml   *TruncatingMethodLogger
   359  		mpPb *binlogpb.Metadata
   360  	}{
   361  		{
   362  			ml: NewTruncatingMethodLogger(maxUInt, maxUInt),
   363  			mpPb: &binlogpb.Metadata{
   364  				Entry: []*binlogpb.MetadataEntry{
   365  					{Key: "", Value: []byte{1}},
   366  				},
   367  			},
   368  		},
   369  		{
   370  			ml: NewTruncatingMethodLogger(2, maxUInt),
   371  			mpPb: &binlogpb.Metadata{
   372  				Entry: []*binlogpb.MetadataEntry{
   373  					{Key: "", Value: []byte{1}},
   374  				},
   375  			},
   376  		},
   377  		{
   378  			ml: NewTruncatingMethodLogger(1, maxUInt),
   379  			mpPb: &binlogpb.Metadata{
   380  				Entry: []*binlogpb.MetadataEntry{
   381  					{Key: "", Value: nil},
   382  				},
   383  			},
   384  		},
   385  		{
   386  			ml: NewTruncatingMethodLogger(2, maxUInt),
   387  			mpPb: &binlogpb.Metadata{
   388  				Entry: []*binlogpb.MetadataEntry{
   389  					{Key: "", Value: []byte{1, 1}},
   390  				},
   391  			},
   392  		},
   393  		{
   394  			ml: NewTruncatingMethodLogger(2, maxUInt),
   395  			mpPb: &binlogpb.Metadata{
   396  				Entry: []*binlogpb.MetadataEntry{
   397  					{Key: "", Value: []byte{1}},
   398  					{Key: "", Value: []byte{1}},
   399  				},
   400  			},
   401  		},
   402  		// "grpc-trace-bin" is kept in log but not counted towards the size
   403  		// limit.
   404  		{
   405  			ml: NewTruncatingMethodLogger(1, maxUInt),
   406  			mpPb: &binlogpb.Metadata{
   407  				Entry: []*binlogpb.MetadataEntry{
   408  					{Key: "", Value: []byte{1}},
   409  					{Key: "grpc-trace-bin", Value: []byte("some.trace.key")},
   410  				},
   411  			},
   412  		},
   413  	}
   414  
   415  	for i, tc := range testCases {
   416  		truncated := tc.ml.truncateMetadata(tc.mpPb)
   417  		if truncated {
   418  			t.Errorf("test case %v, returned truncated, want not truncated", i)
   419  		}
   420  	}
   421  }
   422  
   423  func (s) TestTruncateMetadataTruncated(t *testing.T) {
   424  	testCases := []struct {
   425  		ml   *TruncatingMethodLogger
   426  		mpPb *binlogpb.Metadata
   427  
   428  		entryLen int
   429  	}{
   430  		{
   431  			ml: NewTruncatingMethodLogger(2, maxUInt),
   432  			mpPb: &binlogpb.Metadata{
   433  				Entry: []*binlogpb.MetadataEntry{
   434  					{Key: "", Value: []byte{1, 1, 1}},
   435  				},
   436  			},
   437  			entryLen: 0,
   438  		},
   439  		{
   440  			ml: NewTruncatingMethodLogger(2, maxUInt),
   441  			mpPb: &binlogpb.Metadata{
   442  				Entry: []*binlogpb.MetadataEntry{
   443  					{Key: "", Value: []byte{1}},
   444  					{Key: "", Value: []byte{1}},
   445  					{Key: "", Value: []byte{1}},
   446  				},
   447  			},
   448  			entryLen: 2,
   449  		},
   450  		{
   451  			ml: NewTruncatingMethodLogger(2, maxUInt),
   452  			mpPb: &binlogpb.Metadata{
   453  				Entry: []*binlogpb.MetadataEntry{
   454  					{Key: "", Value: []byte{1, 1}},
   455  					{Key: "", Value: []byte{1}},
   456  				},
   457  			},
   458  			entryLen: 1,
   459  		},
   460  		{
   461  			ml: NewTruncatingMethodLogger(2, maxUInt),
   462  			mpPb: &binlogpb.Metadata{
   463  				Entry: []*binlogpb.MetadataEntry{
   464  					{Key: "", Value: []byte{1}},
   465  					{Key: "", Value: []byte{1, 1}},
   466  				},
   467  			},
   468  			entryLen: 1,
   469  		},
   470  	}
   471  
   472  	for i, tc := range testCases {
   473  		truncated := tc.ml.truncateMetadata(tc.mpPb)
   474  		if !truncated {
   475  			t.Errorf("test case %v, returned not truncated, want truncated", i)
   476  			continue
   477  		}
   478  		if len(tc.mpPb.Entry) != tc.entryLen {
   479  			t.Errorf("test case %v, entry length: %v, want: %v", i, len(tc.mpPb.Entry), tc.entryLen)
   480  		}
   481  	}
   482  }
   483  
   484  func (s) TestTruncateMessageNotTruncated(t *testing.T) {
   485  	testCases := []struct {
   486  		ml    *TruncatingMethodLogger
   487  		msgPb *binlogpb.Message
   488  	}{
   489  		{
   490  			ml: NewTruncatingMethodLogger(maxUInt, maxUInt),
   491  			msgPb: &binlogpb.Message{
   492  				Data: []byte{1},
   493  			},
   494  		},
   495  		{
   496  			ml: NewTruncatingMethodLogger(maxUInt, 3),
   497  			msgPb: &binlogpb.Message{
   498  				Data: []byte{1, 1},
   499  			},
   500  		},
   501  		{
   502  			ml: NewTruncatingMethodLogger(maxUInt, 2),
   503  			msgPb: &binlogpb.Message{
   504  				Data: []byte{1, 1},
   505  			},
   506  		},
   507  	}
   508  
   509  	for i, tc := range testCases {
   510  		truncated := tc.ml.truncateMessage(tc.msgPb)
   511  		if truncated {
   512  			t.Errorf("test case %v, returned truncated, want not truncated", i)
   513  		}
   514  	}
   515  }
   516  
   517  func (s) TestTruncateMessageTruncated(t *testing.T) {
   518  	testCases := []struct {
   519  		ml    *TruncatingMethodLogger
   520  		msgPb *binlogpb.Message
   521  
   522  		oldLength uint32
   523  	}{
   524  		{
   525  			ml: NewTruncatingMethodLogger(maxUInt, 2),
   526  			msgPb: &binlogpb.Message{
   527  				Length: 3,
   528  				Data:   []byte{1, 1, 1},
   529  			},
   530  			oldLength: 3,
   531  		},
   532  	}
   533  
   534  	for i, tc := range testCases {
   535  		truncated := tc.ml.truncateMessage(tc.msgPb)
   536  		if !truncated {
   537  			t.Errorf("test case %v, returned not truncated, want truncated", i)
   538  			continue
   539  		}
   540  		if len(tc.msgPb.Data) != int(tc.ml.messageMaxLen) {
   541  			t.Errorf("test case %v, message length: %v, want: %v", i, len(tc.msgPb.Data), tc.ml.messageMaxLen)
   542  		}
   543  		if tc.msgPb.Length != tc.oldLength {
   544  			t.Errorf("test case %v, message.Length field: %v, want: %v", i, tc.msgPb.Length, tc.oldLength)
   545  		}
   546  	}
   547  }