...

Source file src/google.golang.org/grpc/clientconn_parsed_target_test.go

Documentation: google.golang.org/grpc

     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  	"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  // Resets the default scheme as though it was never set by the user.
    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  		// No scheme is specified.
    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  		// An unregistered scheme is specified.
    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  		// A registered scheme is specified.
    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  		// Cases for `scheme:absolute-path`.
   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  		// unix:[local_path], unix:[/absolute], and unix://[/absolute] have
   215  		// different behaviors with a custom dialer.
   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