github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/common/flogging/fabenc/formatter_test.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package fabenc_test 8 9 import ( 10 "bytes" 11 "fmt" 12 "runtime" 13 "strconv" 14 "sync" 15 "testing" 16 "time" 17 18 "github.com/hechain20/hechain/common/flogging/fabenc" 19 "github.com/stretchr/testify/require" 20 "go.uber.org/zap" 21 "go.uber.org/zap/zapcore" 22 ) 23 24 func TestParseFormat(t *testing.T) { 25 tests := []struct { 26 desc string 27 spec string 28 formatters []fabenc.Formatter 29 }{ 30 { 31 desc: "empty spec", 32 spec: "", 33 formatters: []fabenc.Formatter{}, 34 }, 35 { 36 desc: "simple verb", 37 spec: "%{color}", 38 formatters: []fabenc.Formatter{ 39 fabenc.ColorFormatter{}, 40 }, 41 }, 42 { 43 desc: "with prefix", 44 spec: "prefix %{color}", 45 formatters: []fabenc.Formatter{ 46 fabenc.StringFormatter{Value: "prefix "}, 47 fabenc.ColorFormatter{}, 48 }, 49 }, 50 { 51 desc: "with suffix", 52 spec: "%{color} suffix", 53 formatters: []fabenc.Formatter{ 54 fabenc.ColorFormatter{}, 55 fabenc.StringFormatter{Value: " suffix"}, 56 }, 57 }, 58 { 59 desc: "with prefix and suffix", 60 spec: "prefix %{color} suffix", 61 formatters: []fabenc.Formatter{ 62 fabenc.StringFormatter{Value: "prefix "}, 63 fabenc.ColorFormatter{}, 64 fabenc.StringFormatter{Value: " suffix"}, 65 }, 66 }, 67 { 68 desc: "with format", 69 spec: "%{level:.4s} suffix", 70 formatters: []fabenc.Formatter{ 71 fabenc.LevelFormatter{FormatVerb: "%.4s"}, 72 fabenc.StringFormatter{Value: " suffix"}, 73 }, 74 }, 75 } 76 77 for _, tc := range tests { 78 t.Run(fmt.Sprintf(tc.desc), func(t *testing.T) { 79 formatters, err := fabenc.ParseFormat(tc.spec) 80 require.NoError(t, err) 81 require.Equal(t, tc.formatters, formatters) 82 }) 83 } 84 } 85 86 func TestParseFormatError(t *testing.T) { 87 _, err := fabenc.ParseFormat("%{color:bad}") 88 require.EqualError(t, err, "invalid color option: bad") 89 } 90 91 func TestNewFormatter(t *testing.T) { 92 tests := []struct { 93 verb string 94 format string 95 formatter fabenc.Formatter 96 errorMsg string 97 }{ 98 {verb: "color", format: "", formatter: fabenc.ColorFormatter{}}, 99 {verb: "color", format: "bold", formatter: fabenc.ColorFormatter{Bold: true}}, 100 {verb: "color", format: "reset", formatter: fabenc.ColorFormatter{Reset: true}}, 101 {verb: "color", format: "unknown", errorMsg: "invalid color option: unknown"}, 102 {verb: "id", format: "", formatter: fabenc.SequenceFormatter{FormatVerb: "%d"}}, 103 {verb: "id", format: "04x", formatter: fabenc.SequenceFormatter{FormatVerb: "%04x"}}, 104 {verb: "level", format: "", formatter: fabenc.LevelFormatter{FormatVerb: "%s"}}, 105 {verb: "level", format: ".4s", formatter: fabenc.LevelFormatter{FormatVerb: "%.4s"}}, 106 {verb: "message", format: "", formatter: fabenc.MessageFormatter{FormatVerb: "%s"}}, 107 {verb: "message", format: "#30s", formatter: fabenc.MessageFormatter{FormatVerb: "%#30s"}}, 108 {verb: "module", format: "", formatter: fabenc.ModuleFormatter{FormatVerb: "%s"}}, 109 {verb: "module", format: "ok", formatter: fabenc.ModuleFormatter{FormatVerb: "%ok"}}, 110 {verb: "shortfunc", format: "", formatter: fabenc.ShortFuncFormatter{FormatVerb: "%s"}}, 111 {verb: "shortfunc", format: "U", formatter: fabenc.ShortFuncFormatter{FormatVerb: "%U"}}, 112 {verb: "time", format: "", formatter: fabenc.TimeFormatter{Layout: "2006-01-02T15:04:05.999Z07:00"}}, 113 {verb: "time", format: "04:05.999999Z05:00", formatter: fabenc.TimeFormatter{Layout: "04:05.999999Z05:00"}}, 114 {verb: "unknown", format: "", errorMsg: "unknown verb: unknown"}, 115 } 116 117 for i, tc := range tests { 118 t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { 119 f, err := fabenc.NewFormatter(tc.verb, tc.format) 120 if tc.errorMsg == "" { 121 require.NoError(t, err) 122 require.Equal(t, tc.formatter, f) 123 } else { 124 require.EqualError(t, err, tc.errorMsg) 125 } 126 }) 127 } 128 } 129 130 func TestColorFormatter(t *testing.T) { 131 tests := []struct { 132 f fabenc.ColorFormatter 133 level zapcore.Level 134 formatted string 135 }{ 136 {f: fabenc.ColorFormatter{Reset: true}, level: zapcore.DebugLevel, formatted: fabenc.ResetColor()}, 137 {f: fabenc.ColorFormatter{}, level: zapcore.DebugLevel, formatted: fabenc.ColorCyan.Normal()}, 138 {f: fabenc.ColorFormatter{Bold: true}, level: zapcore.DebugLevel, formatted: fabenc.ColorCyan.Bold()}, 139 {f: fabenc.ColorFormatter{}, level: zapcore.InfoLevel, formatted: fabenc.ColorBlue.Normal()}, 140 {f: fabenc.ColorFormatter{Bold: true}, level: zapcore.InfoLevel, formatted: fabenc.ColorBlue.Bold()}, 141 {f: fabenc.ColorFormatter{}, level: zapcore.WarnLevel, formatted: fabenc.ColorYellow.Normal()}, 142 {f: fabenc.ColorFormatter{Bold: true}, level: zapcore.WarnLevel, formatted: fabenc.ColorYellow.Bold()}, 143 {f: fabenc.ColorFormatter{}, level: zapcore.ErrorLevel, formatted: fabenc.ColorRed.Normal()}, 144 {f: fabenc.ColorFormatter{Bold: true}, level: zapcore.ErrorLevel, formatted: fabenc.ColorRed.Bold()}, 145 {f: fabenc.ColorFormatter{}, level: zapcore.DPanicLevel, formatted: fabenc.ColorMagenta.Normal()}, 146 {f: fabenc.ColorFormatter{Bold: true}, level: zapcore.DPanicLevel, formatted: fabenc.ColorMagenta.Bold()}, 147 {f: fabenc.ColorFormatter{}, level: zapcore.PanicLevel, formatted: fabenc.ColorMagenta.Normal()}, 148 {f: fabenc.ColorFormatter{Bold: true}, level: zapcore.PanicLevel, formatted: fabenc.ColorMagenta.Bold()}, 149 {f: fabenc.ColorFormatter{}, level: zapcore.FatalLevel, formatted: fabenc.ColorMagenta.Normal()}, 150 {f: fabenc.ColorFormatter{Bold: true}, level: zapcore.FatalLevel, formatted: fabenc.ColorMagenta.Bold()}, 151 {f: fabenc.ColorFormatter{}, level: zapcore.Level(99), formatted: fabenc.ColorNone.Normal()}, 152 {f: fabenc.ColorFormatter{Bold: true}, level: zapcore.Level(99), formatted: fabenc.ColorNone.Normal()}, 153 } 154 155 for i, tc := range tests { 156 t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { 157 buf := &bytes.Buffer{} 158 entry := zapcore.Entry{Level: tc.level} 159 tc.f.Format(buf, entry, nil) 160 require.Equal(t, tc.formatted, buf.String()) 161 }) 162 } 163 } 164 165 func TestLevelFormatter(t *testing.T) { 166 tests := []struct { 167 level zapcore.Level 168 formatted string 169 }{ 170 {level: zapcore.DebugLevel, formatted: "DEBUG"}, 171 {level: zapcore.InfoLevel, formatted: "INFO"}, 172 {level: zapcore.WarnLevel, formatted: "WARN"}, 173 {level: zapcore.ErrorLevel, formatted: "ERROR"}, 174 {level: zapcore.DPanicLevel, formatted: "DPANIC"}, 175 {level: zapcore.PanicLevel, formatted: "PANIC"}, 176 {level: zapcore.FatalLevel, formatted: "FATAL"}, 177 {level: zapcore.Level(99), formatted: "LEVEL(99)"}, 178 } 179 180 for i, tc := range tests { 181 t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { 182 buf := &bytes.Buffer{} 183 entry := zapcore.Entry{Level: tc.level} 184 fabenc.LevelFormatter{FormatVerb: "%s"}.Format(buf, entry, nil) 185 require.Equal(t, tc.formatted, buf.String()) 186 }) 187 } 188 } 189 190 func TestMessageFormatter(t *testing.T) { 191 buf := &bytes.Buffer{} 192 entry := zapcore.Entry{Message: "some message text \n\n"} 193 f := fabenc.MessageFormatter{FormatVerb: "%s"} 194 f.Format(buf, entry, nil) 195 require.Equal(t, "some message text ", buf.String()) 196 } 197 198 func TestModuleFormatter(t *testing.T) { 199 buf := &bytes.Buffer{} 200 entry := zapcore.Entry{LoggerName: "logger/name"} 201 f := fabenc.ModuleFormatter{FormatVerb: "%s"} 202 f.Format(buf, entry, nil) 203 require.Equal(t, "logger/name", buf.String()) 204 } 205 206 func TestSequenceFormatter(t *testing.T) { 207 mutex := &sync.Mutex{} 208 results := map[string]struct{}{} 209 210 ready := &sync.WaitGroup{} 211 ready.Add(100) 212 213 finished := &sync.WaitGroup{} 214 finished.Add(100) 215 216 fabenc.SetSequence(0) 217 for i := 1; i <= 100; i++ { 218 go func(i int) { 219 buf := &bytes.Buffer{} 220 entry := zapcore.Entry{Level: zapcore.DebugLevel} 221 f := fabenc.SequenceFormatter{FormatVerb: "%d"} 222 ready.Done() // setup complete 223 ready.Wait() // wait for all go routines to be ready 224 225 f.Format(buf, entry, nil) // format concurrently 226 227 mutex.Lock() 228 results[buf.String()] = struct{}{} 229 mutex.Unlock() 230 231 finished.Done() 232 }(i) 233 } 234 235 finished.Wait() 236 for i := 1; i <= 100; i++ { 237 require.Contains(t, results, strconv.Itoa(i)) 238 } 239 } 240 241 func TestShortFuncFormatter(t *testing.T) { 242 callerpc, _, _, ok := runtime.Caller(0) 243 require.True(t, ok) 244 buf := &bytes.Buffer{} 245 entry := zapcore.Entry{Caller: zapcore.EntryCaller{PC: callerpc}} 246 fabenc.ShortFuncFormatter{FormatVerb: "%s"}.Format(buf, entry, nil) 247 require.Equal(t, "TestShortFuncFormatter", buf.String()) 248 249 buf = &bytes.Buffer{} 250 entry = zapcore.Entry{Caller: zapcore.EntryCaller{PC: 0}} 251 fabenc.ShortFuncFormatter{FormatVerb: "%s"}.Format(buf, entry, nil) 252 require.Equal(t, "(unknown)", buf.String()) 253 } 254 255 func TestTimeFormatter(t *testing.T) { 256 buf := &bytes.Buffer{} 257 entry := zapcore.Entry{Time: time.Date(1975, time.August, 15, 12, 0, 0, 333, time.UTC)} 258 f := fabenc.TimeFormatter{Layout: time.RFC3339Nano} 259 f.Format(buf, entry, nil) 260 require.Equal(t, "1975-08-15T12:00:00.000000333Z", buf.String()) 261 } 262 263 func TestMultiFormatter(t *testing.T) { 264 entry := zapcore.Entry{ 265 Message: "message", 266 Level: zapcore.InfoLevel, 267 } 268 fields := []zapcore.Field{ 269 zap.String("name", "value"), 270 } 271 272 tests := []struct { 273 desc string 274 initial []fabenc.Formatter 275 update []fabenc.Formatter 276 expected string 277 }{ 278 { 279 desc: "no formatters", 280 initial: nil, 281 update: nil, 282 expected: "", 283 }, 284 { 285 desc: "initial formatters", 286 initial: []fabenc.Formatter{fabenc.StringFormatter{Value: "string1"}}, 287 update: nil, 288 expected: "string1", 289 }, 290 { 291 desc: "set to formatters", 292 initial: []fabenc.Formatter{fabenc.StringFormatter{Value: "string1"}}, 293 update: []fabenc.Formatter{ 294 fabenc.StringFormatter{Value: "string1"}, 295 fabenc.StringFormatter{Value: "-"}, 296 fabenc.StringFormatter{Value: "string2"}, 297 }, 298 expected: "string1-string2", 299 }, 300 { 301 desc: "set to empty", 302 initial: []fabenc.Formatter{fabenc.StringFormatter{Value: "string1"}}, 303 update: []fabenc.Formatter{}, 304 expected: "", 305 }, 306 } 307 308 for _, tc := range tests { 309 mf := fabenc.NewMultiFormatter(tc.initial...) 310 if tc.update != nil { 311 mf.SetFormatters(tc.update) 312 } 313 314 buf := &bytes.Buffer{} 315 mf.Format(buf, entry, fields) 316 require.Equal(t, tc.expected, buf.String()) 317 } 318 }