github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/internal/resolver/config_selector_test.go (about)

     1  /*
     2   *
     3   * Copyright 2020 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 resolver
    20  
    21  import (
    22  	"testing"
    23  	"time"
    24  
    25  	"github.com/google/go-cmp/cmp"
    26  	"github.com/hxx258456/ccgo/grpc/internal/grpctest"
    27  	"github.com/hxx258456/ccgo/grpc/internal/serviceconfig"
    28  )
    29  
    30  type s struct {
    31  	grpctest.Tester
    32  }
    33  
    34  func Test(t *testing.T) {
    35  	grpctest.RunSubTests(t, s{})
    36  }
    37  
    38  type fakeConfigSelector struct {
    39  	selectConfig func(RPCInfo) (*RPCConfig, error)
    40  }
    41  
    42  func (f *fakeConfigSelector) SelectConfig(r RPCInfo) (*RPCConfig, error) {
    43  	return f.selectConfig(r)
    44  }
    45  
    46  func (s) TestSafeConfigSelector(t *testing.T) {
    47  	testRPCInfo := RPCInfo{Method: "test method"}
    48  
    49  	retChan1 := make(chan *RPCConfig)
    50  	retChan2 := make(chan *RPCConfig)
    51  	defer close(retChan1)
    52  	defer close(retChan2)
    53  
    54  	one := 1
    55  	two := 2
    56  
    57  	resp1 := &RPCConfig{MethodConfig: serviceconfig.MethodConfig{MaxReqSize: &one}}
    58  	resp2 := &RPCConfig{MethodConfig: serviceconfig.MethodConfig{MaxReqSize: &two}}
    59  
    60  	cs1Called := make(chan struct{}, 1)
    61  	cs2Called := make(chan struct{}, 1)
    62  
    63  	cs1 := &fakeConfigSelector{
    64  		selectConfig: func(r RPCInfo) (*RPCConfig, error) {
    65  			cs1Called <- struct{}{}
    66  			if diff := cmp.Diff(r, testRPCInfo); diff != "" {
    67  				t.Errorf("SelectConfig(%v) called; want %v\n  Diffs:\n%s", r, testRPCInfo, diff)
    68  			}
    69  			return <-retChan1, nil
    70  		},
    71  	}
    72  	cs2 := &fakeConfigSelector{
    73  		selectConfig: func(r RPCInfo) (*RPCConfig, error) {
    74  			cs2Called <- struct{}{}
    75  			if diff := cmp.Diff(r, testRPCInfo); diff != "" {
    76  				t.Errorf("SelectConfig(%v) called; want %v\n  Diffs:\n%s", r, testRPCInfo, diff)
    77  			}
    78  			return <-retChan2, nil
    79  		},
    80  	}
    81  
    82  	scs := &SafeConfigSelector{}
    83  	scs.UpdateConfigSelector(cs1)
    84  
    85  	cs1Returned := make(chan struct{})
    86  	go func() {
    87  		got, err := scs.SelectConfig(testRPCInfo) // blocks until send to retChan1
    88  		if err != nil || got != resp1 {
    89  			t.Errorf("SelectConfig(%v) = %v, %v; want %v, nil", testRPCInfo, got, err, resp1)
    90  		}
    91  		close(cs1Returned)
    92  	}()
    93  
    94  	// cs1 is blocked but should be called
    95  	select {
    96  	case <-time.After(500 * time.Millisecond):
    97  		t.Fatalf("timed out waiting for cs1 to be called")
    98  	case <-cs1Called:
    99  	}
   100  
   101  	// swap in cs2 now that cs1 is called
   102  	csSwapped := make(chan struct{})
   103  	go func() {
   104  		// wait awhile first to ensure cs1 could be called below.
   105  		time.Sleep(50 * time.Millisecond)
   106  		scs.UpdateConfigSelector(cs2) // Blocks until cs1 done
   107  		close(csSwapped)
   108  	}()
   109  
   110  	// Allow cs1 to return and cs2 to eventually be swapped in.
   111  	retChan1 <- resp1
   112  
   113  	cs1Done := false // set when cs2 is first called
   114  	for dl := time.Now().Add(150 * time.Millisecond); !time.Now().After(dl); {
   115  		gotConfigChan := make(chan *RPCConfig, 1)
   116  		go func() {
   117  			cfg, _ := scs.SelectConfig(testRPCInfo)
   118  			gotConfigChan <- cfg
   119  		}()
   120  		select {
   121  		case <-time.After(500 * time.Millisecond):
   122  			t.Fatalf("timed out waiting for cs1 or cs2 to be called")
   123  		case <-cs1Called:
   124  			// Initially, before swapping to cs2, cs1 should be called
   125  			retChan1 <- resp1
   126  			go func() { <-gotConfigChan }()
   127  			if cs1Done {
   128  				t.Fatalf("cs1 called after cs2")
   129  			}
   130  		case <-cs2Called:
   131  			// Success! the new config selector is being called
   132  			if !cs1Done {
   133  				select {
   134  				case <-csSwapped:
   135  				case <-time.After(50 * time.Millisecond):
   136  					t.Fatalf("timed out waiting for UpdateConfigSelector to return")
   137  				}
   138  				select {
   139  				case <-cs1Returned:
   140  				case <-time.After(50 * time.Millisecond):
   141  					t.Fatalf("timed out waiting for cs1 to return")
   142  				}
   143  				cs1Done = true
   144  			}
   145  			retChan2 <- resp2
   146  			got := <-gotConfigChan
   147  			if diff := cmp.Diff(got, resp2); diff != "" {
   148  				t.Fatalf("SelectConfig(%v) = %v; want %v\n  Diffs:\n%s", testRPCInfo, got, resp2, diff)
   149  			}
   150  		}
   151  		time.Sleep(10 * time.Millisecond)
   152  	}
   153  	if !cs1Done {
   154  		t.Fatalf("timed out waiting for cs2 to be called")
   155  	}
   156  }