google.golang.org/grpc@v1.74.2/xds/internal/internal_test.go (about) 1 /* 2 * 3 * Copyright 2019 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 package internal 19 20 import ( 21 "reflect" 22 "strings" 23 "testing" 24 "unicode" 25 26 corepb "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" 27 "github.com/google/go-cmp/cmp" 28 "google.golang.org/grpc/internal/grpctest" 29 "google.golang.org/grpc/xds/internal/clients" 30 ) 31 32 const ignorePrefix = "XXX_" 33 34 type s struct { 35 grpctest.Tester 36 } 37 38 func Test(t *testing.T) { 39 grpctest.RunSubTests(t, s{}) 40 } 41 42 func ignore(name string) bool { 43 if !unicode.IsUpper([]rune(name)[0]) { 44 return true 45 } 46 return strings.HasPrefix(name, ignorePrefix) 47 } 48 49 // A reflection based test to make sure internal.Locality contains all the 50 // fields (expect for XXX_) from the proto message. 51 func (s) TestLocalityMatchProtoMessage(t *testing.T) { 52 want1 := make(map[string]string) 53 for ty, i := reflect.TypeOf(clients.Locality{}), 0; i < ty.NumField(); i++ { 54 f := ty.Field(i) 55 if ignore(f.Name) { 56 continue 57 } 58 want1[f.Name] = f.Type.Name() 59 } 60 61 want2 := make(map[string]string) 62 for ty, i := reflect.TypeOf(corepb.Locality{}), 0; i < ty.NumField(); i++ { 63 f := ty.Field(i) 64 if ignore(f.Name) { 65 continue 66 } 67 want2[f.Name] = f.Type.Name() 68 } 69 70 if diff := cmp.Diff(want1, want2); diff != "" { 71 t.Fatalf("internal type and proto message have different fields: (-got +want):\n%+v", diff) 72 } 73 } 74 75 func TestLocalityToAndFromString(t *testing.T) { 76 tests := []struct { 77 name string 78 localityID clients.Locality 79 str string 80 wantErr bool 81 }{ 82 { 83 name: "3 fields", 84 localityID: clients.Locality{Region: "r:r", Zone: "z#z", SubZone: "s^s"}, 85 str: `{region="r:r", zone="z#z", sub_zone="s^s"}`, 86 }, 87 { 88 name: "2 fields", 89 localityID: clients.Locality{Region: "r:r", Zone: "z#z"}, 90 str: `{region="r:r", zone="z#z", sub_zone=""}`, 91 }, 92 { 93 name: "1 field", 94 localityID: clients.Locality{Region: "r:r"}, 95 str: `{region="r:r", zone="", sub_zone=""}`, 96 }, 97 } 98 for _, tt := range tests { 99 t.Run(tt.name, func(t *testing.T) { 100 gotStr := LocalityString(tt.localityID) 101 if gotStr != tt.str { 102 t.Errorf("%#v.String() = %q, want %q", tt.localityID, gotStr, tt.str) 103 } 104 105 gotID, err := LocalityFromString(tt.str) 106 if (err != nil) != tt.wantErr { 107 t.Errorf("clients.LocalityFromString(%q) error = %v, wantErr %v", tt.str, err, tt.wantErr) 108 return 109 } 110 if diff := cmp.Diff(gotID, tt.localityID); diff != "" { 111 t.Errorf("clients.LocalityFromString() got = %v, want %v, diff: %s", gotID, tt.localityID, diff) 112 } 113 }) 114 } 115 }