forked from saiya/dsps
/
testing.go
136 lines (114 loc) · 2.9 KB
/
testing.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package logger
import (
"context"
"sync"
"testing"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"go.uber.org/zap/zaptest"
)
// LogCapture represents log capture system for testing purpose
type LogCapture struct {
lock sync.Mutex
logEntries []CapturedLog
}
func (c *LogCapture) append(logEntry CapturedLog) {
c.lock.Lock()
defer c.lock.Unlock()
c.logEntries = append(c.logEntries, logEntry)
}
// LastLog returns captured log
func (c *LogCapture) LastLog(offset int) *CapturedLog {
c.lock.Lock()
defer c.lock.Unlock()
return &c.logEntries[len(c.logEntries)-1-offset]
}
// Count returns total count of captured logs
func (c *LogCapture) Count() int {
c.lock.Lock()
defer c.lock.Unlock()
return len(c.logEntries)
}
// CapturedLog represents captured log object
type CapturedLog struct {
zapcore.Entry
Fields []zapcore.Field
}
// FindErrorField returns error field of the log or nil
func (log CapturedLog) FindErrorField() error {
for _, f := range log.Fields {
if err, ok := f.Interface.(error); ok && f.Type == zapcore.ErrorType {
return err
}
}
return nil
}
// FindStringField string field of the given name
func (log CapturedLog) FindStringField(key string) string {
for _, f := range log.Fields {
if f.Key == key && f.Type == zapcore.StringType {
return f.String
}
}
return ""
}
// WithTestLogger swaps global logger for testing only.
func WithTestLogger(t *testing.T, filter *Filter, f func(lc *LogCapture)) {
var prev *loggerImpl
defer func() {
rootLoggerLock.Lock()
defer rootLoggerLock.Unlock()
rootLogger = prev
}()
lc := LogCapture{}
func() {
rootLoggerLock.Lock()
defer rootLoggerLock.Unlock()
prev = rootLogger
if filter == nil {
filter = rootLogger.filter
}
// based on uber-go/fx Sentry example: https://github.com/uber-go/zap/issues/418#issuecomment-438323524
logger := zaptest.NewLogger(t).WithOptions(zap.WrapCore(func(z zapcore.Core) zapcore.Core {
return zapcore.NewTee(z, lc.createZapCore())
}))
rootLogger = &loggerImpl{
ctx: context.Background(),
zap: logger,
filter: filter,
}
}()
f(&lc)
}
type logCaptureZapCore struct {
*LogCapture
fields []zapcore.Field
}
func (c *LogCapture) createZapCore() zapcore.Core {
return &logCaptureZapCore{LogCapture: c}
}
func (c *logCaptureZapCore) Sync() error {
return nil
}
func (c *logCaptureZapCore) Check(ent zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry {
if c.Enabled(ent.Level) {
return ce.AddCore(ent, c)
}
return ce
}
func (c *logCaptureZapCore) Write(entry zapcore.Entry, fields []zapcore.Field) error {
c.append(CapturedLog{
Entry: entry,
Fields: append(c.fields, fields...),
})
return nil
}
func (c *logCaptureZapCore) With(fields []zapcore.Field) zapcore.Core {
return &logCaptureZapCore{
LogCapture: c.LogCapture,
fields: append(c.fields, fields...),
}
}
func (c *logCaptureZapCore) Enabled(level zapcore.Level) bool {
return true
}