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  }