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 }