github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/internal/grpctest/tlogger.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 grpctest
    20  
    21  import (
    22  	"errors"
    23  	"fmt"
    24  	"os"
    25  	"path"
    26  	"regexp"
    27  	"runtime"
    28  	"strconv"
    29  	"sync"
    30  	"testing"
    31  	"time"
    32  
    33  	"github.com/hxx258456/ccgo/grpc/grpclog"
    34  )
    35  
    36  // TLogger serves as the grpclog logger and is the interface through which
    37  // expected errors are declared in tests.
    38  var TLogger *tLogger
    39  
    40  const callingFrame = 4
    41  
    42  type logType int
    43  
    44  func (l logType) String() string {
    45  	switch l {
    46  	case infoLog:
    47  		return "INFO"
    48  	case warningLog:
    49  		return "WARNING"
    50  	case errorLog:
    51  		return "ERROR"
    52  	case fatalLog:
    53  		return "FATAL"
    54  	}
    55  	return "UNKNOWN"
    56  }
    57  
    58  const (
    59  	infoLog logType = iota
    60  	warningLog
    61  	errorLog
    62  	fatalLog
    63  )
    64  
    65  type tLogger struct {
    66  	v           int
    67  	initialized bool
    68  
    69  	mu     sync.Mutex // guards t, start, and errors
    70  	t      *testing.T
    71  	start  time.Time
    72  	errors map[*regexp.Regexp]int
    73  }
    74  
    75  func init() {
    76  	TLogger = &tLogger{errors: map[*regexp.Regexp]int{}}
    77  	vLevel := os.Getenv("GRPC_GO_LOG_VERBOSITY_LEVEL")
    78  	if vl, err := strconv.Atoi(vLevel); err == nil {
    79  		TLogger.v = vl
    80  	}
    81  }
    82  
    83  // getCallingPrefix returns the <file:line> at the given depth from the stack.
    84  func getCallingPrefix(depth int) (string, error) {
    85  	_, file, line, ok := runtime.Caller(depth)
    86  	if !ok {
    87  		return "", errors.New("frame request out-of-bounds")
    88  	}
    89  	return fmt.Sprintf("%s:%d", path.Base(file), line), nil
    90  }
    91  
    92  // log logs the message with the specified parameters to the tLogger.
    93  func (g *tLogger) log(ltype logType, depth int, format string, args ...interface{}) {
    94  	g.mu.Lock()
    95  	defer g.mu.Unlock()
    96  	prefix, err := getCallingPrefix(callingFrame + depth)
    97  	if err != nil {
    98  		g.t.Error(err)
    99  		return
   100  	}
   101  	args = append([]interface{}{ltype.String() + " " + prefix}, args...)
   102  	args = append(args, fmt.Sprintf(" (t=+%s)", time.Since(g.start)))
   103  
   104  	if format == "" {
   105  		switch ltype {
   106  		case errorLog:
   107  			// fmt.Sprintln is used rather than fmt.Sprint because t.Log uses fmt.Sprintln behavior.
   108  			if g.expected(fmt.Sprintln(args...)) {
   109  				g.t.Log(args...)
   110  			} else {
   111  				g.t.Error(args...)
   112  			}
   113  		case fatalLog:
   114  			panic(fmt.Sprint(args...))
   115  		default:
   116  			g.t.Log(args...)
   117  		}
   118  	} else {
   119  		// Add formatting directives for the callingPrefix and timeSuffix.
   120  		format = "%v " + format + "%s"
   121  		switch ltype {
   122  		case errorLog:
   123  			if g.expected(fmt.Sprintf(format, args...)) {
   124  				g.t.Logf(format, args...)
   125  			} else {
   126  				g.t.Errorf(format, args...)
   127  			}
   128  		case fatalLog:
   129  			panic(fmt.Sprintf(format, args...))
   130  		default:
   131  			g.t.Logf(format, args...)
   132  		}
   133  	}
   134  }
   135  
   136  // Update updates the testing.T that the testing logger logs to. Should be done
   137  // before every test. It also initializes the tLogger if it has not already.
   138  func (g *tLogger) Update(t *testing.T) {
   139  	g.mu.Lock()
   140  	defer g.mu.Unlock()
   141  	if !g.initialized {
   142  		grpclog.SetLoggerV2(TLogger)
   143  		g.initialized = true
   144  	}
   145  	g.t = t
   146  	g.start = time.Now()
   147  	g.errors = map[*regexp.Regexp]int{}
   148  }
   149  
   150  // ExpectError declares an error to be expected. For the next test, the first
   151  // error log matching the expression (using FindString) will not cause the test
   152  // to fail. "For the next test" includes all the time until the next call to
   153  // Update(). Note that if an expected error is not encountered, this will cause
   154  // the test to fail.
   155  func (g *tLogger) ExpectError(expr string) {
   156  	g.ExpectErrorN(expr, 1)
   157  }
   158  
   159  // ExpectErrorN declares an error to be expected n times.
   160  func (g *tLogger) ExpectErrorN(expr string, n int) {
   161  	g.mu.Lock()
   162  	defer g.mu.Unlock()
   163  	re, err := regexp.Compile(expr)
   164  	if err != nil {
   165  		g.t.Error(err)
   166  		return
   167  	}
   168  	g.errors[re] += n
   169  }
   170  
   171  // EndTest checks if expected errors were not encountered.
   172  func (g *tLogger) EndTest(t *testing.T) {
   173  	g.mu.Lock()
   174  	defer g.mu.Unlock()
   175  	for re, count := range g.errors {
   176  		if count > 0 {
   177  			t.Errorf("Expected error '%v' not encountered", re.String())
   178  		}
   179  	}
   180  	g.errors = map[*regexp.Regexp]int{}
   181  }
   182  
   183  // expected determines if the error string is protected or not.
   184  func (g *tLogger) expected(s string) bool {
   185  	for re, count := range g.errors {
   186  		if re.FindStringIndex(s) != nil {
   187  			g.errors[re]--
   188  			if count <= 1 {
   189  				delete(g.errors, re)
   190  			}
   191  			return true
   192  		}
   193  	}
   194  	return false
   195  }
   196  
   197  func (g *tLogger) Info(args ...interface{}) {
   198  	g.log(infoLog, 0, "", args...)
   199  }
   200  
   201  func (g *tLogger) Infoln(args ...interface{}) {
   202  	g.log(infoLog, 0, "", args...)
   203  }
   204  
   205  func (g *tLogger) Infof(format string, args ...interface{}) {
   206  	g.log(infoLog, 0, format, args...)
   207  }
   208  
   209  func (g *tLogger) InfoDepth(depth int, args ...interface{}) {
   210  	g.log(infoLog, depth, "", args...)
   211  }
   212  
   213  func (g *tLogger) Warning(args ...interface{}) {
   214  	g.log(warningLog, 0, "", args...)
   215  }
   216  
   217  func (g *tLogger) Warningln(args ...interface{}) {
   218  	g.log(warningLog, 0, "", args...)
   219  }
   220  
   221  func (g *tLogger) Warningf(format string, args ...interface{}) {
   222  	g.log(warningLog, 0, format, args...)
   223  }
   224  
   225  func (g *tLogger) WarningDepth(depth int, args ...interface{}) {
   226  	g.log(warningLog, depth, "", args...)
   227  }
   228  
   229  func (g *tLogger) Error(args ...interface{}) {
   230  	g.log(errorLog, 0, "", args...)
   231  }
   232  
   233  func (g *tLogger) Errorln(args ...interface{}) {
   234  	g.log(errorLog, 0, "", args...)
   235  }
   236  
   237  func (g *tLogger) Errorf(format string, args ...interface{}) {
   238  	g.log(errorLog, 0, format, args...)
   239  }
   240  
   241  func (g *tLogger) ErrorDepth(depth int, args ...interface{}) {
   242  	g.log(errorLog, depth, "", args...)
   243  }
   244  
   245  func (g *tLogger) Fatal(args ...interface{}) {
   246  	g.log(fatalLog, 0, "", args...)
   247  }
   248  
   249  func (g *tLogger) Fatalln(args ...interface{}) {
   250  	g.log(fatalLog, 0, "", args...)
   251  }
   252  
   253  func (g *tLogger) Fatalf(format string, args ...interface{}) {
   254  	g.log(fatalLog, 0, format, args...)
   255  }
   256  
   257  func (g *tLogger) FatalDepth(depth int, args ...interface{}) {
   258  	g.log(fatalLog, depth, "", args...)
   259  }
   260  
   261  func (g *tLogger) V(l int) bool {
   262  	return l <= g.v
   263  }