github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/balancer/grpclb/grpclb_util_test.go (about)

     1  /*
     2   *
     3   * Copyright 2018 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 grpclb
    20  
    21  import (
    22  	"fmt"
    23  	"sync"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/hxx258456/ccgo/grpc/balancer"
    28  	"github.com/hxx258456/ccgo/grpc/resolver"
    29  )
    30  
    31  type mockSubConn struct {
    32  	balancer.SubConn
    33  }
    34  
    35  type mockClientConn struct {
    36  	balancer.ClientConn
    37  
    38  	mu       sync.Mutex
    39  	subConns map[balancer.SubConn]resolver.Address
    40  }
    41  
    42  func newMockClientConn() *mockClientConn {
    43  	return &mockClientConn{
    44  		subConns: make(map[balancer.SubConn]resolver.Address),
    45  	}
    46  }
    47  
    48  func (mcc *mockClientConn) NewSubConn(addrs []resolver.Address, opts balancer.NewSubConnOptions) (balancer.SubConn, error) {
    49  	sc := &mockSubConn{}
    50  	mcc.mu.Lock()
    51  	defer mcc.mu.Unlock()
    52  	mcc.subConns[sc] = addrs[0]
    53  	return sc, nil
    54  }
    55  
    56  func (mcc *mockClientConn) RemoveSubConn(sc balancer.SubConn) {
    57  	mcc.mu.Lock()
    58  	defer mcc.mu.Unlock()
    59  	delete(mcc.subConns, sc)
    60  }
    61  
    62  const testCacheTimeout = 100 * time.Millisecond
    63  
    64  func checkMockCC(mcc *mockClientConn, scLen int) error {
    65  	mcc.mu.Lock()
    66  	defer mcc.mu.Unlock()
    67  	if len(mcc.subConns) != scLen {
    68  		return fmt.Errorf("mcc = %+v, want len(mcc.subConns) = %v", mcc.subConns, scLen)
    69  	}
    70  	return nil
    71  }
    72  
    73  func checkCacheCC(ccc *lbCacheClientConn, sccLen, sctaLen int) error {
    74  	ccc.mu.Lock()
    75  	defer ccc.mu.Unlock()
    76  	if len(ccc.subConnCache) != sccLen {
    77  		return fmt.Errorf("ccc = %+v, want len(ccc.subConnCache) = %v", ccc.subConnCache, sccLen)
    78  	}
    79  	if len(ccc.subConnToAddr) != sctaLen {
    80  		return fmt.Errorf("ccc = %+v, want len(ccc.subConnToAddr) = %v", ccc.subConnToAddr, sctaLen)
    81  	}
    82  	return nil
    83  }
    84  
    85  // Test that SubConn won't be immediately removed.
    86  func (s) TestLBCacheClientConnExpire(t *testing.T) {
    87  	mcc := newMockClientConn()
    88  	if err := checkMockCC(mcc, 0); err != nil {
    89  		t.Fatal(err)
    90  	}
    91  
    92  	ccc := newLBCacheClientConn(mcc)
    93  	ccc.timeout = testCacheTimeout
    94  	if err := checkCacheCC(ccc, 0, 0); err != nil {
    95  		t.Fatal(err)
    96  	}
    97  
    98  	sc, _ := ccc.NewSubConn([]resolver.Address{{Addr: "address1"}}, balancer.NewSubConnOptions{})
    99  	// One subconn in MockCC.
   100  	if err := checkMockCC(mcc, 1); err != nil {
   101  		t.Fatal(err)
   102  	}
   103  	// No subconn being deleted, and one in CacheCC.
   104  	if err := checkCacheCC(ccc, 0, 1); err != nil {
   105  		t.Fatal(err)
   106  	}
   107  
   108  	ccc.RemoveSubConn(sc)
   109  	// One subconn in MockCC before timeout.
   110  	if err := checkMockCC(mcc, 1); err != nil {
   111  		t.Fatal(err)
   112  	}
   113  	// One subconn being deleted, and one in CacheCC.
   114  	if err := checkCacheCC(ccc, 1, 1); err != nil {
   115  		t.Fatal(err)
   116  	}
   117  
   118  	// Should all become empty after timeout.
   119  	var err error
   120  	for i := 0; i < 2; i++ {
   121  		time.Sleep(testCacheTimeout)
   122  		err = checkMockCC(mcc, 0)
   123  		if err != nil {
   124  			continue
   125  		}
   126  		err = checkCacheCC(ccc, 0, 0)
   127  		if err != nil {
   128  			continue
   129  		}
   130  	}
   131  	if err != nil {
   132  		t.Fatal(err)
   133  	}
   134  }
   135  
   136  // Test that NewSubConn with the same address of a SubConn being removed will
   137  // reuse the SubConn and cancel the removing.
   138  func (s) TestLBCacheClientConnReuse(t *testing.T) {
   139  	mcc := newMockClientConn()
   140  	if err := checkMockCC(mcc, 0); err != nil {
   141  		t.Fatal(err)
   142  	}
   143  
   144  	ccc := newLBCacheClientConn(mcc)
   145  	ccc.timeout = testCacheTimeout
   146  	if err := checkCacheCC(ccc, 0, 0); err != nil {
   147  		t.Fatal(err)
   148  	}
   149  
   150  	sc, _ := ccc.NewSubConn([]resolver.Address{{Addr: "address1"}}, balancer.NewSubConnOptions{})
   151  	// One subconn in MockCC.
   152  	if err := checkMockCC(mcc, 1); err != nil {
   153  		t.Fatal(err)
   154  	}
   155  	// No subconn being deleted, and one in CacheCC.
   156  	if err := checkCacheCC(ccc, 0, 1); err != nil {
   157  		t.Fatal(err)
   158  	}
   159  
   160  	ccc.RemoveSubConn(sc)
   161  	// One subconn in MockCC before timeout.
   162  	if err := checkMockCC(mcc, 1); err != nil {
   163  		t.Fatal(err)
   164  	}
   165  	// One subconn being deleted, and one in CacheCC.
   166  	if err := checkCacheCC(ccc, 1, 1); err != nil {
   167  		t.Fatal(err)
   168  	}
   169  
   170  	// Recreate the old subconn, this should cancel the deleting process.
   171  	sc, _ = ccc.NewSubConn([]resolver.Address{{Addr: "address1"}}, balancer.NewSubConnOptions{})
   172  	// One subconn in MockCC.
   173  	if err := checkMockCC(mcc, 1); err != nil {
   174  		t.Fatal(err)
   175  	}
   176  	// No subconn being deleted, and one in CacheCC.
   177  	if err := checkCacheCC(ccc, 0, 1); err != nil {
   178  		t.Fatal(err)
   179  	}
   180  
   181  	var err error
   182  	// Should not become empty after 2*timeout.
   183  	time.Sleep(2 * testCacheTimeout)
   184  	err = checkMockCC(mcc, 1)
   185  	if err != nil {
   186  		t.Fatal(err)
   187  	}
   188  	err = checkCacheCC(ccc, 0, 1)
   189  	if err != nil {
   190  		t.Fatal(err)
   191  	}
   192  
   193  	// Call remove again, will delete after timeout.
   194  	ccc.RemoveSubConn(sc)
   195  	// One subconn in MockCC before timeout.
   196  	if err := checkMockCC(mcc, 1); err != nil {
   197  		t.Fatal(err)
   198  	}
   199  	// One subconn being deleted, and one in CacheCC.
   200  	if err := checkCacheCC(ccc, 1, 1); err != nil {
   201  		t.Fatal(err)
   202  	}
   203  
   204  	// Should all become empty after timeout.
   205  	for i := 0; i < 2; i++ {
   206  		time.Sleep(testCacheTimeout)
   207  		err = checkMockCC(mcc, 0)
   208  		if err != nil {
   209  			continue
   210  		}
   211  		err = checkCacheCC(ccc, 0, 0)
   212  		if err != nil {
   213  			continue
   214  		}
   215  	}
   216  	if err != nil {
   217  		t.Fatal(err)
   218  	}
   219  }
   220  
   221  // Test that if the timer to remove a SubConn fires at the same time NewSubConn
   222  // cancels the timer, it doesn't cause deadlock.
   223  func (s) TestLBCache_RemoveTimer_New_Race(t *testing.T) {
   224  	mcc := newMockClientConn()
   225  	if err := checkMockCC(mcc, 0); err != nil {
   226  		t.Fatal(err)
   227  	}
   228  
   229  	ccc := newLBCacheClientConn(mcc)
   230  	ccc.timeout = time.Nanosecond
   231  	if err := checkCacheCC(ccc, 0, 0); err != nil {
   232  		t.Fatal(err)
   233  	}
   234  
   235  	sc, _ := ccc.NewSubConn([]resolver.Address{{Addr: "address1"}}, balancer.NewSubConnOptions{})
   236  	// One subconn in MockCC.
   237  	if err := checkMockCC(mcc, 1); err != nil {
   238  		t.Fatal(err)
   239  	}
   240  	// No subconn being deleted, and one in CacheCC.
   241  	if err := checkCacheCC(ccc, 0, 1); err != nil {
   242  		t.Fatal(err)
   243  	}
   244  
   245  	done := make(chan struct{})
   246  
   247  	go func() {
   248  		for i := 0; i < 1000; i++ {
   249  			// Remove starts a timer with 1 ns timeout, the NewSubConn will race
   250  			// with with the timer.
   251  			ccc.RemoveSubConn(sc)
   252  			sc, _ = ccc.NewSubConn([]resolver.Address{{Addr: "address1"}}, balancer.NewSubConnOptions{})
   253  		}
   254  		close(done)
   255  	}()
   256  
   257  	select {
   258  	case <-time.After(time.Second):
   259  		t.Fatalf("Test didn't finish within 1 second. Deadlock")
   260  	case <-done:
   261  	}
   262  }