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 19package v2 20 21import ( 22 "testing" 23 "time" 24 25 v2xdspb "github.com/envoyproxy/go-control-plane/envoy/api/v2" 26 "github.com/golang/protobuf/ptypes" 27 anypb "github.com/golang/protobuf/ptypes/any" 28 "google.golang.org/grpc/xds/internal" 29 xdsclient "google.golang.org/grpc/xds/internal/client" 30 "google.golang.org/grpc/xds/internal/testutils" 31 "google.golang.org/grpc/xds/internal/version" 32) 33 34var ( 35 badlyMarshaledEDSResponse = &v2xdspb.DiscoveryResponse{ 36 Resources: []*anypb.Any{ 37 { 38 TypeUrl: version.V2EndpointsURL, 39 Value: []byte{1, 2, 3, 4}, 40 }, 41 }, 42 TypeUrl: version.V2EndpointsURL, 43 } 44 badResourceTypeInEDSResponse = &v2xdspb.DiscoveryResponse{ 45 Resources: []*anypb.Any{ 46 { 47 TypeUrl: httpConnManagerURL, 48 Value: marshaledConnMgr1, 49 }, 50 }, 51 TypeUrl: version.V2EndpointsURL, 52 } 53 marshaledGoodCLA1 = func() *anypb.Any { 54 clab0 := testutils.NewClusterLoadAssignmentBuilder(goodEDSName, nil) 55 clab0.AddLocality("locality-1", 1, 1, []string{"addr1:314"}, nil) 56 clab0.AddLocality("locality-2", 1, 0, []string{"addr2:159"}, nil) 57 a, _ := ptypes.MarshalAny(clab0.Build()) 58 return a 59 }() 60 goodEDSResponse1 = &v2xdspb.DiscoveryResponse{ 61 Resources: []*anypb.Any{ 62 marshaledGoodCLA1, 63 }, 64 TypeUrl: version.V2EndpointsURL, 65 } 66 marshaledGoodCLA2 = func() *anypb.Any { 67 clab0 := testutils.NewClusterLoadAssignmentBuilder("not-goodEDSName", nil) 68 clab0.AddLocality("locality-1", 1, 0, []string{"addr1:314"}, nil) 69 a, _ := ptypes.MarshalAny(clab0.Build()) 70 return a 71 }() 72 goodEDSResponse2 = &v2xdspb.DiscoveryResponse{ 73 Resources: []*anypb.Any{ 74 marshaledGoodCLA2, 75 }, 76 TypeUrl: version.V2EndpointsURL, 77 } 78) 79 80func (s) TestEDSHandleResponse(t *testing.T) { 81 tests := []struct { 82 name string 83 edsResponse *v2xdspb.DiscoveryResponse 84 wantErr bool 85 wantUpdate map[string]xdsclient.EndpointsUpdate 86 wantUpdateMD xdsclient.UpdateMetadata 87 wantUpdateErr bool 88 }{ 89 // Any in resource is badly marshaled. 90 { 91 name: "badly-marshaled_response", 92 edsResponse: badlyMarshaledEDSResponse, 93 wantErr: true, 94 wantUpdate: nil, 95 wantUpdateMD: xdsclient.UpdateMetadata{ 96 Status: xdsclient.ServiceStatusNACKed, 97 ErrState: &xdsclient.UpdateErrorMetadata{ 98 Err: errPlaceHolder, 99 }, 100 }, 101 wantUpdateErr: false, 102 }, 103 // Response doesn't contain resource with the right type. 104 { 105 name: "no-config-in-response", 106 edsResponse: badResourceTypeInEDSResponse, 107 wantErr: true, 108 wantUpdate: nil, 109 wantUpdateMD: xdsclient.UpdateMetadata{ 110 Status: xdsclient.ServiceStatusNACKed, 111 ErrState: &xdsclient.UpdateErrorMetadata{ 112 Err: errPlaceHolder, 113 }, 114 }, 115 wantUpdateErr: false, 116 }, 117 // Response contains one uninteresting ClusterLoadAssignment. 118 { 119 name: "one-uninterestring-assignment", 120 edsResponse: goodEDSResponse2, 121 wantErr: false, 122 wantUpdate: map[string]xdsclient.EndpointsUpdate{ 123 "not-goodEDSName": { 124 Localities: []xdsclient.Locality{ 125 { 126 Endpoints: []xdsclient.Endpoint{{Address: "addr1:314"}}, 127 ID: internal.LocalityID{SubZone: "locality-1"}, 128 Priority: 0, 129 Weight: 1, 130 }, 131 }, 132 Raw: marshaledGoodCLA2, 133 }, 134 }, 135 wantUpdateMD: xdsclient.UpdateMetadata{ 136 Status: xdsclient.ServiceStatusACKed, 137 }, 138 wantUpdateErr: false, 139 }, 140 // Response contains one good ClusterLoadAssignment. 141 { 142 name: "one-good-assignment", 143 edsResponse: goodEDSResponse1, 144 wantErr: false, 145 wantUpdate: map[string]xdsclient.EndpointsUpdate{ 146 goodEDSName: { 147 Localities: []xdsclient.Locality{ 148 { 149 Endpoints: []xdsclient.Endpoint{{Address: "addr1:314"}}, 150 ID: internal.LocalityID{SubZone: "locality-1"}, 151 Priority: 1, 152 Weight: 1, 153 }, 154 { 155 Endpoints: []xdsclient.Endpoint{{Address: "addr2:159"}}, 156 ID: internal.LocalityID{SubZone: "locality-2"}, 157 Priority: 0, 158 Weight: 1, 159 }, 160 }, 161 Raw: marshaledGoodCLA1, 162 }, 163 }, 164 wantUpdateMD: xdsclient.UpdateMetadata{ 165 Status: xdsclient.ServiceStatusACKed, 166 }, 167 wantUpdateErr: false, 168 }, 169 } 170 for _, test := range tests { 171 t.Run(test.name, func(t *testing.T) { 172 testWatchHandle(t, &watchHandleTestcase{ 173 rType: xdsclient.EndpointsResource, 174 resourceName: goodEDSName, 175 responseToHandle: test.edsResponse, 176 wantHandleErr: test.wantErr, 177 wantUpdate: test.wantUpdate, 178 wantUpdateMD: test.wantUpdateMD, 179 wantUpdateErr: test.wantUpdateErr, 180 }) 181 }) 182 } 183} 184 185// TestEDSHandleResponseWithoutWatch tests the case where the v2Client 186// receives an EDS response without a registered EDS watcher. 187func (s) TestEDSHandleResponseWithoutWatch(t *testing.T) { 188 _, cc, cleanup := startServerAndGetCC(t) 189 defer cleanup() 190 191 v2c, err := newV2Client(&testUpdateReceiver{ 192 f: func(xdsclient.ResourceType, map[string]interface{}, xdsclient.UpdateMetadata) {}, 193 }, cc, goodNodeProto, func(int) time.Duration { return 0 }, nil) 194 if err != nil { 195 t.Fatal(err) 196 } 197 defer v2c.Close() 198 199 if v2c.handleEDSResponse(badResourceTypeInEDSResponse) == nil { 200 t.Fatal("v2c.handleEDSResponse() succeeded, should have failed") 201 } 202 203 if v2c.handleEDSResponse(goodEDSResponse1) != nil { 204 t.Fatal("v2c.handleEDSResponse() succeeded, should have failed") 205 } 206} 207