-
Notifications
You must be signed in to change notification settings - Fork 14
/
test_util.go
169 lines (138 loc) · 4.53 KB
/
test_util.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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
package testutil
import (
"context"
"time"
"github.com/anz-bank/sysl-go/config"
"github.com/anz-bank/sysl-go/log"
)
type TestLogEntries struct {
Entries []TestLogEntry
}
// The TestLogger is an implementation of log.Logger suitable for use within unit tests.
// Provision with NewTestLogger or NewTestContext.
type TestLogger struct {
Level log.Level
Fields map[string]interface{}
entries *TestLogEntries // shared entries
}
type TestLogEntry struct {
Level log.Level
Message string
Error error
Fields map[string]interface{}
}
func NewTestLogger() *TestLogger {
return &TestLogger{Level: log.InfoLevel, entries: &TestLogEntries{}}
}
func (l *TestLogger) Entries() []TestLogEntry {
return l.entries.Entries
}
func (l *TestLogger) EntryCount() int {
return len(l.entries.Entries)
}
func (l *TestLogger) Error(err error, message string) { l.log(log.ErrorLevel, err, message) }
func (l *TestLogger) Info(message string) { l.log(log.InfoLevel, nil, message) }
func (l *TestLogger) Debug(message string) { l.log(log.DebugLevel, nil, message) }
func (l *TestLogger) log(level log.Level, err error, message string) {
if l.Level >= level {
l.entries.Entries = append(l.entries.Entries, TestLogEntry{
Level: level,
Message: message,
Error: err,
Fields: l.copyFields(),
})
}
}
func (l *TestLogger) WithStr(key string, value string) log.Logger {
return l.withField(key, value)
}
func (l *TestLogger) WithInt(key string, value int) log.Logger {
return l.withField(key, value)
}
func (l *TestLogger) WithDuration(key string, value time.Duration) log.Logger {
return l.withField(key, value)
}
func (l *TestLogger) withField(key string, value interface{}) log.Logger {
fields := l.copyFields()
fields[key] = value
return &TestLogger{l.Level, fields, l.entries}
}
func (l *TestLogger) WithLevel(level log.Level) log.Logger {
return &TestLogger{level, l.Fields, l.entries}
}
func (l *TestLogger) Inject(ctx context.Context) (context.Context, func(ctx context.Context) log.Logger) {
return ctx, func(_ context.Context) log.Logger { return l } // return single instance
}
func (l *TestLogger) copyFields() map[string]interface{} {
fields := make(map[string]interface{})
for key, value := range l.Fields {
fields[key] = value
}
return fields
}
func (l *TestLogger) LastEntry() *TestLogEntry {
if len(l.entries.Entries) == 0 {
return nil
}
return &l.entries.Entries[len(l.entries.Entries)-1]
}
// TestContextOpt is an interface to help configure the test context.
type TestContextOpt interface {
Apply(ctx context.Context) context.Context
}
// NewTestContext returns a context suitable for use within unit tests.
// The context comes equipped with the following:
// 1. Logger
// To modify the test context further, pass additional TestContextOpt values.
func NewTestContext(opts ...TestContextOpt) context.Context {
ctx, _ := NewTestContextWithLogger(opts...)
return ctx
}
// NewTestContext returns a context (and logger) suitable for use within unit tests.
// The context comes equipped with the following:
// 1. Logger
// To modify the test context further, pass additional TestContextOpt values.
func NewTestContextWithLogger(opts ...TestContextOpt) (context.Context, *TestLogger) {
ctx := log.PutLogger(context.Background(), NewTestLogger())
for _, o := range opts {
ctx = o.Apply(ctx)
}
logger := log.GetLogger(ctx)
return ctx, logger.(*TestLogger)
}
// WithLogLevel returns a TestContextOpt that sets the log level within the test context.
func WithLogLevel(level log.Level) TestContextOpt {
return &withLogLevel{level}
}
type withLogLevel struct {
level log.Level
}
func (w *withLogLevel) Apply(ctx context.Context) context.Context {
return log.WithLevel(ctx, w.level)
}
// WithConfig returns a TestContextOpt that adds the given configuration into the test context.
func WithConfig(cfg *config.DefaultConfig) TestContextOpt {
return &withConfig{cfg}
}
type withConfig struct {
cfg *config.DefaultConfig
}
func (w *withConfig) Apply(ctx context.Context) context.Context {
return config.PutDefaultConfig(ctx, w.cfg)
}
// WithLogPayload returns a TestContextOpt that sets the configuration option within the
// test context to log the payload contents or not.
func WithLogPayload(log bool) TestContextOpt {
return &withLogPayload{log}
}
type withLogPayload struct {
log bool
}
func (w *withLogPayload) Apply(ctx context.Context) context.Context {
cfg := config.GetDefaultConfig(ctx)
if cfg == nil {
cfg = &config.DefaultConfig{}
}
cfg.Library.Log.LogPayload = w.log
return config.PutDefaultConfig(ctx, cfg)
}