github.com/cellofellow/gopkg@v0.0.0-20140722061823-eec0544a62ad/glog/glog_test.go (about) 1 // Go support for leveled logs, analogous to https://code.google.com/p/google-glog/ 2 // 3 // Copyright 2013 Google Inc. All Rights Reserved. 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 package glog 18 19 import ( 20 "bytes" 21 "fmt" 22 "path/filepath" 23 "runtime" 24 "strings" 25 "testing" 26 "time" 27 ) 28 29 // Test that shortHostname works as advertised. 30 func TestShortHostname(t *testing.T) { 31 for hostname, expect := range map[string]string{ 32 "": "", 33 "host": "host", 34 "host.google.com": "host", 35 } { 36 if got := shortHostname(hostname); expect != got { 37 t.Errorf("shortHostname(%q): expected %q, got %q", hostname, expect, got) 38 } 39 } 40 } 41 42 // flushBuffer wraps a bytes.Buffer to satisfy flushSyncWriter. 43 type flushBuffer struct { 44 bytes.Buffer 45 } 46 47 func (f *flushBuffer) Flush() error { 48 return nil 49 } 50 51 func (f *flushBuffer) Sync() error { 52 return nil 53 } 54 55 // swap sets the log writers and returns the old array. 56 func (l *loggingT) swap(writers [numSeverity]flushSyncWriter) (old [numSeverity]flushSyncWriter) { 57 l.mu.Lock() 58 defer l.mu.Unlock() 59 old = l.file 60 for i, w := range writers { 61 logging.file[i] = w 62 } 63 return 64 } 65 66 // newBuffers sets the log writers to all new byte buffers and returns the old array. 67 func (l *loggingT) newBuffers() [numSeverity]flushSyncWriter { 68 return l.swap([numSeverity]flushSyncWriter{new(flushBuffer), new(flushBuffer), new(flushBuffer), new(flushBuffer)}) 69 } 70 71 // contents returns the specified log value as a string. 72 func contents(s severity) string { 73 return logging.file[s].(*flushBuffer).String() 74 } 75 76 // contains reports whether the string is contained in the log. 77 func contains(s severity, str string, t *testing.T) bool { 78 return strings.Contains(contents(s), str) 79 } 80 81 // setFlags configures the logging flags how the test expects them. 82 func setFlags() { 83 logging.toStderr = false 84 } 85 86 // Test that Info works as advertised. 87 func TestInfo(t *testing.T) { 88 setFlags() 89 defer logging.swap(logging.newBuffers()) 90 Info("test") 91 if !contains(infoLog, "I", t) { 92 t.Errorf("Info has wrong character: %q", contents(infoLog)) 93 } 94 if !contains(infoLog, "test", t) { 95 t.Error("Info failed") 96 } 97 } 98 99 // Test that the header has the correct format. 100 func TestHeader(t *testing.T) { 101 setFlags() 102 defer logging.swap(logging.newBuffers()) 103 defer func(previous func() time.Time) { timeNow = previous }(timeNow) 104 timeNow = func() time.Time { 105 return time.Date(2006, 1, 2, 15, 4, 5, .678901e9, time.Local) 106 } 107 Info("test") 108 var line, pid int 109 n, err := fmt.Sscanf(contents(infoLog), "I0102 15:04:05.678901 %d glog_test.go:%d] test\n", &pid, &line) 110 if n != 2 || err != nil { 111 t.Errorf("log format error: %d elements, error %s:\n%s", n, err, contents(infoLog)) 112 } 113 } 114 115 // Test that an Error log goes to Warning and Info. 116 // Even in the Info log, the source character will be E, so the data should 117 // all be identical. 118 func TestError(t *testing.T) { 119 setFlags() 120 defer logging.swap(logging.newBuffers()) 121 Error("test") 122 if !contains(errorLog, "E", t) { 123 t.Errorf("Error has wrong character: %q", contents(errorLog)) 124 } 125 if !contains(errorLog, "test", t) { 126 t.Error("Error failed") 127 } 128 str := contents(errorLog) 129 if !contains(warningLog, str, t) { 130 t.Error("Warning failed") 131 } 132 if !contains(infoLog, str, t) { 133 t.Error("Info failed") 134 } 135 } 136 137 // Test that a Warning log goes to Info. 138 // Even in the Info log, the source character will be W, so the data should 139 // all be identical. 140 func TestWarning(t *testing.T) { 141 setFlags() 142 defer logging.swap(logging.newBuffers()) 143 Warning("test") 144 if !contains(warningLog, "W", t) { 145 t.Errorf("Warning has wrong character: %q", contents(warningLog)) 146 } 147 if !contains(warningLog, "test", t) { 148 t.Error("Warning failed") 149 } 150 str := contents(warningLog) 151 if !contains(infoLog, str, t) { 152 t.Error("Info failed") 153 } 154 } 155 156 // Test that a V log goes to Info. 157 func TestV(t *testing.T) { 158 setFlags() 159 defer logging.swap(logging.newBuffers()) 160 logging.verbosity.Set("2") 161 defer logging.verbosity.Set("0") 162 V(2).Info("test") 163 if !contains(infoLog, "I", t) { 164 t.Errorf("Info has wrong character: %q", contents(infoLog)) 165 } 166 if !contains(infoLog, "test", t) { 167 t.Error("Info failed") 168 } 169 } 170 171 // Test that a vmodule enables a log in this file. 172 func TestVmoduleOn(t *testing.T) { 173 setFlags() 174 defer logging.swap(logging.newBuffers()) 175 logging.vmodule.Set("glog_test=2") 176 defer logging.vmodule.Set("") 177 if !V(1) { 178 t.Error("V not enabled for 1") 179 } 180 if !V(2) { 181 t.Error("V not enabled for 2") 182 } 183 if V(3) { 184 t.Error("V enabled for 3") 185 } 186 V(2).Info("test") 187 if !contains(infoLog, "I", t) { 188 t.Errorf("Info has wrong character: %q", contents(infoLog)) 189 } 190 if !contains(infoLog, "test", t) { 191 t.Error("Info failed") 192 } 193 } 194 195 // Test that a vmodule of another file does not enable a log in this file. 196 func TestVmoduleOff(t *testing.T) { 197 setFlags() 198 defer logging.swap(logging.newBuffers()) 199 logging.vmodule.Set("notthisfile=2") 200 defer logging.vmodule.Set("") 201 for i := 1; i <= 3; i++ { 202 if V(Level(i)) { 203 t.Errorf("V enabled for %d", i) 204 } 205 } 206 V(2).Info("test") 207 if contents(infoLog) != "" { 208 t.Error("V logged incorrectly") 209 } 210 } 211 212 // vGlobs are patterns that match/don't match this file at V=2. 213 var vGlobs = map[string]bool{ 214 // Easy to test the numeric match here. 215 "glog_test=1": false, // If -vmodule sets V to 1, V(2) will fail. 216 "glog_test=2": true, 217 "glog_test=3": true, // If -vmodule sets V to 1, V(3) will succeed. 218 // These all use 2 and check the patterns. All are true. 219 "*=2": true, 220 "?l*=2": true, 221 "????_*=2": true, 222 "??[mno]?_*t=2": true, 223 // These all use 2 and check the patterns. All are false. 224 "*x=2": false, 225 "m*=2": false, 226 "??_*=2": false, 227 "?[abc]?_*t=2": false, 228 } 229 230 // Test that vmodule globbing works as advertised. 231 func testVmoduleGlob(pat string, match bool, t *testing.T) { 232 setFlags() 233 defer logging.swap(logging.newBuffers()) 234 defer logging.vmodule.Set("") 235 logging.vmodule.Set(pat) 236 if V(2) != Verbose(match) { 237 t.Errorf("incorrect match for %q: got %t expected %t", pat, V(2), match) 238 } 239 } 240 241 // Test that a vmodule globbing works as advertised. 242 func TestVmoduleGlob(t *testing.T) { 243 for glob, match := range vGlobs { 244 testVmoduleGlob(glob, match, t) 245 } 246 } 247 248 func TestRollover(t *testing.T) { 249 setFlags() 250 var err error 251 defer func(previous func(error)) { logExitFunc = previous }(logExitFunc) 252 logExitFunc = func(e error) { 253 err = e 254 } 255 defer func(previous uint64) { MaxSize = previous }(MaxSize) 256 MaxSize = 512 257 258 Info("x") // Be sure we have a file. 259 info, ok := logging.file[infoLog].(*syncBuffer) 260 if !ok { 261 t.Fatal("info wasn't created") 262 } 263 if err != nil { 264 t.Fatalf("info has initial error: %v", err) 265 } 266 fname0 := info.file.Name() 267 Info(strings.Repeat("x", int(MaxSize))) // force a rollover 268 if err != nil { 269 t.Fatalf("info has error after big write: %v", err) 270 } 271 272 // Make sure the next log file gets a file name with a different 273 // time stamp. 274 // 275 // TODO: determine whether we need to support subsecond log 276 // rotation. C++ does not appear to handle this case (nor does it 277 // handle Daylight Savings Time properly). 278 time.Sleep(1 * time.Second) 279 280 Info("x") // create a new file 281 if err != nil { 282 t.Fatalf("error after rotation: %v", err) 283 } 284 fname1 := info.file.Name() 285 if fname0 == fname1 { 286 t.Errorf("info.f.Name did not change: %v", fname0) 287 } 288 if info.nbytes >= MaxSize { 289 t.Errorf("file size was not reset: %d", info.nbytes) 290 } 291 } 292 293 func TestLogBacktraceAt(t *testing.T) { 294 setFlags() 295 defer logging.swap(logging.newBuffers()) 296 // The peculiar style of this code simplifies line counting and maintenance of the 297 // tracing block below. 298 var infoLine string 299 setTraceLocation := func(file string, line int, ok bool, delta int) { 300 if !ok { 301 t.Fatal("could not get file:line") 302 } 303 _, file = filepath.Split(file) 304 infoLine = fmt.Sprintf("%s:%d", file, line+delta) 305 err := logging.traceLocation.Set(infoLine) 306 if err != nil { 307 t.Fatal("error setting log_backtrace_at: ", err) 308 } 309 } 310 { 311 // Start of tracing block. These lines know about each other's relative position. 312 _, file, line, ok := runtime.Caller(0) 313 setTraceLocation(file, line, ok, +2) // Two lines between Caller and Info calls. 314 Info("we want a stack trace here") 315 } 316 numAppearances := strings.Count(contents(infoLog), infoLine) 317 if numAppearances < 2 { 318 // Need 2 appearances, one in the log header and one in the trace: 319 // log_test.go:281: I0511 16:36:06.952398 02238 log_test.go:280] we want a stack trace here 320 // ... 321 // github.com/glog/glog_test.go:280 (0x41ba91) 322 // ... 323 // We could be more precise but that would require knowing the details 324 // of the traceback format, which may not be dependable. 325 t.Fatal("got no trace back; log is ", contents(infoLog)) 326 } 327 } 328 329 func BenchmarkHeader(b *testing.B) { 330 for i := 0; i < b.N; i++ { 331 logging.putBuffer(logging.header(infoLog)) 332 } 333 }