github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/xds/googledirectpath/googlec2p_test.go (about) 1 /* 2 * 3 * Copyright 2021 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 19 package googledirectpath 20 21 import ( 22 "strconv" 23 "testing" 24 "time" 25 26 "github.com/google/go-cmp/cmp" 27 "github.com/google/go-cmp/cmp/cmpopts" 28 grpc "github.com/hxx258456/ccgo/grpc" 29 "github.com/hxx258456/ccgo/grpc/internal/envconfig" 30 "github.com/hxx258456/ccgo/grpc/resolver" 31 "github.com/hxx258456/ccgo/grpc/xds/internal/xdsclient" 32 "github.com/hxx258456/ccgo/grpc/xds/internal/xdsclient/bootstrap" 33 "github.com/hxx258456/ccgo/grpc/xds/internal/xdsclient/xdsresource/version" 34 "google.golang.org/protobuf/testing/protocmp" 35 "google.golang.org/protobuf/types/known/structpb" 36 37 v3corepb "github.com/hxx258456/ccgo/go-control-plane/envoy/config/core/v3" 38 ) 39 40 type emptyResolver struct { 41 resolver.Resolver 42 scheme string 43 } 44 45 func (er *emptyResolver) Build(_ resolver.Target, _ resolver.ClientConn, _ resolver.BuildOptions) (resolver.Resolver, error) { 46 return er, nil 47 } 48 49 func (er *emptyResolver) Scheme() string { 50 return er.scheme 51 } 52 53 func (er *emptyResolver) Close() {} 54 55 var ( 56 testDNSResolver = &emptyResolver{scheme: "dns"} 57 testXDSResolver = &emptyResolver{scheme: "xds"} 58 ) 59 60 func replaceResolvers() func() { 61 var registerForTesting bool 62 if resolver.Get(c2pScheme) == nil { 63 // If env var to enable c2p is not set, the resolver isn't registered. 64 // Need to register and unregister in defer. 65 registerForTesting = true 66 resolver.Register(&c2pResolverBuilder{}) 67 } 68 oldDNS := resolver.Get("dns") 69 resolver.Register(testDNSResolver) 70 oldXDS := resolver.Get("xds") 71 resolver.Register(testXDSResolver) 72 return func() { 73 if oldDNS != nil { 74 resolver.Register(oldDNS) 75 } else { 76 resolver.UnregisterForTesting("dns") 77 } 78 if oldXDS != nil { 79 resolver.Register(oldXDS) 80 } else { 81 resolver.UnregisterForTesting("xds") 82 } 83 if registerForTesting { 84 resolver.UnregisterForTesting(c2pScheme) 85 } 86 } 87 } 88 89 // Test that when bootstrap env is set, fallback to DNS. 90 func TestBuildWithBootstrapEnvSet(t *testing.T) { 91 defer replaceResolvers()() 92 builder := resolver.Get(c2pScheme) 93 94 for i, envP := range []*string{&envconfig.XDSBootstrapFileName, &envconfig.XDSBootstrapFileContent} { 95 t.Run(strconv.Itoa(i), func(t *testing.T) { 96 // Set bootstrap config env var. 97 oldEnv := *envP 98 *envP = "does not matter" 99 defer func() { *envP = oldEnv }() 100 101 // Build should return DNS, not xDS. 102 r, err := builder.Build(resolver.Target{}, nil, resolver.BuildOptions{}) 103 if err != nil { 104 t.Fatalf("failed to build resolver: %v", err) 105 } 106 if r != testDNSResolver { 107 t.Fatalf("want dns resolver, got %#v", r) 108 } 109 }) 110 } 111 } 112 113 // Test that when not on GCE, fallback to DNS. 114 func TestBuildNotOnGCE(t *testing.T) { 115 defer replaceResolvers()() 116 builder := resolver.Get(c2pScheme) 117 118 oldOnGCE := onGCE 119 onGCE = func() bool { return false } 120 defer func() { onGCE = oldOnGCE }() 121 122 // Build should return DNS, not xDS. 123 r, err := builder.Build(resolver.Target{}, nil, resolver.BuildOptions{}) 124 if err != nil { 125 t.Fatalf("failed to build resolver: %v", err) 126 } 127 if r != testDNSResolver { 128 t.Fatalf("want dns resolver, got %#v", r) 129 } 130 } 131 132 type testXDSClient struct { 133 xdsclient.XDSClient 134 closed chan struct{} 135 } 136 137 func (c *testXDSClient) Close() { 138 c.closed <- struct{}{} 139 } 140 141 // Test that when xDS is built, the client is built with the correct config. 142 func TestBuildXDS(t *testing.T) { 143 defer replaceResolvers()() 144 builder := resolver.Get(c2pScheme) 145 146 oldOnGCE := onGCE 147 onGCE = func() bool { return true } 148 defer func() { onGCE = oldOnGCE }() 149 150 const testZone = "test-zone" 151 oldGetZone := getZone 152 getZone = func(time.Duration) string { return testZone } 153 defer func() { getZone = oldGetZone }() 154 155 for _, tt := range []struct { 156 name string 157 ipv6 bool 158 tdURI string // traffic director URI will be overridden if this is set. 159 }{ 160 {name: "ipv6 true", ipv6: true}, 161 {name: "ipv6 false", ipv6: false}, 162 {name: "override TD URI", ipv6: true, tdURI: "test-uri"}, 163 } { 164 t.Run(tt.name, func(t *testing.T) { 165 oldGetIPv6Capability := getIPv6Capable 166 getIPv6Capable = func(time.Duration) bool { return tt.ipv6 } 167 defer func() { getIPv6Capable = oldGetIPv6Capability }() 168 169 if tt.tdURI != "" { 170 oldURI := envconfig.C2PResolverTestOnlyTrafficDirectorURI 171 envconfig.C2PResolverTestOnlyTrafficDirectorURI = tt.tdURI 172 defer func() { 173 envconfig.C2PResolverTestOnlyTrafficDirectorURI = oldURI 174 }() 175 } 176 177 tXDSClient := &testXDSClient{closed: make(chan struct{}, 1)} 178 179 configCh := make(chan *bootstrap.Config, 1) 180 oldNewClient := newClientWithConfig 181 newClientWithConfig = func(config *bootstrap.Config) (xdsclient.XDSClient, error) { 182 configCh <- config 183 return tXDSClient, nil 184 } 185 defer func() { newClientWithConfig = oldNewClient }() 186 187 // Build should return DNS, not xDS. 188 r, err := builder.Build(resolver.Target{}, nil, resolver.BuildOptions{}) 189 if err != nil { 190 t.Fatalf("failed to build resolver: %v", err) 191 } 192 rr := r.(*c2pResolver) 193 if rrr := rr.Resolver; rrr != testXDSResolver { 194 t.Fatalf("want xds resolver, got %#v, ", rrr) 195 } 196 197 wantNode := &v3corepb.Node{ 198 Id: id, 199 Metadata: nil, 200 Locality: &v3corepb.Locality{Zone: testZone}, 201 UserAgentName: gRPCUserAgentName, 202 UserAgentVersionType: &v3corepb.Node_UserAgentVersion{UserAgentVersion: grpc.Version}, 203 ClientFeatures: []string{clientFeatureNoOverprovisioning}, 204 } 205 if tt.ipv6 { 206 wantNode.Metadata = &structpb.Struct{ 207 Fields: map[string]*structpb.Value{ 208 ipv6CapableMetadataName: { 209 Kind: &structpb.Value_BoolValue{BoolValue: true}, 210 }, 211 }, 212 } 213 } 214 wantConfig := &bootstrap.Config{ 215 XDSServer: &bootstrap.ServerConfig{ 216 ServerURI: tdURL, 217 TransportAPI: version.TransportV3, 218 NodeProto: wantNode, 219 }, 220 ClientDefaultListenerResourceNameTemplate: "%s", 221 } 222 if tt.tdURI != "" { 223 wantConfig.XDSServer.ServerURI = tt.tdURI 224 } 225 cmpOpts := cmp.Options{ 226 cmpopts.IgnoreFields(bootstrap.ServerConfig{}, "Creds"), 227 cmp.AllowUnexported(bootstrap.ServerConfig{}), 228 protocmp.Transform(), 229 } 230 select { 231 case c := <-configCh: 232 if diff := cmp.Diff(c, wantConfig, cmpOpts); diff != "" { 233 t.Fatalf("%v", diff) 234 } 235 case <-time.After(time.Second): 236 t.Fatalf("timeout waiting for client config") 237 } 238 239 r.Close() 240 select { 241 case <-tXDSClient.closed: 242 case <-time.After(time.Second): 243 t.Fatalf("timeout waiting for client close") 244 } 245 }) 246 } 247 }