...

Source file src/google.golang.org/grpc/internal/grpctest/grpctest.go

Documentation: google.golang.org/grpc/internal/grpctest

     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 grpctest implements testing helpers.
    20  package grpctest
    21  
    22  import (
    23  	"reflect"
    24  	"strings"
    25  	"sync/atomic"
    26  	"testing"
    27  
    28  	"google.golang.org/grpc/internal/leakcheck"
    29  )
    30  
    31  var lcFailed uint32
    32  
    33  type errorer struct {
    34  	t *testing.T
    35  }
    36  
    37  func (e errorer) Errorf(format string, args ...any) {
    38  	atomic.StoreUint32(&lcFailed, 1)
    39  	e.t.Errorf(format, args...)
    40  }
    41  
    42  // Tester is an implementation of the x interface parameter to
    43  // grpctest.RunSubTests with default Setup and Teardown behavior. Setup updates
    44  // the tlogger and Teardown performs a leak check. Embed in a struct with tests
    45  // defined to use.
    46  type Tester struct{}
    47  
    48  // Setup updates the tlogger.
    49  func (Tester) Setup(t *testing.T) {
    50  	TLogger.Update(t)
    51  }
    52  
    53  // Teardown performs a leak check.
    54  func (Tester) Teardown(t *testing.T) {
    55  	if atomic.LoadUint32(&lcFailed) == 1 {
    56  		return
    57  	}
    58  	leakcheck.Check(errorer{t: t})
    59  	if atomic.LoadUint32(&lcFailed) == 1 {
    60  		t.Log("Leak check disabled for future tests")
    61  	}
    62  	TLogger.EndTest(t)
    63  }
    64  
    65  // Interface defines Tester's methods for use in this package.
    66  type Interface interface {
    67  	Setup(*testing.T)
    68  	Teardown(*testing.T)
    69  }
    70  
    71  func getTestFunc(t *testing.T, xv reflect.Value, name string) func(*testing.T) {
    72  	if m := xv.MethodByName(name); m.IsValid() {
    73  		if f, ok := m.Interface().(func(*testing.T)); ok {
    74  			return f
    75  		}
    76  		// Method exists but has the wrong type signature.
    77  		t.Fatalf("grpctest: function %v has unexpected signature (%T)", name, m.Interface())
    78  	}
    79  	return func(*testing.T) {}
    80  }
    81  
    82  // RunSubTests runs all "Test___" functions that are methods of x as subtests
    83  // of the current test.  Setup is run before the test function and Teardown is
    84  // run after.
    85  //
    86  // For example usage, see example_test.go.  Run it using:
    87  //
    88  //	$ go test -v -run TestExample .
    89  //
    90  // To run a specific test/subtest:
    91  //
    92  //	$ go test -v -run 'TestExample/^Something$' .
    93  func RunSubTests(t *testing.T, x Interface) {
    94  	xt := reflect.TypeOf(x)
    95  	xv := reflect.ValueOf(x)
    96  
    97  	for i := 0; i < xt.NumMethod(); i++ {
    98  		methodName := xt.Method(i).Name
    99  		if !strings.HasPrefix(methodName, "Test") {
   100  			continue
   101  		}
   102  		tfunc := getTestFunc(t, xv, methodName)
   103  		t.Run(strings.TrimPrefix(methodName, "Test"), func(t *testing.T) {
   104  			// Run leakcheck in t.Cleanup() to guarantee it is run even if tfunc
   105  			// or setup uses t.Fatal().
   106  			//
   107  			// Note that a defer would run before t.Cleanup, so if a goroutine
   108  			// is closed by a test's t.Cleanup, a deferred leakcheck would fail.
   109  			t.Cleanup(func() { x.Teardown(t) })
   110  			x.Setup(t)
   111  			tfunc(t)
   112  		})
   113  	}
   114  }
   115  

View as plain text