2019-04-07 01:25:14 +01:00
// Copyright 2019 The Gitea Authors. All rights reserved.
2022-11-27 13:20:29 -05:00
// SPDX-License-Identifier: MIT
2019-04-07 01:25:14 +01:00
2023-05-08 19:49:59 +08:00
package testlogger
2019-04-07 01:25:14 +01:00
import (
2020-01-29 01:01:06 +00:00
"context"
2019-04-07 01:25:14 +01:00
"fmt"
"os"
"runtime"
"strings"
2019-09-17 17:39:37 +08:00
"sync"
2019-04-07 01:25:14 +01:00
"testing"
2020-06-02 02:39:44 +01:00
"time"
2019-04-07 01:25:14 +01:00
"code.gitea.io/gitea/modules/log"
2020-01-29 01:01:06 +00:00
"code.gitea.io/gitea/modules/queue"
2019-04-07 01:25:14 +01:00
)
2020-06-02 02:39:44 +01:00
var (
prefix string
2022-09-02 15:18:23 -04:00
SlowTest = 10 * time . Second
SlowFlush = 5 * time . Second
2020-06-02 02:39:44 +01:00
)
2019-04-07 01:25:14 +01:00
2022-09-02 15:18:23 -04:00
var WriterCloser = & testLoggerWriterCloser { }
2019-04-07 01:25:14 +01:00
type testLoggerWriterCloser struct {
2019-09-17 17:39:37 +08:00
sync . RWMutex
2023-05-22 06:35:11 +08:00
t [ ] testing . TB
2019-04-07 01:25:14 +01:00
}
2023-05-22 06:35:11 +08:00
func ( w * testLoggerWriterCloser ) pushT ( t testing . TB ) {
2019-09-17 17:39:37 +08:00
w . Lock ( )
2019-11-25 23:21:37 +00:00
w . t = append ( w . t , t )
2019-09-17 17:39:37 +08:00
w . Unlock ( )
}
2019-04-07 01:25:14 +01:00
func ( w * testLoggerWriterCloser ) Write ( p [ ] byte ) ( int , error ) {
2023-05-08 19:49:59 +08:00
// There was a data race problem: the logger system could still try to output logs after the runner is finished.
// So we must ensure that the "t" in stack is still valid.
2019-09-17 17:39:37 +08:00
w . RLock ( )
2023-05-08 19:49:59 +08:00
defer w . RUnlock ( )
2023-05-22 06:35:11 +08:00
var t testing . TB
2019-11-25 23:21:37 +00:00
if len ( w . t ) > 0 {
t = w . t [ len ( w . t ) - 1 ]
}
2019-04-11 12:49:49 +01:00
2023-05-08 19:49:59 +08:00
if len ( p ) > 0 && p [ len ( p ) - 1 ] == '\n' {
p = p [ : len ( p ) - 1 ]
}
2019-04-11 12:49:49 +01:00
2023-05-22 06:35:11 +08:00
if t == nil {
2023-05-12 22:20:29 +08:00
// if there is no running test, the log message should be outputted to console, to avoid losing important information.
// the "???" prefix is used to match the "===" and "+++" in PrintCurrentTest
return fmt . Fprintf ( os . Stdout , "??? [TestLogger] %s\n" , p )
2019-04-07 01:25:14 +01:00
}
2023-05-08 19:49:59 +08:00
2023-05-22 06:35:11 +08:00
t . Log ( string ( p ) )
2019-04-07 01:25:14 +01:00
return len ( p ) , nil
}
2023-05-08 19:49:59 +08:00
func ( w * testLoggerWriterCloser ) popT ( ) {
2019-11-25 23:21:37 +00:00
w . Lock ( )
if len ( w . t ) > 0 {
w . t = w . t [ : len ( w . t ) - 1 ]
}
w . Unlock ( )
2023-05-08 19:49:59 +08:00
}
func ( w * testLoggerWriterCloser ) Close ( ) error {
2019-04-07 01:25:14 +01:00
return nil
}
2021-09-01 14:05:04 +01:00
func ( w * testLoggerWriterCloser ) Reset ( ) {
w . Lock ( )
if len ( w . t ) > 0 {
for _ , t := range w . t {
if t == nil {
continue
}
2023-05-22 06:35:11 +08:00
_ , _ = fmt . Fprintf ( os . Stdout , "Unclosed logger writer in test: %s" , t . Name ( ) )
t . Errorf ( "Unclosed logger writer in test: %s" , t . Name ( ) )
2021-09-01 14:05:04 +01:00
}
w . t = nil
}
w . Unlock ( )
}
2019-04-07 01:25:14 +01:00
// PrintCurrentTest prints the current test to os.Stdout
2019-11-25 23:21:37 +00:00
func PrintCurrentTest ( t testing . TB , skip ... int ) func ( ) {
2023-06-21 13:50:26 +08:00
t . Helper ( )
2020-06-02 02:39:44 +01:00
start := time . Now ( )
2019-04-07 01:25:14 +01:00
actualSkip := 1
if len ( skip ) > 0 {
2023-06-21 13:50:26 +08:00
actualSkip = skip [ 0 ] + 1
2019-04-07 01:25:14 +01:00
}
_ , filename , line , _ := runtime . Caller ( actualSkip )
if log . CanColorStdout {
2023-05-22 06:35:11 +08:00
_ , _ = fmt . Fprintf ( os . Stdout , "=== %s (%s:%d)\n" , fmt . Formatter ( log . NewColoredValue ( t . Name ( ) ) ) , strings . TrimPrefix ( filename , prefix ) , line )
2019-04-07 01:25:14 +01:00
} else {
2023-05-22 06:35:11 +08:00
_ , _ = fmt . Fprintf ( os . Stdout , "=== %s (%s:%d)\n" , t . Name ( ) , strings . TrimPrefix ( filename , prefix ) , line )
2019-04-07 01:25:14 +01:00
}
2023-05-22 06:35:11 +08:00
WriterCloser . pushT ( t )
2019-11-25 23:21:37 +00:00
return func ( ) {
2020-06-02 02:39:44 +01:00
took := time . Since ( start )
2022-09-02 15:18:23 -04:00
if took > SlowTest {
2020-06-02 02:39:44 +01:00
if log . CanColorStdout {
2023-05-22 06:35:11 +08:00
_ , _ = fmt . Fprintf ( os . Stdout , "+++ %s is a slow test (took %v)\n" , fmt . Formatter ( log . NewColoredValue ( t . Name ( ) , log . Bold , log . FgYellow ) ) , fmt . Formatter ( log . NewColoredValue ( took , log . Bold , log . FgYellow ) ) )
2020-06-02 02:39:44 +01:00
} else {
2023-05-22 06:35:11 +08:00
_ , _ = fmt . Fprintf ( os . Stdout , "+++ %s is a slow test (took %v)\n" , t . Name ( ) , took )
2020-06-02 02:39:44 +01:00
}
}
2022-09-02 15:18:23 -04:00
timer := time . AfterFunc ( SlowFlush , func ( ) {
2020-06-02 02:39:44 +01:00
if log . CanColorStdout {
2023-05-22 06:35:11 +08:00
_ , _ = fmt . Fprintf ( os . Stdout , "+++ %s ... still flushing after %v ...\n" , fmt . Formatter ( log . NewColoredValue ( t . Name ( ) , log . Bold , log . FgRed ) ) , SlowFlush )
2020-06-02 02:39:44 +01:00
} else {
2023-05-22 06:35:11 +08:00
_ , _ = fmt . Fprintf ( os . Stdout , "+++ %s ... still flushing after %v ...\n" , t . Name ( ) , SlowFlush )
2020-06-02 02:39:44 +01:00
}
} )
2023-05-08 19:49:59 +08:00
if err := queue . GetManager ( ) . FlushAll ( context . Background ( ) , time . Minute ) ; err != nil {
2020-01-29 01:01:06 +00:00
t . Errorf ( "Flushing queues failed with error %v" , err )
}
2020-06-02 02:39:44 +01:00
timer . Stop ( )
flushTook := time . Since ( start ) - took
2022-09-02 15:18:23 -04:00
if flushTook > SlowFlush {
2020-06-02 02:39:44 +01:00
if log . CanColorStdout {
2023-05-22 06:35:11 +08:00
_ , _ = fmt . Fprintf ( os . Stdout , "+++ %s had a slow clean-up flush (took %v)\n" , fmt . Formatter ( log . NewColoredValue ( t . Name ( ) , log . Bold , log . FgRed ) ) , fmt . Formatter ( log . NewColoredValue ( flushTook , log . Bold , log . FgRed ) ) )
2020-06-02 02:39:44 +01:00
} else {
2023-05-22 06:35:11 +08:00
_ , _ = fmt . Fprintf ( os . Stdout , "+++ %s had a slow clean-up flush (took %v)\n" , t . Name ( ) , flushTook )
2020-06-02 02:39:44 +01:00
}
}
2023-05-08 19:49:59 +08:00
WriterCloser . popT ( )
2019-11-25 23:21:37 +00:00
}
2019-04-07 01:25:14 +01:00
}
// Printf takes a format and args and prints the string to os.Stdout
2023-07-04 20:36:08 +02:00
func Printf ( format string , args ... any ) {
2019-04-07 01:25:14 +01:00
if log . CanColorStdout {
for i := 0 ; i < len ( args ) ; i ++ {
args [ i ] = log . NewColoredValue ( args [ i ] )
}
}
2023-05-22 06:35:11 +08:00
_ , _ = fmt . Fprintf ( os . Stdout , "\t" + format , args ... )
2019-04-07 01:25:14 +01:00
}
2023-05-22 06:35:11 +08:00
// TestLogEventWriter is a logger which will write to the testing log
type TestLogEventWriter struct {
* log . EventWriterBaseImpl
2020-07-06 01:07:07 +01:00
}
2023-05-22 06:35:11 +08:00
// NewTestLoggerWriter creates a TestLogEventWriter as a log.LoggerProvider
func NewTestLoggerWriter ( name string , mode log . WriterMode ) log . EventWriter {
w := & TestLogEventWriter { }
w . EventWriterBaseImpl = log . NewEventWriterBase ( name , "test-log-writer" , mode )
w . OutputWriteCloser = WriterCloser
return w
2019-04-07 01:25:14 +01:00
}
func init ( ) {
2023-05-08 19:49:59 +08:00
const relFilePath = "modules/testlogger/testlogger.go"
2019-04-07 01:25:14 +01:00
_ , filename , _ , _ := runtime . Caller ( 0 )
2023-05-08 19:49:59 +08:00
if ! strings . HasSuffix ( filename , relFilePath ) {
panic ( "source code file path doesn't match expected: " + relFilePath )
}
prefix = strings . TrimSuffix ( filename , relFilePath )
2019-04-07 01:25:14 +01:00
}