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  }