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 }