2019-04-06 19:25:14 -05:00
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
2022-09-02 14:18:23 -05:00
package tests
2019-04-06 19:25:14 -05:00
import (
2020-01-28 20:01:06 -05:00
"context"
2019-04-06 19:25:14 -05:00
"fmt"
"os"
"runtime"
"strings"
2019-09-17 04:39:37 -05:00
"sync"
2019-04-06 19:25:14 -05:00
"testing"
2020-06-01 20:39:44 -05:00
"time"
2019-04-06 19:25:14 -05:00
2021-07-24 11:03:58 -05:00
"code.gitea.io/gitea/modules/json"
2019-04-06 19:25:14 -05:00
"code.gitea.io/gitea/modules/log"
2020-01-28 20:01:06 -05:00
"code.gitea.io/gitea/modules/queue"
2019-04-06 19:25:14 -05:00
)
2020-06-01 20:39:44 -05:00
var (
prefix string
2022-09-02 14:18:23 -05:00
SlowTest = 10 * time . Second
SlowFlush = 5 * time . Second
2020-06-01 20:39:44 -05:00
)
2019-04-06 19:25:14 -05:00
// TestLogger is a logger which will write to the testing log
type TestLogger struct {
log . WriterLogger
}
2022-09-02 14:18:23 -05:00
var WriterCloser = & testLoggerWriterCloser { }
2019-04-06 19:25:14 -05:00
type testLoggerWriterCloser struct {
2019-09-17 04:39:37 -05:00
sync . RWMutex
2019-11-25 18:21:37 -05:00
t [ ] * testing . TB
2019-04-06 19:25:14 -05:00
}
2019-09-17 04:39:37 -05:00
func ( w * testLoggerWriterCloser ) setT ( t * testing . TB ) {
w . Lock ( )
2019-11-25 18:21:37 -05:00
w . t = append ( w . t , t )
2019-09-17 04:39:37 -05:00
w . Unlock ( )
}
2019-04-06 19:25:14 -05:00
func ( w * testLoggerWriterCloser ) Write ( p [ ] byte ) ( int , error ) {
2019-09-17 04:39:37 -05:00
w . RLock ( )
2019-11-25 18:21:37 -05:00
var t * testing . TB
if len ( w . t ) > 0 {
t = w . t [ len ( w . t ) - 1 ]
}
2019-09-17 04:39:37 -05:00
w . RUnlock ( )
2019-11-25 18:21:37 -05:00
if t != nil && * t != nil {
2019-04-06 19:25:14 -05:00
if len ( p ) > 0 && p [ len ( p ) - 1 ] == '\n' {
p = p [ : len ( p ) - 1 ]
}
2019-04-11 06:49:49 -05:00
defer func ( ) {
err := recover ( )
if err == nil {
return
}
var errString string
errErr , ok := err . ( error )
if ok {
errString = errErr . Error ( )
} else {
errString , ok = err . ( string )
}
if ! ok {
panic ( err )
}
if ! strings . HasPrefix ( errString , "Log in goroutine after " ) {
panic ( err )
}
} ( )
2019-11-25 18:21:37 -05:00
( * t ) . Log ( string ( p ) )
2019-04-06 19:25:14 -05:00
return len ( p ) , nil
}
return len ( p ) , nil
}
func ( w * testLoggerWriterCloser ) Close ( ) error {
2019-11-25 18:21:37 -05:00
w . Lock ( )
if len ( w . t ) > 0 {
w . t = w . t [ : len ( w . t ) - 1 ]
}
w . Unlock ( )
2019-04-06 19:25:14 -05:00
return nil
}
2021-09-01 08:05:04 -05:00
func ( w * testLoggerWriterCloser ) Reset ( ) {
w . Lock ( )
if len ( w . t ) > 0 {
for _ , t := range w . t {
if t == nil {
continue
}
fmt . Fprintf ( os . Stdout , "Unclosed logger writer in test: %s" , ( * t ) . Name ( ) )
( * t ) . Errorf ( "Unclosed logger writer in test: %s" , ( * t ) . Name ( ) )
}
w . t = nil
}
w . Unlock ( )
}
2019-04-06 19:25:14 -05:00
// PrintCurrentTest prints the current test to os.Stdout
2019-11-25 18:21:37 -05:00
func PrintCurrentTest ( t testing . TB , skip ... int ) func ( ) {
2020-06-01 20:39:44 -05:00
start := time . Now ( )
2019-04-06 19:25:14 -05:00
actualSkip := 1
if len ( skip ) > 0 {
actualSkip = skip [ 0 ]
}
_ , filename , line , _ := runtime . Caller ( actualSkip )
if log . CanColorStdout {
2019-06-12 14:41:28 -05:00
fmt . Fprintf ( os . Stdout , "=== %s (%s:%d)\n" , fmt . Formatter ( log . NewColoredValue ( t . Name ( ) ) ) , strings . TrimPrefix ( filename , prefix ) , line )
2019-04-06 19:25:14 -05:00
} else {
fmt . Fprintf ( os . Stdout , "=== %s (%s:%d)\n" , t . Name ( ) , strings . TrimPrefix ( filename , prefix ) , line )
}
2022-09-02 14:18:23 -05:00
WriterCloser . setT ( & t )
2019-11-25 18:21:37 -05:00
return func ( ) {
2020-06-01 20:39:44 -05:00
took := time . Since ( start )
2022-09-02 14:18:23 -05:00
if took > SlowTest {
2020-06-01 20:39:44 -05:00
if log . CanColorStdout {
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 ) ) )
} else {
2022-06-04 16:43:25 -05:00
fmt . Fprintf ( os . Stdout , "+++ %s is a slow test (took %v)\n" , t . Name ( ) , took )
2020-06-01 20:39:44 -05:00
}
}
2022-09-02 14:18:23 -05:00
timer := time . AfterFunc ( SlowFlush , func ( ) {
2020-06-01 20:39:44 -05:00
if log . CanColorStdout {
2022-09-02 14:18:23 -05:00
fmt . Fprintf ( os . Stdout , "+++ %s ... still flushing after %v ...\n" , fmt . Formatter ( log . NewColoredValue ( t . Name ( ) , log . Bold , log . FgRed ) ) , SlowFlush )
2020-06-01 20:39:44 -05:00
} else {
2022-09-02 14:18:23 -05:00
fmt . Fprintf ( os . Stdout , "+++ %s ... still flushing after %v ...\n" , t . Name ( ) , SlowFlush )
2020-06-01 20:39:44 -05:00
}
} )
2021-08-29 23:27:51 -05:00
if err := queue . GetManager ( ) . FlushAll ( context . Background ( ) , 2 * time . Minute ) ; err != nil {
2020-01-28 20:01:06 -05:00
t . Errorf ( "Flushing queues failed with error %v" , err )
}
2020-06-01 20:39:44 -05:00
timer . Stop ( )
flushTook := time . Since ( start ) - took
2022-09-02 14:18:23 -05:00
if flushTook > SlowFlush {
2020-06-01 20:39:44 -05:00
if log . CanColorStdout {
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 ) ) )
} else {
fmt . Fprintf ( os . Stdout , "+++ %s had a slow clean-up flush (took %v)\n" , t . Name ( ) , flushTook )
}
}
2022-09-02 14:18:23 -05:00
_ = WriterCloser . Close ( )
2019-11-25 18:21:37 -05:00
}
2019-04-06 19:25:14 -05:00
}
// Printf takes a format and args and prints the string to os.Stdout
func Printf ( format string , args ... interface { } ) {
if log . CanColorStdout {
for i := 0 ; i < len ( args ) ; i ++ {
args [ i ] = log . NewColoredValue ( args [ i ] )
}
}
fmt . Fprintf ( os . Stdout , "\t" + format , args ... )
}
// NewTestLogger creates a TestLogger as a log.LoggerProvider
func NewTestLogger ( ) log . LoggerProvider {
logger := & TestLogger { }
logger . Colorize = log . CanColorStdout
logger . Level = log . TRACE
return logger
}
// Init inits connection writer with json config.
// json config only need key "level".
func ( log * TestLogger ) Init ( config string ) error {
err := json . Unmarshal ( [ ] byte ( config ) , log )
if err != nil {
return err
}
2022-09-02 14:18:23 -05:00
log . NewWriterLogger ( WriterCloser )
2019-04-06 19:25:14 -05:00
return nil
}
2022-02-25 04:20:50 -05:00
// Content returns the content accumulated in the content provider
func ( log * TestLogger ) Content ( ) ( string , error ) {
return "" , fmt . Errorf ( "not supported" )
}
2019-04-06 19:25:14 -05:00
// Flush when log should be flushed
func ( log * TestLogger ) Flush ( ) {
}
2022-01-20 12:46:10 -05:00
// ReleaseReopen does nothing
2020-07-05 19:07:07 -05:00
func ( log * TestLogger ) ReleaseReopen ( ) error {
return nil
}
2019-04-06 19:25:14 -05:00
// GetName returns the default name for this implementation
func ( log * TestLogger ) GetName ( ) string {
return "test"
}
func init ( ) {
log . Register ( "test" , NewTestLogger )
_ , filename , _ , _ := runtime . Caller ( 0 )
2022-09-02 14:18:23 -05:00
prefix = strings . TrimSuffix ( filename , "tests/integration/testlogger.go" )
2019-04-06 19:25:14 -05:00
}