1
18
19 package grpc
20
21 import (
22 "context"
23 "errors"
24 "fmt"
25 "net"
26 "testing"
27 "time"
28
29 "github.com/google/go-cmp/cmp"
30 "google.golang.org/grpc/credentials/insecure"
31 "google.golang.org/grpc/internal"
32 "google.golang.org/grpc/internal/testutils"
33 "google.golang.org/grpc/resolver"
34 )
35
36 func generateTarget(target string) resolver.Target {
37 return resolver.Target{URL: *testutils.MustParseURL(target)}
38 }
39
40
41 func resetInitialResolverState() {
42 resolver.SetDefaultScheme("passthrough")
43 internal.UserSetDefaultScheme = false
44 }
45
46 type testResolverForParser struct {
47 resolver.Resolver
48 }
49
50 func (testResolverForParser) Build(resolver.Target, resolver.ClientConn, resolver.BuildOptions) (resolver.Resolver, error) {
51 return testResolverForParser{}, nil
52 }
53
54 func (testResolverForParser) Close() {}
55
56 func (testResolverForParser) Scheme() string {
57 return "testresolverforparser"
58 }
59
60 func init() { resolver.Register(testResolverForParser{}) }
61
62 func (s) TestParsedTarget_Success_WithoutCustomDialer(t *testing.T) {
63 tests := []struct {
64 target string
65 wantDialParse resolver.Target
66 wantNewClientParse resolver.Target
67 wantCustomParse resolver.Target
68 }{
69
70 {
71 target: "://a/b",
72 wantDialParse: generateTarget("passthrough:///://a/b"),
73 wantNewClientParse: generateTarget("dns:///://a/b"),
74 wantCustomParse: generateTarget("testresolverforparser:///://a/b"),
75 },
76 {
77 target: "a//b",
78 wantDialParse: generateTarget("passthrough:///a//b"),
79 wantNewClientParse: generateTarget("dns:///a//b"),
80 wantCustomParse: generateTarget("testresolverforparser:///a//b"),
81 },
82
83
84 {
85 target: "a:///",
86 wantDialParse: generateTarget("passthrough:///a:///"),
87 wantNewClientParse: generateTarget("dns:///a:///"),
88 wantCustomParse: generateTarget("testresolverforparser:///a:///"),
89 },
90 {
91 target: "a:b",
92 wantDialParse: generateTarget("passthrough:///a:b"),
93 wantNewClientParse: generateTarget("dns:///a:b"),
94 wantCustomParse: generateTarget("testresolverforparser:///a:b"),
95 },
96
97
98 {
99 target: "dns://a.server.com/google.com",
100 wantDialParse: generateTarget("dns://a.server.com/google.com"),
101 wantNewClientParse: generateTarget("dns://a.server.com/google.com"),
102 wantCustomParse: generateTarget("dns://a.server.com/google.com"),
103 },
104 {
105 target: "unix-abstract:/ a///://::!@#$%25^&*()b",
106 wantDialParse: generateTarget("unix-abstract:/ a///://::!@#$%25^&*()b"),
107 wantNewClientParse: generateTarget("unix-abstract:/ a///://::!@#$%25^&*()b"),
108 wantCustomParse: generateTarget("unix-abstract:/ a///://::!@#$%25^&*()b"),
109 },
110 {
111 target: "unix-abstract:passthrough:abc",
112 wantDialParse: generateTarget("unix-abstract:passthrough:abc"),
113 wantNewClientParse: generateTarget("unix-abstract:passthrough:abc"),
114 wantCustomParse: generateTarget("unix-abstract:passthrough:abc"),
115 },
116 {
117 target: "passthrough:///unix:///a/b/c",
118 wantDialParse: generateTarget("passthrough:///unix:///a/b/c"),
119 wantNewClientParse: generateTarget("passthrough:///unix:///a/b/c"),
120 wantCustomParse: generateTarget("passthrough:///unix:///a/b/c"),
121 },
122
123
124 {
125 target: "dns:/a/b/c",
126 wantDialParse: generateTarget("dns:/a/b/c"),
127 wantNewClientParse: generateTarget("dns:/a/b/c"),
128 wantCustomParse: generateTarget("dns:/a/b/c"),
129 },
130 {
131 target: "unregistered:/a/b/c",
132 wantDialParse: generateTarget("passthrough:///unregistered:/a/b/c"),
133 wantNewClientParse: generateTarget("dns:///unregistered:/a/b/c"),
134 wantCustomParse: generateTarget("testresolverforparser:///unregistered:/a/b/c"),
135 },
136 }
137
138 for _, test := range tests {
139 t.Run(test.target, func(t *testing.T) {
140 resetInitialResolverState()
141 cc, err := Dial(test.target, WithTransportCredentials(insecure.NewCredentials()))
142 if err != nil {
143 t.Fatalf("Dial(%q) failed: %v", test.target, err)
144 }
145 cc.Close()
146
147 if !cmp.Equal(cc.parsedTarget, test.wantDialParse) {
148 t.Errorf("cc.parsedTarget for dial target %q = %+v, want %+v", test.target, cc.parsedTarget, test.wantDialParse)
149 }
150
151 cc, err = NewClient(test.target, WithTransportCredentials(insecure.NewCredentials()))
152 if err != nil {
153 t.Fatalf("NewClient(%q) failed: %v", test.target, err)
154 }
155 cc.Close()
156
157 if !cmp.Equal(cc.parsedTarget, test.wantNewClientParse) {
158 t.Errorf("cc.parsedTarget for newClient target %q = %+v, want %+v", test.target, cc.parsedTarget, test.wantNewClientParse)
159 }
160
161 resolver.SetDefaultScheme("testresolverforparser")
162 cc, err = Dial(test.target, WithTransportCredentials(insecure.NewCredentials()))
163 if err != nil {
164 t.Fatalf("Dial(%q) failed: %v", test.target, err)
165 }
166 cc.Close()
167
168 if !cmp.Equal(cc.parsedTarget, test.wantCustomParse) {
169 t.Errorf("cc.parsedTarget for dial target %q = %+v, want %+v", test.target, cc.parsedTarget, test.wantDialParse)
170 }
171
172 cc, err = NewClient(test.target, WithTransportCredentials(insecure.NewCredentials()))
173 if err != nil {
174 t.Fatalf("NewClient(%q) failed: %v", test.target, err)
175 }
176 cc.Close()
177
178 if !cmp.Equal(cc.parsedTarget, test.wantCustomParse) {
179 t.Errorf("cc.parsedTarget for newClient target %q = %+v, want %+v", test.target, cc.parsedTarget, test.wantNewClientParse)
180 }
181
182 })
183 }
184 resetInitialResolverState()
185 }
186
187 func (s) TestParsedTarget_Failure_WithoutCustomDialer(t *testing.T) {
188 targets := []string{
189 "",
190 "unix://a/b/c",
191 "unix://authority",
192 "unix-abstract://authority/a/b/c",
193 "unix-abstract://authority",
194 }
195
196 for _, target := range targets {
197 t.Run(target, func(t *testing.T) {
198 if cc, err := Dial(target, WithTransportCredentials(insecure.NewCredentials())); err == nil {
199 defer cc.Close()
200 t.Fatalf("Dial(%q) succeeded cc.parsedTarget = %+v, expected to fail", target, cc.parsedTarget)
201 }
202 })
203 }
204 }
205
206 func (s) TestParsedTarget_WithCustomDialer(t *testing.T) {
207 resetInitialResolverState()
208 defScheme := resolver.GetDefaultScheme()
209 tests := []struct {
210 target string
211 wantParsed resolver.Target
212 wantDialerAddress string
213 }{
214
215
216 {
217 target: "unix:a/b/c",
218 wantParsed: resolver.Target{URL: *testutils.MustParseURL("unix:a/b/c")},
219 wantDialerAddress: "unix:a/b/c",
220 },
221 {
222 target: "unix:/a/b/c",
223 wantParsed: resolver.Target{URL: *testutils.MustParseURL("unix:/a/b/c")},
224 wantDialerAddress: "unix:///a/b/c",
225 },
226 {
227 target: "unix:///a/b/c",
228 wantParsed: resolver.Target{URL: *testutils.MustParseURL("unix:///a/b/c")},
229 wantDialerAddress: "unix:///a/b/c",
230 },
231 {
232 target: "dns:///127.0.0.1:50051",
233 wantParsed: resolver.Target{URL: *testutils.MustParseURL("dns:///127.0.0.1:50051")},
234 wantDialerAddress: "127.0.0.1:50051",
235 },
236 {
237 target: ":///127.0.0.1:50051",
238 wantParsed: resolver.Target{URL: *testutils.MustParseURL(fmt.Sprintf("%s:///%s", defScheme, ":///127.0.0.1:50051"))},
239 wantDialerAddress: ":///127.0.0.1:50051",
240 },
241 {
242 target: "dns://authority/127.0.0.1:50051",
243 wantParsed: resolver.Target{URL: *testutils.MustParseURL("dns://authority/127.0.0.1:50051")},
244 wantDialerAddress: "127.0.0.1:50051",
245 },
246 {
247 target: "://authority/127.0.0.1:50051",
248 wantParsed: resolver.Target{URL: *testutils.MustParseURL(fmt.Sprintf("%s:///%s", defScheme, "://authority/127.0.0.1:50051"))},
249 wantDialerAddress: "://authority/127.0.0.1:50051",
250 },
251 {
252 target: "/unix/socket/address",
253 wantParsed: resolver.Target{URL: *testutils.MustParseURL(fmt.Sprintf("%s:///%s", defScheme, "/unix/socket/address"))},
254 wantDialerAddress: "/unix/socket/address",
255 },
256 {
257 target: "",
258 wantParsed: resolver.Target{URL: *testutils.MustParseURL(fmt.Sprintf("%s:///%s", defScheme, ""))},
259 wantDialerAddress: "",
260 },
261 {
262 target: "passthrough://a.server.com/google.com",
263 wantParsed: resolver.Target{URL: *testutils.MustParseURL("passthrough://a.server.com/google.com")},
264 wantDialerAddress: "google.com",
265 },
266 }
267
268 for _, test := range tests {
269 t.Run(test.target, func(t *testing.T) {
270 addrCh := make(chan string, 1)
271 dialer := func(ctx context.Context, address string) (net.Conn, error) {
272 addrCh <- address
273 return nil, errors.New("dialer error")
274 }
275
276 cc, err := Dial(test.target, WithTransportCredentials(insecure.NewCredentials()), WithContextDialer(dialer))
277 if err != nil {
278 t.Fatalf("Dial(%q) failed: %v", test.target, err)
279 }
280 defer cc.Close()
281
282 select {
283 case addr := <-addrCh:
284 if addr != test.wantDialerAddress {
285 t.Fatalf("address in custom dialer is %q, want %q", addr, test.wantDialerAddress)
286 }
287 case <-time.After(time.Second):
288 t.Fatal("timeout when waiting for custom dialer to be invoked")
289 }
290 if !cmp.Equal(cc.parsedTarget, test.wantParsed) {
291 t.Errorf("cc.parsedTarget for dial target %q = %+v, want %+v", test.target, cc.parsedTarget, test.wantParsed)
292 }
293 })
294 }
295 }
296
View as plain text