/* * * Copyright 2018 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package binarylog import ( "fmt" "testing" ) // This tests that when multiple configs are specified, all methods loggers will // be set correctly. Correctness of each logger is covered by other unit tests. func TestNewLoggerFromConfigString(t *testing.T) { const ( s1 = "s1" m1 = "m1" m2 = "m2" fullM1 = s1 + "/" + m1 fullM2 = s1 + "/" + m2 ) c := fmt.Sprintf("*{h:1;m:2},%s{h},%s{m},%s{h;m}", s1+"/*", fullM1, fullM2) l := NewLoggerFromConfigString(c).(*logger) if l.all.hdr != 1 || l.all.msg != 2 { t.Errorf("l.all = %#v, want headerLen: 1, messageLen: 2", l.all) } if ml, ok := l.services[s1]; ok { if ml.hdr != maxUInt || ml.msg != 0 { t.Errorf("want maxUInt header, 0 message, got header: %v, message: %v", ml.hdr, ml.msg) } } else { t.Errorf("service/* is not set") } if ml, ok := l.methods[fullM1]; ok { if ml.hdr != 0 || ml.msg != maxUInt { t.Errorf("want 0 header, maxUInt message, got header: %v, message: %v", ml.hdr, ml.msg) } } else { t.Errorf("service/method{h} is not set") } if ml, ok := l.methods[fullM2]; ok { if ml.hdr != maxUInt || ml.msg != maxUInt { t.Errorf("want maxUInt header, maxUInt message, got header: %v, message: %v", ml.hdr, ml.msg) } } else { t.Errorf("service/method{h;m} is not set") } } func TestNewLoggerFromConfigStringInvalid(t *testing.T) { testCases := []string{ "", "*{}", "s/m,*{}", "s/m,s/m{a}", // Duplciate rules. "s/m,-s/m", "-s/m,s/m", "s/m,s/m", "s/m,s/m{h:1;m:1}", "s/m{h:1;m:1},s/m", "-s/m,-s/m", "s/*,s/*{h:1;m:1}", "*,*{h:1;m:1}", } for _, tc := range testCases { l := NewLoggerFromConfigString(tc) if l != nil { t.Errorf("With config %q, want logger %v, got %v", tc, nil, l) } } } func TestParseMethodConfigAndSuffix(t *testing.T) { testCases := []struct { in, service, method, suffix string }{ { in: "p.s/m", service: "p.s", method: "m", suffix: "", }, { in: "p.s/m{h,m}", service: "p.s", method: "m", suffix: "{h,m}", }, { in: "p.s/*", service: "p.s", method: "*", suffix: "", }, { in: "p.s/*{h,m}", service: "p.s", method: "*", suffix: "{h,m}", }, // invalid suffix will be detected by another function. { in: "p.s/m{invalidsuffix}", service: "p.s", method: "m", suffix: "{invalidsuffix}", }, { in: "p.s/*{invalidsuffix}", service: "p.s", method: "*", suffix: "{invalidsuffix}", }, { in: "s/m*", service: "s", method: "m", suffix: "*", }, { in: "s/*m", service: "s", method: "*", suffix: "m", }, { in: "s/**", service: "s", method: "*", suffix: "*", }, } for _, tc := range testCases { t.Logf("testing parseMethodConfigAndSuffix(%q)", tc.in) s, m, suffix, err := parseMethodConfigAndSuffix(tc.in) if err != nil { t.Errorf("returned error %v, want nil", err) continue } if s != tc.service { t.Errorf("service = %q, want %q", s, tc.service) } if m != tc.method { t.Errorf("method = %q, want %q", m, tc.method) } if suffix != tc.suffix { t.Errorf("suffix = %q, want %q", suffix, tc.suffix) } } } func TestParseMethodConfigAndSuffixInvalid(t *testing.T) { testCases := []string{ "*/m", "*/m{}", } for _, tc := range testCases { s, m, suffix, err := parseMethodConfigAndSuffix(tc) if err == nil { t.Errorf("Parsing %q got nil error with %q, %q, %q, want non-nil error", tc, s, m, suffix) } } } func TestParseHeaderMessageLengthConfig(t *testing.T) { testCases := []struct { in string hdr, msg uint64 }{ { in: "", hdr: maxUInt, msg: maxUInt, }, { in: "{h}", hdr: maxUInt, msg: 0, }, { in: "{h:314}", hdr: 314, msg: 0, }, { in: "{m}", hdr: 0, msg: maxUInt, }, { in: "{m:213}", hdr: 0, msg: 213, }, { in: "{h;m}", hdr: maxUInt, msg: maxUInt, }, { in: "{h:314;m}", hdr: 314, msg: maxUInt, }, { in: "{h;m:213}", hdr: maxUInt, msg: 213, }, { in: "{h:314;m:213}", hdr: 314, msg: 213, }, } for _, tc := range testCases { t.Logf("testing parseHeaderMessageLengthConfig(%q)", tc.in) hdr, msg, err := parseHeaderMessageLengthConfig(tc.in) if err != nil { t.Errorf("returned error %v, want nil", err) continue } if hdr != tc.hdr { t.Errorf("header length = %v, want %v", hdr, tc.hdr) } if msg != tc.msg { t.Errorf("message length = %v, want %v", msg, tc.msg) } } } func TestParseHeaderMessageLengthConfigInvalid(t *testing.T) { testCases := []string{ "{}", "{h;a}", "{h;m;b}", } for _, tc := range testCases { _, _, err := parseHeaderMessageLengthConfig(tc) if err == nil { t.Errorf("Parsing %q got nil error, want non-nil error", tc) } } } func TestFillMethodLoggerWithConfigStringBlacklist(t *testing.T) { testCases := []string{ "p.s/m", "service/method", } for _, tc := range testCases { c := "-" + tc t.Logf("testing fillMethodLoggerWithConfigString(%q)", c) l := newEmptyLogger() if err := l.fillMethodLoggerWithConfigString(c); err != nil { t.Errorf("returned err %v, want nil", err) continue } _, ok := l.blacklist[tc] if !ok { t.Errorf("blacklist[%q] is not set", tc) } } } func TestFillMethodLoggerWithConfigStringGlobal(t *testing.T) { testCases := []struct { in string hdr, msg uint64 }{ { in: "", hdr: maxUInt, msg: maxUInt, }, { in: "{h}", hdr: maxUInt, msg: 0, }, { in: "{h:314}", hdr: 314, msg: 0, }, { in: "{m}", hdr: 0, msg: maxUInt, }, { in: "{m:213}", hdr: 0, msg: 213, }, { in: "{h;m}", hdr: maxUInt, msg: maxUInt, }, { in: "{h:314;m}", hdr: 314, msg: maxUInt, }, { in: "{h;m:213}", hdr: maxUInt, msg: 213, }, { in: "{h:314;m:213}", hdr: 314, msg: 213, }, } for _, tc := range testCases { c := "*" + tc.in t.Logf("testing fillMethodLoggerWithConfigString(%q)", c) l := newEmptyLogger() if err := l.fillMethodLoggerWithConfigString(c); err != nil { t.Errorf("returned err %v, want nil", err) continue } if l.all == nil { t.Errorf("l.all is not set") continue } if hdr := l.all.hdr; hdr != tc.hdr { t.Errorf("header length = %v, want %v", hdr, tc.hdr) } if msg := l.all.msg; msg != tc.msg { t.Errorf("message length = %v, want %v", msg, tc.msg) } } } func TestFillMethodLoggerWithConfigStringPerService(t *testing.T) { testCases := []struct { in string hdr, msg uint64 }{ { in: "", hdr: maxUInt, msg: maxUInt, }, { in: "{h}", hdr: maxUInt, msg: 0, }, { in: "{h:314}", hdr: 314, msg: 0, }, { in: "{m}", hdr: 0, msg: maxUInt, }, { in: "{m:213}", hdr: 0, msg: 213, }, { in: "{h;m}", hdr: maxUInt, msg: maxUInt, }, { in: "{h:314;m}", hdr: 314, msg: maxUInt, }, { in: "{h;m:213}", hdr: maxUInt, msg: 213, }, { in: "{h:314;m:213}", hdr: 314, msg: 213, }, } const serviceName = "service" for _, tc := range testCases { c := serviceName + "/*" + tc.in t.Logf("testing fillMethodLoggerWithConfigString(%q)", c) l := newEmptyLogger() if err := l.fillMethodLoggerWithConfigString(c); err != nil { t.Errorf("returned err %v, want nil", err) continue } ml, ok := l.services[serviceName] if !ok { t.Errorf("l.service[%q] is not set", serviceName) continue } if hdr := ml.hdr; hdr != tc.hdr { t.Errorf("header length = %v, want %v", hdr, tc.hdr) } if msg := ml.msg; msg != tc.msg { t.Errorf("message length = %v, want %v", msg, tc.msg) } } } func TestFillMethodLoggerWithConfigStringPerMethod(t *testing.T) { testCases := []struct { in string hdr, msg uint64 }{ { in: "", hdr: maxUInt, msg: maxUInt, }, { in: "{h}", hdr: maxUInt, msg: 0, }, { in: "{h:314}", hdr: 314, msg: 0, }, { in: "{m}", hdr: 0, msg: maxUInt, }, { in: "{m:213}", hdr: 0, msg: 213, }, { in: "{h;m}", hdr: maxUInt, msg: maxUInt, }, { in: "{h:314;m}", hdr: 314, msg: maxUInt, }, { in: "{h;m:213}", hdr: maxUInt, msg: 213, }, { in: "{h:314;m:213}", hdr: 314, msg: 213, }, } const ( serviceName = "service" methodName = "method" fullMethodName = serviceName + "/" + methodName ) for _, tc := range testCases { c := fullMethodName + tc.in t.Logf("testing fillMethodLoggerWithConfigString(%q)", c) l := newEmptyLogger() if err := l.fillMethodLoggerWithConfigString(c); err != nil { t.Errorf("returned err %v, want nil", err) continue } ml, ok := l.methods[fullMethodName] if !ok { t.Errorf("l.methods[%q] is not set", fullMethodName) continue } if hdr := ml.hdr; hdr != tc.hdr { t.Errorf("header length = %v, want %v", hdr, tc.hdr) } if msg := ml.msg; msg != tc.msg { t.Errorf("message length = %v, want %v", msg, tc.msg) } } } func TestFillMethodLoggerWithConfigStringInvalid(t *testing.T) { testCases := []string{ "", "{}", "p.s/m{}", "p.s/m{a}", "p.s/m*", "p.s/**", "*/m", "-p.s/*", "-p.s/m{h}", } l := &logger{} for _, tc := range testCases { if err := l.fillMethodLoggerWithConfigString(tc); err == nil { t.Errorf("fillMethodLoggerWithConfigString(%q) returned nil error, want non-nil", tc) } } }