github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/logger/loggers_test.go (about) 1 // Copyright 2014 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package logger 18 19 import ( 20 "io/ioutil" 21 "log" 22 "math/rand" 23 "os" 24 "sync" 25 "testing" 26 "time" 27 ) 28 29 type TestLogSystem struct { 30 mutex sync.Mutex 31 output string 32 level LogLevel 33 } 34 35 func (ls *TestLogSystem) GetLogger() *log.Logger { 36 return ls.GetLogger() 37 } 38 39 func (ls *TestLogSystem) LogPrint(msg LogMsg) { 40 ls.mutex.Lock() 41 if ls.level >= msg.Level() { 42 ls.output += msg.String() 43 } 44 ls.mutex.Unlock() 45 } 46 47 func (ls *TestLogSystem) SetLogLevel(i LogLevel) { 48 ls.mutex.Lock() 49 ls.level = i 50 ls.mutex.Unlock() 51 } 52 53 func (ls *TestLogSystem) GetLogLevel() LogLevel { 54 ls.mutex.Lock() 55 defer ls.mutex.Unlock() 56 return ls.level 57 } 58 59 func (ls *TestLogSystem) CheckOutput(t *testing.T, expected string) { 60 ls.mutex.Lock() 61 output := ls.output 62 ls.mutex.Unlock() 63 if output != expected { 64 t.Errorf("log output mismatch:\n got: %q\n want: %q\n", output, expected) 65 } 66 } 67 68 type blockedLogSystem struct { 69 LogSystem 70 unblock chan struct{} 71 } 72 73 func (ls blockedLogSystem) LogPrint(msg LogMsg) { 74 <-ls.unblock 75 ls.LogSystem.LogPrint(msg) 76 } 77 78 func TestLoggerFlush(t *testing.T) { 79 Reset() 80 81 logger := NewLogger("TEST") 82 ls := blockedLogSystem{&TestLogSystem{level: WarnLevel}, make(chan struct{})} 83 AddLogSystem(ls) 84 for i := 0; i < 5; i++ { 85 // these writes shouldn't hang even though ls is blocked 86 logger.Errorf(".") 87 } 88 89 beforeFlush := time.Now() 90 time.AfterFunc(80*time.Millisecond, func() { close(ls.unblock) }) 91 Flush() // this should hang for approx. 80ms 92 if blockd := time.Now().Sub(beforeFlush); blockd < 80*time.Millisecond { 93 t.Errorf("Flush didn't block long enough, blocked for %v, should've been >= 80ms", blockd) 94 } 95 96 ls.LogSystem.(*TestLogSystem).CheckOutput(t, "[TEST] .[TEST] .[TEST] .[TEST] .[TEST] .") 97 } 98 99 func TestLoggerPrintln(t *testing.T) { 100 Reset() 101 102 logger := NewLogger("TEST") 103 testLogSystem := &TestLogSystem{level: WarnLevel} 104 AddLogSystem(testLogSystem) 105 logger.Errorln("error") 106 logger.Warnln("warn") 107 logger.Infoln("info") 108 logger.Debugln("debug") 109 Flush() 110 111 testLogSystem.CheckOutput(t, "[TEST] error\n[TEST] warn\n") 112 } 113 114 func TestLoggerPrintf(t *testing.T) { 115 Reset() 116 117 logger := NewLogger("TEST") 118 testLogSystem := &TestLogSystem{level: WarnLevel} 119 AddLogSystem(testLogSystem) 120 logger.Errorf("error to %v\n", []int{1, 2, 3}) 121 logger.Warnf("warn %%d %d", 5) 122 logger.Infof("info") 123 logger.Debugf("debug") 124 Flush() 125 testLogSystem.CheckOutput(t, "[TEST] error to [1 2 3]\n[TEST] warn %d 5") 126 } 127 128 func TestMultipleLogSystems(t *testing.T) { 129 Reset() 130 131 logger := NewLogger("TEST") 132 testLogSystem0 := &TestLogSystem{level: ErrorLevel} 133 testLogSystem1 := &TestLogSystem{level: WarnLevel} 134 AddLogSystem(testLogSystem0) 135 AddLogSystem(testLogSystem1) 136 logger.Errorln("error") 137 logger.Warnln("warn") 138 Flush() 139 140 testLogSystem0.CheckOutput(t, "[TEST] error\n") 141 testLogSystem1.CheckOutput(t, "[TEST] error\n[TEST] warn\n") 142 } 143 144 func TestFileLogSystem(t *testing.T) { 145 Reset() 146 147 logger := NewLogger("TEST") 148 filename := "test.log" 149 file, _ := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, os.ModePerm) 150 testLogSystem := NewStdLogSystem(file, 0, WarnLevel) 151 AddLogSystem(testLogSystem) 152 logger.Errorf("error to %s\n", filename) 153 logger.Warnln("warn") 154 Flush() 155 contents, _ := ioutil.ReadFile(filename) 156 output := string(contents) 157 if output != "[TEST] error to test.log\n[TEST] warn\n" { 158 t.Error("Expected contents of file 'test.log': '[TEST] error to test.log\\n[TEST] warn\\n', got ", output) 159 } else { 160 os.Remove(filename) 161 } 162 } 163 164 func TestNoLogSystem(t *testing.T) { 165 Reset() 166 167 logger := NewLogger("TEST") 168 logger.Warnln("warn") 169 Flush() 170 } 171 172 func TestConcurrentAddSystem(t *testing.T) { 173 rand.Seed(time.Now().Unix()) 174 Reset() 175 176 logger := NewLogger("TEST") 177 stop := make(chan struct{}) 178 writer := func() { 179 select { 180 case <-stop: 181 return 182 default: 183 logger.Infoln("foo") 184 Flush() 185 } 186 } 187 188 go writer() 189 go writer() 190 191 stopTime := time.Now().Add(100 * time.Millisecond) 192 for time.Now().Before(stopTime) { 193 time.Sleep(time.Duration(rand.Intn(20)) * time.Millisecond) 194 AddLogSystem(NewStdLogSystem(ioutil.Discard, 0, InfoLevel)) 195 } 196 close(stop) 197 }