google.golang.org/grpc@v1.72.2/stats/opentelemetry/internal/tracing/carrier_test.go (about)

     1  /*
     2   *
     3   * Copyright 2024 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   *     htestp://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 tracing
    20  
    21  import (
    22  	"context"
    23  	"testing"
    24  
    25  	"github.com/google/go-cmp/cmp"
    26  	"github.com/google/go-cmp/cmp/cmpopts"
    27  	"google.golang.org/grpc/internal/grpctest"
    28  	"google.golang.org/grpc/metadata"
    29  )
    30  
    31  type s struct {
    32  	grpctest.Tester
    33  }
    34  
    35  func Test(t *testing.T) {
    36  	grpctest.RunSubTests(t, s{})
    37  }
    38  
    39  // TestIncomingCarrier verifies that `IncomingCarrier.Get()` returns correct
    40  // value for the corresponding key in the carrier's context metadata, if key is
    41  // present. If key is not present, it verifies that empty string is returned.
    42  //
    43  // If multiple values are present for a key, it verifies that last value is
    44  // returned.
    45  //
    46  // If key ends with `-bin`, it verifies that a correct binary value is returned
    47  // in the string format for the binary header.
    48  func (s) TestIncomingCarrier(t *testing.T) {
    49  	tests := []struct {
    50  		name     string
    51  		md       metadata.MD
    52  		key      string
    53  		want     string
    54  		wantKeys []string
    55  	}{
    56  		{
    57  			name:     "existing key",
    58  			md:       metadata.Pairs("key1", "value1"),
    59  			key:      "key1",
    60  			want:     "value1",
    61  			wantKeys: []string{"key1"},
    62  		},
    63  		{
    64  			name:     "non-existing key",
    65  			md:       metadata.Pairs("key1", "value1"),
    66  			key:      "key2",
    67  			want:     "",
    68  			wantKeys: []string{"key1"},
    69  		},
    70  		{
    71  			name:     "empty key",
    72  			md:       metadata.MD{},
    73  			key:      "key1",
    74  			want:     "",
    75  			wantKeys: []string{},
    76  		},
    77  		{
    78  			name:     "more than one key/value pair",
    79  			md:       metadata.MD{"key1": []string{"value1"}, "key2": []string{"value2"}},
    80  			key:      "key2",
    81  			want:     "value2",
    82  			wantKeys: []string{"key1", "key2"},
    83  		},
    84  		{
    85  			name:     "more than one value for a key",
    86  			md:       metadata.MD{"key1": []string{"value1", "value2"}},
    87  			key:      "key1",
    88  			want:     "value2",
    89  			wantKeys: []string{"key1"},
    90  		},
    91  		{
    92  			name:     "grpc-trace-bin key",
    93  			md:       metadata.Pairs("grpc-trace-bin", string([]byte{0x01, 0x02, 0x03})),
    94  			key:      "grpc-trace-bin",
    95  			want:     string([]byte{0x01, 0x02, 0x03}),
    96  			wantKeys: []string{"grpc-trace-bin"},
    97  		},
    98  		{
    99  			name:     "grpc-trace-bin key with another string key",
   100  			md:       metadata.MD{"key1": []string{"value1"}, "grpc-trace-bin": []string{string([]byte{0x01, 0x02, 0x03})}},
   101  			key:      "grpc-trace-bin",
   102  			want:     string([]byte{0x01, 0x02, 0x03}),
   103  			wantKeys: []string{"key1", "grpc-trace-bin"},
   104  		},
   105  	}
   106  
   107  	for _, test := range tests {
   108  		t.Run(test.name, func(t *testing.T) {
   109  			ctx, cancel := context.WithCancel(context.Background())
   110  			defer cancel()
   111  			c := NewIncomingCarrier(metadata.NewIncomingContext(ctx, test.md))
   112  			got := c.Get(test.key)
   113  			if got != test.want {
   114  				t.Fatalf("c.Get() = %s, want %s", got, test.want)
   115  			}
   116  			if gotKeys := c.Keys(); !cmp.Equal(test.wantKeys, gotKeys, cmpopts.SortSlices(func(a, b string) bool { return a < b })) {
   117  				t.Fatalf("c.Keys() = keys %v, want %v", gotKeys, test.wantKeys)
   118  			}
   119  		})
   120  	}
   121  }
   122  
   123  // TestOutgoingCarrier verifies that a key-value pair is set in carrier's
   124  // context metadata using `OutgoingCarrier.Set()`. If key is not present, it
   125  // verifies that key-value pair is insterted. If key is already present, it
   126  // verifies that new value is appended at the end of list for the existing key.
   127  //
   128  // If key ends with `-bin`, it verifies that a binary value is set for
   129  // `-bin` header in string format.
   130  //
   131  // It also verifies that both existing and newly inserted keys are present in
   132  // the carrier's context using `Carrier.Keys()`.
   133  func (s) TestOutgoingCarrier(t *testing.T) {
   134  	tests := []struct {
   135  		name      string
   136  		initialMD metadata.MD
   137  		setKey    string
   138  		setValue  string
   139  		wantValue string // expected value of the set key
   140  		wantKeys  []string
   141  	}{
   142  		{
   143  			name:      "new key",
   144  			initialMD: metadata.MD{},
   145  			setKey:    "key1",
   146  			setValue:  "value1",
   147  			wantValue: "value1",
   148  			wantKeys:  []string{"key1"},
   149  		},
   150  		{
   151  			name:      "add to existing key",
   152  			initialMD: metadata.MD{"key1": []string{"oldvalue"}},
   153  			setKey:    "key1",
   154  			setValue:  "newvalue",
   155  			wantValue: "newvalue",
   156  			wantKeys:  []string{"key1"},
   157  		},
   158  		{
   159  			name:      "new key with different existing key",
   160  			initialMD: metadata.MD{"key2": []string{"value2"}},
   161  			setKey:    "key1",
   162  			setValue:  "value1",
   163  			wantValue: "value1",
   164  			wantKeys:  []string{"key2", "key1"},
   165  		},
   166  		{
   167  			name:      "grpc-trace-bin binary key",
   168  			initialMD: metadata.MD{"key1": []string{"value1"}},
   169  			setKey:    "grpc-trace-bin",
   170  			setValue:  string([]byte{0x01, 0x02, 0x03}),
   171  			wantValue: string([]byte{0x01, 0x02, 0x03}),
   172  			wantKeys:  []string{"key1", "grpc-trace-bin"},
   173  		},
   174  	}
   175  
   176  	for _, test := range tests {
   177  		t.Run(test.name, func(t *testing.T) {
   178  			ctx, cancel := context.WithCancel(context.Background())
   179  			defer cancel()
   180  			c := NewOutgoingCarrier(metadata.NewOutgoingContext(ctx, test.initialMD))
   181  			c.Set(test.setKey, test.setValue)
   182  			if gotKeys := c.Keys(); !cmp.Equal(test.wantKeys, gotKeys, cmpopts.SortSlices(func(a, b string) bool { return a < b })) {
   183  				t.Fatalf("c.Keys() = keys %v, want %v", gotKeys, test.wantKeys)
   184  			}
   185  			if md, ok := metadata.FromOutgoingContext(c.Context()); ok && md.Get(test.setKey)[len(md.Get(test.setKey))-1] != test.wantValue {
   186  				t.Fatalf("got value %s, want %s, for key %s", md.Get(test.setKey)[len(md.Get(test.setKey))-1], test.wantValue, test.setKey)
   187  			}
   188  		})
   189  	}
   190  }