gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/grpc/clientconn_parsed_target_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 grpc 20 21 import ( 22 "context" 23 "errors" 24 "net" 25 "net/url" 26 "testing" 27 "time" 28 29 "github.com/google/go-cmp/cmp" 30 31 "gitee.com/ks-custle/core-gm/grpc/resolver" 32 ) 33 34 func (s) TestParsedTarget_Success_WithoutCustomDialer(t *testing.T) { 35 defScheme := resolver.GetDefaultScheme() 36 tests := []struct { 37 target string 38 wantParsed resolver.Target 39 }{ 40 // Target.Scheme、Target.Authority、Target.Endpoint are deprecated, use URL.Scheme、URL.Host、URL.Path instead. 41 // No scheme is specified. 42 //{target: "", wantParsed: resolver.Target{Scheme: defScheme, Authority: "", Endpoint: "", URL: url.URL{Scheme: defScheme, Path: "/"}}}, 43 {target: "", wantParsed: resolver.Target{URL: url.URL{Scheme: defScheme, Host: "", Path: "/"}}}, 44 //{target: "://", wantParsed: resolver.Target{Scheme: defScheme, Authority: "", Endpoint: "://", URL: url.URL{Scheme: defScheme, Path: "/://"}}}, 45 {target: "://", wantParsed: resolver.Target{URL: url.URL{Scheme: defScheme, Host: "", Path: "/://"}}}, 46 //{target: ":///", wantParsed: resolver.Target{Scheme: defScheme, Authority: "", Endpoint: ":///", URL: url.URL{Scheme: defScheme, Path: "/:///"}}}, 47 {target: ":///", wantParsed: resolver.Target{URL: url.URL{Scheme: defScheme, Host: "", Path: "/:///"}}}, 48 //{target: "://a/", wantParsed: resolver.Target{Scheme: defScheme, Authority: "", Endpoint: "://a/", URL: url.URL{Scheme: defScheme, Path: "/://a/"}}}, 49 {target: "://a/", wantParsed: resolver.Target{URL: url.URL{Scheme: defScheme, Path: "/://a/"}}}, 50 //{target: ":///a", wantParsed: resolver.Target{Scheme: defScheme, Authority: "", Endpoint: ":///a", URL: url.URL{Scheme: defScheme, Path: "/:///a"}}}, 51 {target: ":///a", wantParsed: resolver.Target{URL: url.URL{Scheme: defScheme, Path: "/:///a"}}}, 52 //{target: "://a/b", wantParsed: resolver.Target{Scheme: defScheme, Authority: "", Endpoint: "://a/b", URL: url.URL{Scheme: defScheme, Path: "/://a/b"}}}, 53 {target: "://a/b", wantParsed: resolver.Target{URL: url.URL{Scheme: defScheme, Path: "/://a/b"}}}, 54 //{target: "/", wantParsed: resolver.Target{Scheme: defScheme, Authority: "", Endpoint: "/", URL: url.URL{Scheme: defScheme, Path: "//"}}}, 55 {target: "/", wantParsed: resolver.Target{URL: url.URL{Scheme: defScheme, Path: "//"}}}, 56 //{target: "a/b", wantParsed: resolver.Target{Scheme: defScheme, Authority: "", Endpoint: "a/b", URL: url.URL{Scheme: defScheme, Path: "/a/b"}}}, 57 {target: "a/b", wantParsed: resolver.Target{URL: url.URL{Scheme: defScheme, Path: "/a/b"}}}, 58 //{target: "a//b", wantParsed: resolver.Target{Scheme: defScheme, Authority: "", Endpoint: "a//b", URL: url.URL{Scheme: defScheme, Path: "/a//b"}}}, 59 {target: "a//b", wantParsed: resolver.Target{URL: url.URL{Scheme: defScheme, Path: "/a//b"}}}, 60 //{target: "google.com", wantParsed: resolver.Target{Scheme: defScheme, Authority: "", Endpoint: "google.com", URL: url.URL{Scheme: defScheme, Path: "/google.com"}}}, 61 {target: "google.com", wantParsed: resolver.Target{URL: url.URL{Scheme: defScheme, Path: "/google.com"}}}, 62 //{target: "google.com/?a=b", wantParsed: resolver.Target{Scheme: defScheme, Authority: "", Endpoint: "google.com/", URL: url.URL{Scheme: defScheme, Path: "/google.com/", RawQuery: "a=b"}}}, 63 {target: "google.com/?a=b", wantParsed: resolver.Target{URL: url.URL{Scheme: defScheme, Path: "/google.com/", RawQuery: "a=b"}}}, 64 //{target: "/unix/socket/address", wantParsed: resolver.Target{Scheme: defScheme, Authority: "", Endpoint: "/unix/socket/address", URL: url.URL{Scheme: defScheme, Path: "//unix/socket/address"}}}, 65 {target: "/unix/socket/address", wantParsed: resolver.Target{URL: url.URL{Scheme: defScheme, Path: "//unix/socket/address"}}}, 66 67 // An unregistered scheme is specified. 68 //{target: "a:///", wantParsed: resolver.Target{Scheme: defScheme, Authority: "", Endpoint: "a:///", URL: url.URL{Scheme: defScheme, Path: "/a:///"}}}, 69 {target: "a:///", wantParsed: resolver.Target{URL: url.URL{Scheme: defScheme, Path: "/a:///"}}}, 70 //{target: "a://b/", wantParsed: resolver.Target{Scheme: defScheme, Authority: "", Endpoint: "a://b/", URL: url.URL{Scheme: defScheme, Path: "/a://b/"}}}, 71 {target: "a://b/", wantParsed: resolver.Target{URL: url.URL{Scheme: defScheme, Path: "/a://b/"}}}, 72 //{target: "a:///b", wantParsed: resolver.Target{Scheme: defScheme, Authority: "", Endpoint: "a:///b", URL: url.URL{Scheme: defScheme, Path: "/a:///b"}}}, 73 {target: "a:///b", wantParsed: resolver.Target{URL: url.URL{Scheme: defScheme, Path: "/a:///b"}}}, 74 //{target: "a://b/c", wantParsed: resolver.Target{Scheme: defScheme, Authority: "", Endpoint: "a://b/c", URL: url.URL{Scheme: defScheme, Path: "/a://b/c"}}}, 75 {target: "a://b/c", wantParsed: resolver.Target{URL: url.URL{Scheme: defScheme, Path: "/a://b/c"}}}, 76 //{target: "a:b", wantParsed: resolver.Target{Scheme: defScheme, Authority: "", Endpoint: "a:b", URL: url.URL{Scheme: defScheme, Path: "/a:b"}}}, 77 {target: "a:b", wantParsed: resolver.Target{URL: url.URL{Scheme: defScheme, Path: "/a:b"}}}, 78 //{target: "a:/b", wantParsed: resolver.Target{Scheme: defScheme, Authority: "", Endpoint: "a:/b", URL: url.URL{Scheme: defScheme, Path: "/a:/b"}}}, 79 {target: "a:/b", wantParsed: resolver.Target{URL: url.URL{Scheme: defScheme, Path: "/a:/b"}}}, 80 //{target: "a://b", wantParsed: resolver.Target{Scheme: defScheme, Authority: "", Endpoint: "a://b", URL: url.URL{Scheme: defScheme, Path: "/a://b"}}}, 81 {target: "a://b", wantParsed: resolver.Target{URL: url.URL{Scheme: defScheme, Path: "/a://b"}}}, 82 83 // A registered scheme is specified. 84 //{target: "dns:///google.com", wantParsed: resolver.Target{Scheme: "dns", Authority: "", Endpoint: "google.com", URL: url.URL{Scheme: "dns", Path: "/google.com"}}}, 85 {target: "dns:///google.com", wantParsed: resolver.Target{URL: url.URL{Scheme: "dns", Path: "/google.com"}}}, 86 //{target: "dns://a.server.com/google.com", wantParsed: resolver.Target{Scheme: "dns", Authority: "a.server.com", Endpoint: "google.com", URL: url.URL{Scheme: "dns", Host: "a.server.com", Path: "/google.com"}}}, 87 {target: "dns://a.server.com/google.com", wantParsed: resolver.Target{URL: url.URL{Scheme: "dns", Host: "a.server.com", Path: "/google.com"}}}, 88 //{target: "dns://a.server.com/google.com/?a=b", wantParsed: resolver.Target{Scheme: "dns", Authority: "a.server.com", Endpoint: "google.com/", URL: url.URL{Scheme: "dns", Host: "a.server.com", Path: "/google.com/", RawQuery: "a=b"}}}, 89 {target: "dns://a.server.com/google.com/?a=b", wantParsed: resolver.Target{URL: url.URL{Scheme: "dns", Host: "a.server.com", Path: "/google.com/", RawQuery: "a=b"}}}, 90 //{target: "unix:///a/b/c", wantParsed: resolver.Target{Scheme: "unix", Authority: "", Endpoint: "a/b/c", URL: url.URL{Scheme: "unix", Path: "/a/b/c"}}}, 91 {target: "unix:///a/b/c", wantParsed: resolver.Target{URL: url.URL{Scheme: "unix", Path: "/a/b/c"}}}, 92 //{target: "unix-abstract:a/b/c", wantParsed: resolver.Target{Scheme: "unix-abstract", Authority: "", Endpoint: "a/b/c", URL: url.URL{Scheme: "unix-abstract", Path: "", Opaque: "a/b/c"}}}, 93 {target: "unix-abstract:a/b/c", wantParsed: resolver.Target{URL: url.URL{Scheme: "unix-abstract", Path: "", Opaque: "a/b/c"}}}, 94 //{target: "unix-abstract:a b", wantParsed: resolver.Target{Scheme: "unix-abstract", Authority: "", Endpoint: "a b", URL: url.URL{Scheme: "unix-abstract", Path: "", Opaque: "a b"}}}, 95 {target: "unix-abstract:a b", wantParsed: resolver.Target{URL: url.URL{Scheme: "unix-abstract", Path: "", Opaque: "a b"}}}, 96 //{target: "unix-abstract:a:b", wantParsed: resolver.Target{Scheme: "unix-abstract", Authority: "", Endpoint: "a:b", URL: url.URL{Scheme: "unix-abstract", Path: "", Opaque: "a:b"}}}, 97 {target: "unix-abstract:a:b", wantParsed: resolver.Target{URL: url.URL{Scheme: "unix-abstract", Path: "", Opaque: "a:b"}}}, 98 //{target: "unix-abstract:a-b", wantParsed: resolver.Target{Scheme: "unix-abstract", Authority: "", Endpoint: "a-b", URL: url.URL{Scheme: "unix-abstract", Path: "", Opaque: "a-b"}}}, 99 {target: "unix-abstract:a-b", wantParsed: resolver.Target{URL: url.URL{Scheme: "unix-abstract", Path: "", Opaque: "a-b"}}}, 100 //{target: "unix-abstract:/ a///://::!@#$%25^&*()b", wantParsed: resolver.Target{Scheme: "unix-abstract", Authority: "", Endpoint: " a///://::!@", URL: url.URL{Scheme: "unix-abstract", Path: "/ a///://::!@", RawPath: "/ a///://::!@", Fragment: "$%^&*()b", RawFragment: "$%25^&*()b"}}}, 101 {target: "unix-abstract:/ a///://::!@#$%25^&*()b", wantParsed: resolver.Target{URL: url.URL{Scheme: "unix-abstract", Path: "/ a///://::!@", RawPath: "/ a///://::!@", Fragment: "$%^&*()b", RawFragment: "$%25^&*()b"}}}, 102 //{target: "unix-abstract:passthrough:abc", wantParsed: resolver.Target{Scheme: "unix-abstract", Authority: "", Endpoint: "passthrough:abc", URL: url.URL{Scheme: "unix-abstract", Path: "", Opaque: "passthrough:abc"}}}, 103 {target: "unix-abstract:passthrough:abc", wantParsed: resolver.Target{URL: url.URL{Scheme: "unix-abstract", Path: "", Opaque: "passthrough:abc"}}}, 104 //{target: "unix-abstract:unix:///abc", wantParsed: resolver.Target{Scheme: "unix-abstract", Authority: "", Endpoint: "unix:///abc", URL: url.URL{Scheme: "unix-abstract", Path: "", Opaque: "unix:///abc"}}}, 105 {target: "unix-abstract:unix:///abc", wantParsed: resolver.Target{URL: url.URL{Scheme: "unix-abstract", Path: "", Opaque: "unix:///abc"}}}, 106 //{target: "unix-abstract:///a/b/c", wantParsed: resolver.Target{Scheme: "unix-abstract", Authority: "", Endpoint: "a/b/c", URL: url.URL{Scheme: "unix-abstract", Path: "/a/b/c"}}}, 107 {target: "unix-abstract:///a/b/c", wantParsed: resolver.Target{URL: url.URL{Scheme: "unix-abstract", Path: "/a/b/c"}}}, 108 //{target: "unix-abstract:///", wantParsed: resolver.Target{Scheme: "unix-abstract", Authority: "", Endpoint: "", URL: url.URL{Scheme: "unix-abstract", Path: "/"}}}, 109 {target: "unix-abstract:///", wantParsed: resolver.Target{URL: url.URL{Scheme: "unix-abstract", Path: "/"}}}, 110 //{target: "passthrough:///unix:///a/b/c", wantParsed: resolver.Target{Scheme: "passthrough", Authority: "", Endpoint: "unix:///a/b/c", URL: url.URL{Scheme: "passthrough", Path: "/unix:///a/b/c"}}}, 111 {target: "passthrough:///unix:///a/b/c", wantParsed: resolver.Target{URL: url.URL{Scheme: "passthrough", Path: "/unix:///a/b/c"}}}, 112 113 // Cases for `scheme:absolute-path`. 114 //{target: "dns:/a/b/c", wantParsed: resolver.Target{Scheme: "dns", Authority: "", Endpoint: "a/b/c", URL: url.URL{Scheme: "dns", Path: "/a/b/c"}}}, 115 {target: "dns:/a/b/c", wantParsed: resolver.Target{URL: url.URL{Scheme: "dns", Path: "/a/b/c"}}}, 116 //{target: "unregistered:/a/b/c", wantParsed: resolver.Target{Scheme: defScheme, Authority: "", Endpoint: "unregistered:/a/b/c", URL: url.URL{Scheme: defScheme, Path: "/unregistered:/a/b/c"}}}, 117 {target: "unregistered:/a/b/c", wantParsed: resolver.Target{URL: url.URL{Scheme: defScheme, Path: "/unregistered:/a/b/c"}}}, 118 } 119 120 for _, test := range tests { 121 t.Run(test.target, func(t *testing.T) { 122 cc, err := Dial(test.target, WithInsecure()) 123 if err != nil { 124 t.Fatalf("Dial(%q) failed: %v", test.target, err) 125 } 126 defer cc.Close() 127 128 if !cmp.Equal(cc.parsedTarget, test.wantParsed) { 129 t.Errorf("cc.parsedTarget for dial target %q = %+v, want %+v", test.target, cc.parsedTarget, test.wantParsed) 130 } 131 }) 132 } 133 } 134 135 func (s) TestParsedTarget_Failure_WithoutCustomDialer(t *testing.T) { 136 targets := []string{ 137 "unix://a/b/c", 138 "unix://authority", 139 "unix-abstract://authority/a/b/c", 140 "unix-abstract://authority", 141 } 142 143 for _, target := range targets { 144 t.Run(target, func(t *testing.T) { 145 if cc, err := Dial(target, WithInsecure()); err == nil { 146 defer cc.Close() 147 t.Fatalf("Dial(%q) succeeded cc.parsedTarget = %+v, expected to fail", target, cc.parsedTarget) 148 } 149 }) 150 } 151 } 152 153 func (s) TestParsedTarget_WithCustomDialer(t *testing.T) { 154 defScheme := resolver.GetDefaultScheme() 155 tests := []struct { 156 target string 157 wantParsed resolver.Target 158 wantDialerAddress string 159 }{ 160 // Target.Scheme、Target.Authority、Target.Endpoint are deprecated, use URL.Scheme、URL.Host、URL.Path instead. 161 // unix:[local_path], unix:[/absolute], and unix://[/absolute] have 162 // different behaviors with a custom dialer. 163 { 164 target: "unix:a/b/c", 165 //wantParsed: resolver.Target{Scheme: "unix", Authority: "", Endpoint: "a/b/c", URL: url.URL{Scheme: "unix", Opaque: "a/b/c"}}, 166 wantParsed: resolver.Target{URL: url.URL{Scheme: "unix", Opaque: "a/b/c"}}, 167 wantDialerAddress: "unix:a/b/c", 168 }, 169 { 170 target: "unix:/a/b/c", 171 //wantParsed: resolver.Target{Scheme: "unix", Authority: "", Endpoint: "a/b/c", URL: url.URL{Scheme: "unix", Path: "/a/b/c"}}, 172 wantParsed: resolver.Target{URL: url.URL{Scheme: "unix", Path: "/a/b/c"}}, 173 wantDialerAddress: "unix:///a/b/c", 174 }, 175 { 176 target: "unix:///a/b/c", 177 //wantParsed: resolver.Target{Scheme: "unix", Authority: "", Endpoint: "a/b/c", URL: url.URL{Scheme: "unix", Path: "/a/b/c"}}, 178 wantParsed: resolver.Target{URL: url.URL{Scheme: "unix", Path: "/a/b/c"}}, 179 wantDialerAddress: "unix:///a/b/c", 180 }, 181 { 182 target: "dns:///127.0.0.1:50051", 183 //wantParsed: resolver.Target{Scheme: "dns", Authority: "", Endpoint: "127.0.0.1:50051", URL: url.URL{Scheme: "dns", Path: "/127.0.0.1:50051"}}, 184 wantParsed: resolver.Target{URL: url.URL{Scheme: "dns", Path: "/127.0.0.1:50051"}}, 185 wantDialerAddress: "127.0.0.1:50051", 186 }, 187 { 188 target: ":///127.0.0.1:50051", 189 //wantParsed: resolver.Target{Scheme: defScheme, Authority: "", Endpoint: ":///127.0.0.1:50051", URL: url.URL{Scheme: defScheme, Path: "/:///127.0.0.1:50051"}}, 190 wantParsed: resolver.Target{URL: url.URL{Scheme: defScheme, Path: "/:///127.0.0.1:50051"}}, 191 wantDialerAddress: ":///127.0.0.1:50051", 192 }, 193 { 194 target: "dns://authority/127.0.0.1:50051", 195 //wantParsed: resolver.Target{Scheme: "dns", Authority: "authority", Endpoint: "127.0.0.1:50051", URL: url.URL{Scheme: "dns", Host: "authority", Path: "/127.0.0.1:50051"}}, 196 wantParsed: resolver.Target{URL: url.URL{Scheme: "dns", Host: "authority", Path: "/127.0.0.1:50051"}}, 197 wantDialerAddress: "127.0.0.1:50051", 198 }, 199 { 200 target: "://authority/127.0.0.1:50051", 201 //wantParsed: resolver.Target{Scheme: defScheme, Authority: "", Endpoint: "://authority/127.0.0.1:50051", URL: url.URL{Scheme: defScheme, Path: "/://authority/127.0.0.1:50051"}}, 202 wantParsed: resolver.Target{URL: url.URL{Scheme: defScheme, Path: "/://authority/127.0.0.1:50051"}}, 203 wantDialerAddress: "://authority/127.0.0.1:50051", 204 }, 205 { 206 target: "/unix/socket/address", 207 //wantParsed: resolver.Target{Scheme: defScheme, Authority: "", Endpoint: "/unix/socket/address", URL: url.URL{Scheme: defScheme, Path: "//unix/socket/address"}}, 208 wantParsed: resolver.Target{URL: url.URL{Scheme: defScheme, Path: "//unix/socket/address"}}, 209 wantDialerAddress: "/unix/socket/address", 210 }, 211 { 212 target: "passthrough://a.server.com/google.com", 213 //wantParsed: resolver.Target{Scheme: "passthrough", Authority: "a.server.com", Endpoint: "google.com", URL: url.URL{Scheme: "passthrough", Host: "a.server.com", Path: "/google.com"}}, 214 wantParsed: resolver.Target{URL: url.URL{Scheme: "passthrough", Host: "a.server.com", Path: "/google.com"}}, 215 wantDialerAddress: "google.com", 216 }, 217 } 218 219 for _, test := range tests { 220 t.Run(test.target, func(t *testing.T) { 221 addrCh := make(chan string, 1) 222 dialer := func(ctx context.Context, address string) (net.Conn, error) { 223 addrCh <- address 224 return nil, errors.New("dialer error") 225 } 226 227 cc, err := Dial(test.target, WithInsecure(), WithContextDialer(dialer)) 228 if err != nil { 229 t.Fatalf("Dial(%q) failed: %v", test.target, err) 230 } 231 defer cc.Close() 232 233 select { 234 case addr := <-addrCh: 235 if addr != test.wantDialerAddress { 236 t.Fatalf("address in custom dialer is %q, want %q", addr, test.wantDialerAddress) 237 } 238 case <-time.After(time.Second): 239 t.Fatal("timeout when waiting for custom dialer to be invoked") 240 } 241 if !cmp.Equal(cc.parsedTarget, test.wantParsed) { 242 t.Errorf("cc.parsedTarget for dial target %q = %+v, want %+v", test.target, cc.parsedTarget, test.wantParsed) 243 } 244 }) 245 } 246 }