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  }