Skip to content

Commit 9119750

Browse files
authored
Improve test logger (#24235)
Before, there was a `log/buffer.go`, but that design is not general, and it introduces a lot of irrelevant `Content() (string, error) ` and `return "", fmt.Errorf("not supported")` . And the old `log/buffer.go` is difficult to use, developers have to write a lot of `Contains` and `Sleep` code. The new `LogChecker` is designed to be a general approach to help to assert some messages appearing or not appearing in logs.
1 parent 65fe0fb commit 9119750

File tree

13 files changed

+195
-214
lines changed

13 files changed

+195
-214
lines changed

models/migrations/base/testlogger.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,6 @@ func (log *TestLogger) Init(config string) error {
165165
return nil
166166
}
167167

168-
// Content returns the content accumulated in the content provider
169-
func (log *TestLogger) Content() (string, error) {
170-
return "", fmt.Errorf("not supported")
171-
}
172-
173168
// Flush when log should be flushed
174169
func (log *TestLogger) Flush() {
175170
}

modules/log/buffer.go

Lines changed: 0 additions & 71 deletions
This file was deleted.

modules/log/buffer_test.go

Lines changed: 0 additions & 63 deletions
This file was deleted.

modules/log/conn.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,6 @@ func (log *ConnLogger) Init(jsonconfig string) error {
118118
return nil
119119
}
120120

121-
// Content returns the content accumulated in the content provider
122-
func (log *ConnLogger) Content() (string, error) {
123-
return "", fmt.Errorf("not supported")
124-
}
125-
126121
// Flush does nothing for this implementation
127122
func (log *ConnLogger) Flush() {
128123
}

modules/log/console.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,6 @@ func (log *ConsoleLogger) Init(config string) error {
6565
return nil
6666
}
6767

68-
// Content returns the content accumulated in the content provider
69-
func (log *ConsoleLogger) Content() (string, error) {
70-
return "", fmt.Errorf("not supported")
71-
}
72-
7368
// Flush when log should be flushed
7469
func (log *ConsoleLogger) Flush() {
7570
}

modules/log/event.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -247,12 +247,6 @@ func (m *MultiChannelledLog) GetEventLogger(name string) EventLogger {
247247
return m.loggers[name]
248248
}
249249

250-
// GetEventProvider returns a sub logger provider content from this MultiChannelledLog
251-
func (m *MultiChannelledLog) GetLoggerProviderContent(name string) (string, error) {
252-
channelledLogger := m.GetEventLogger(name).(*ChannelledLog)
253-
return channelledLogger.loggerProvider.Content()
254-
}
255-
256250
// GetEventLoggerNames returns a list of names
257251
func (m *MultiChannelledLog) GetEventLoggerNames() []string {
258252
m.rwmutex.RLock()
@@ -460,3 +454,7 @@ func (m *MultiChannelledLog) ResetLevel() Level {
460454
func (m *MultiChannelledLog) GetName() string {
461455
return m.name
462456
}
457+
458+
func (e *Event) GetMsg() string {
459+
return e.msg
460+
}

modules/log/file.go

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -253,15 +253,6 @@ func (log *FileLogger) deleteOldLog() {
253253
})
254254
}
255255

256-
// Content returns the content accumulated in the content provider
257-
func (log *FileLogger) Content() (string, error) {
258-
b, err := os.ReadFile(log.Filename)
259-
if err != nil {
260-
return "", err
261-
}
262-
return string(b), nil
263-
}
264-
265256
// Flush flush file logger.
266257
// there are no buffering messages in file logger in memory.
267258
// flush file means sync file from disk.

modules/log/provider.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ package log
66
// LoggerProvider represents behaviors of a logger provider.
77
type LoggerProvider interface {
88
Init(config string) error
9-
Content() (string, error)
109
EventLogger
1110
}
1211

modules/log/smtp.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,6 @@ func (log *SMTPLogger) sendMail(p []byte) (int, error) {
9595
)
9696
}
9797

98-
// Content returns the content accumulated in the content provider
99-
func (log *SMTPLogger) Content() (string, error) {
100-
return "", fmt.Errorf("not supported")
101-
}
102-
10398
// Flush when log should be flushed
10499
func (log *SMTPLogger) Flush() {
105100
}

modules/test/logchecker.go

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package test
5+
6+
import (
7+
"strconv"
8+
"strings"
9+
"sync"
10+
"sync/atomic"
11+
"time"
12+
13+
"code.gitea.io/gitea/modules/log"
14+
)
15+
16+
type LogChecker struct {
17+
logger *log.MultiChannelledLogger
18+
loggerName string
19+
eventLoggerName string
20+
21+
filterMessages []string
22+
filtered []bool
23+
24+
stopMark string
25+
stopped bool
26+
27+
mu sync.Mutex
28+
}
29+
30+
func (lc *LogChecker) LogEvent(event *log.Event) error {
31+
lc.mu.Lock()
32+
defer lc.mu.Unlock()
33+
for i, msg := range lc.filterMessages {
34+
if strings.Contains(event.GetMsg(), msg) {
35+
lc.filtered[i] = true
36+
}
37+
}
38+
if strings.Contains(event.GetMsg(), lc.stopMark) {
39+
lc.stopped = true
40+
}
41+
return nil
42+
}
43+
44+
func (lc *LogChecker) Close() {}
45+
46+
func (lc *LogChecker) Flush() {}
47+
48+
func (lc *LogChecker) GetLevel() log.Level {
49+
return log.TRACE
50+
}
51+
52+
func (lc *LogChecker) GetStacktraceLevel() log.Level {
53+
return log.NONE
54+
}
55+
56+
func (lc *LogChecker) GetName() string {
57+
return lc.eventLoggerName
58+
}
59+
60+
func (lc *LogChecker) ReleaseReopen() error {
61+
return nil
62+
}
63+
64+
var checkerIndex int64
65+
66+
func NewLogChecker(loggerName string) (logChecker *LogChecker, cancel func()) {
67+
logger := log.GetLogger(loggerName)
68+
newCheckerIndex := atomic.AddInt64(&checkerIndex, 1)
69+
lc := &LogChecker{
70+
logger: logger,
71+
loggerName: loggerName,
72+
eventLoggerName: "TestLogChecker-" + strconv.FormatInt(newCheckerIndex, 10),
73+
}
74+
if err := logger.AddLogger(lc); err != nil {
75+
panic(err) // it's impossible
76+
}
77+
return lc, func() { _, _ = logger.DelLogger(lc.GetName()) }
78+
}
79+
80+
// Filter will make the `Check` function to check if these logs are outputted.
81+
func (lc *LogChecker) Filter(msgs ...string) *LogChecker {
82+
lc.mu.Lock()
83+
defer lc.mu.Unlock()
84+
lc.filterMessages = make([]string, len(msgs))
85+
copy(lc.filterMessages, msgs)
86+
lc.filtered = make([]bool, len(lc.filterMessages))
87+
return lc
88+
}
89+
90+
func (lc *LogChecker) StopMark(msg string) *LogChecker {
91+
lc.mu.Lock()
92+
defer lc.mu.Unlock()
93+
lc.stopMark = msg
94+
lc.stopped = false
95+
return lc
96+
}
97+
98+
// Check returns the filtered slice and whether the stop mark is reached.
99+
func (lc *LogChecker) Check(d time.Duration) (filtered []bool, stopped bool) {
100+
stop := time.Now().Add(d)
101+
102+
for {
103+
lc.mu.Lock()
104+
stopped = lc.stopped
105+
lc.mu.Unlock()
106+
107+
if time.Now().After(stop) || stopped {
108+
lc.mu.Lock()
109+
f := make([]bool, len(lc.filtered))
110+
copy(f, lc.filtered)
111+
lc.mu.Unlock()
112+
return f, stopped
113+
}
114+
time.Sleep(10 * time.Millisecond)
115+
}
116+
}

modules/test/logchecker_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package test
5+
6+
import (
7+
"testing"
8+
"time"
9+
10+
"code.gitea.io/gitea/modules/log"
11+
12+
"github.com/stretchr/testify/assert"
13+
)
14+
15+
func TestLogChecker(t *testing.T) {
16+
_ = log.NewLogger(1000, "console", "console", `{"level":"info","stacktracelevel":"NONE","stderr":true}`)
17+
18+
lc, cleanup := NewLogChecker(log.DEFAULT)
19+
defer cleanup()
20+
21+
lc.Filter("First", "Third").StopMark("End")
22+
log.Info("test")
23+
24+
filtered, stopped := lc.Check(100 * time.Millisecond)
25+
assert.EqualValues(t, []bool{false, false}, filtered)
26+
assert.EqualValues(t, false, stopped)
27+
28+
log.Info("First")
29+
filtered, stopped = lc.Check(100 * time.Millisecond)
30+
assert.EqualValues(t, []bool{true, false}, filtered)
31+
assert.EqualValues(t, false, stopped)
32+
33+
log.Info("Second")
34+
filtered, stopped = lc.Check(100 * time.Millisecond)
35+
assert.EqualValues(t, []bool{true, false}, filtered)
36+
assert.EqualValues(t, false, stopped)
37+
38+
log.Info("Third")
39+
filtered, stopped = lc.Check(100 * time.Millisecond)
40+
assert.EqualValues(t, []bool{true, true}, filtered)
41+
assert.EqualValues(t, false, stopped)
42+
43+
log.Info("End")
44+
filtered, stopped = lc.Check(100 * time.Millisecond)
45+
assert.EqualValues(t, []bool{true, true}, filtered)
46+
assert.EqualValues(t, true, stopped)
47+
}

0 commit comments

Comments
 (0)