mirror of
https://github.com/percona/percona-toolkit.git
synced 2025-09-22 20:19:00 +00:00
171 lines
5.8 KiB
Go
171 lines
5.8 KiB
Go
package regex
|
|
|
|
import (
|
|
"io/ioutil"
|
|
"os/exec"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/davecgh/go-spew/spew"
|
|
"github.com/google/go-cmp/cmp"
|
|
"github.com/google/go-cmp/cmp/cmpopts"
|
|
"github.com/percona/percona-toolkit/src/go/pt-galera-log-explainer/translate"
|
|
"github.com/percona/percona-toolkit/src/go/pt-galera-log-explainer/types"
|
|
"github.com/percona/percona-toolkit/src/go/pt-galera-log-explainer/utils"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
type regexTestState struct {
|
|
State string
|
|
LogCtx types.LogCtx
|
|
HashToNodeNames map[string]string
|
|
HashToIP map[string]string
|
|
IPToMethods map[string]string
|
|
IPToNodeNames map[string]string
|
|
}
|
|
|
|
type regexTest struct {
|
|
name string
|
|
log, expectedOut string
|
|
input regexTestState
|
|
expected regexTestState
|
|
displayerExpectedNil bool
|
|
expectedErr bool
|
|
key string
|
|
}
|
|
|
|
func iterateRegexTest(t *testing.T, regexmap types.RegexMap, tests []regexTest) {
|
|
utils.SkipColor = true
|
|
for _, test := range tests {
|
|
if test.name == "" {
|
|
test.name = "default"
|
|
}
|
|
|
|
// Test 1
|
|
// it's defined in maps
|
|
if _, ok := regexmap[test.key]; !ok {
|
|
t.Fatalf("key %s does not exist in maps", test.key)
|
|
}
|
|
|
|
// Add the "input" translations
|
|
// some regexes will react on current state of translations
|
|
translate.ResetDB()
|
|
for hash, nodename := range test.input.HashToNodeNames {
|
|
translate.AddHashToNodeName(hash, nodename, time.Time{})
|
|
}
|
|
for hash, ip := range test.input.HashToIP {
|
|
translate.AddHashToIP(hash, ip, time.Time{})
|
|
}
|
|
for ip, methods := range test.input.IPToMethods {
|
|
translate.AddIPToMethod(ip, methods, time.Time{})
|
|
}
|
|
for ip, nodename := range test.input.IPToNodeNames {
|
|
translate.AddIPToNodeName(ip, nodename, time.Time{})
|
|
}
|
|
|
|
// Test 2
|
|
// Launch the test against grep on tmp file
|
|
err := testRegexFromMap(t, test.log, regexmap[test.key])
|
|
if err != nil {
|
|
if test.expectedErr {
|
|
continue
|
|
}
|
|
t.Fatalf("key: %s\ntestname: %s\nregex string: \"%s\"\nlog: %s\n", test.key, test.name, regexmap[test.key].Regex.String(), err)
|
|
}
|
|
|
|
if test.input.State != "" {
|
|
test.input.LogCtx.SetState(test.input.State)
|
|
}
|
|
|
|
// Test 3
|
|
// Get the message to display using the input context
|
|
logCtx, displayer := regexmap[test.key].Handle(test.input.LogCtx, test.log, time.Time{})
|
|
msg := ""
|
|
if displayer != nil {
|
|
msg = displayer(logCtx)
|
|
} else if !test.displayerExpectedNil {
|
|
t.Errorf("key: %s\ntestname: %s\ndisplayer is nil\nexpected: not nil", test.key, test.name)
|
|
}
|
|
|
|
// Test 4
|
|
// Making sure the updated context is what we expect
|
|
|
|
// alternative to reflect.deepequal, it enables to avoid comparing "states" map
|
|
res := cmp.Equal(logCtx, test.expected.LogCtx, cmpopts.IgnoreUnexported(types.LogCtx{}))
|
|
if !res || logCtx.State() != test.expected.State {
|
|
t.Errorf("context is not as expected: \nkey: %s\ntestname: %s\nlogCtx: %+v\nexpected logCtx: %+v\nout: %s\nexpected out: %s\nstate: %s\nexpected state: %s", test.key, test.name, spew.Sdump(logCtx), spew.Sdump(test.expected.LogCtx), msg, test.expectedOut, logCtx.State(), test.expected.State)
|
|
t.Fail()
|
|
}
|
|
|
|
// Test 5
|
|
// Making sure the displayed message is correct
|
|
if msg != test.expectedOut {
|
|
t.Errorf("displayed message is not as expected: \nkey: %s\ntestname: %s\nlogCtx: %+v\nout: %s\nexpected out: %s\nstate: %s", test.key, test.name, spew.Sdump(logCtx), msg, test.expectedOut, logCtx.State())
|
|
t.Fail()
|
|
}
|
|
|
|
// Test 6
|
|
// Making sure the translations map have the expected values
|
|
// There is a limitation here: "extra" translations stored will not be seen
|
|
maxTime, _ := time.Parse(time.RFC3339, "2100-01-01T01:01:01Z")
|
|
for hash, expectedValue := range test.expected.HashToNodeNames {
|
|
if value := translate.GetNodeNameFromHash(hash, maxTime); value != expectedValue {
|
|
t.Errorf("wrong HashToNodeNames\ntest key: %s\ntestname: %s\nlogCtx: %+v\nout: %s\nhash: %s\nexpectedValue: %s\nvalue: %s", test.key, test.name, spew.Sdump(logCtx), msg, hash, expectedValue, value)
|
|
t.Fail()
|
|
}
|
|
}
|
|
for hash, expectedValue := range test.expected.HashToIP {
|
|
if value := translate.GetIPFromHash(hash); value != expectedValue {
|
|
t.Errorf("wrong HashToIP\ntest key: %s\ntestname: %s\nlogCtx: %+v\nout: %s\nhash: %s\nexpectedValue: %s\nvalue: %s", test.key, test.name, spew.Sdump(logCtx), msg, hash, expectedValue, value)
|
|
t.Fail()
|
|
}
|
|
}
|
|
for ip, expectedValue := range test.expected.IPToMethods {
|
|
if value := translate.GetMethodFromIP(ip, maxTime); value != expectedValue {
|
|
t.Errorf("wrong IPToMethods\ntest key: %s\ntestname: %s\nlogCtx: %+v\nout: %s\nhash: %s\nexpectedValue: %s\nvalue: %s", test.key, test.name, spew.Sdump(logCtx), msg, ip, expectedValue, value)
|
|
t.Fail()
|
|
}
|
|
}
|
|
for ip, expectedValue := range test.expected.IPToNodeNames {
|
|
if value := translate.GetNodeNameFromIP(ip, maxTime); value != expectedValue {
|
|
t.Errorf("wrong IPToNodeNames\ntest key: %s\ntestname: %s\nlogCtx: %+v\nout: %s\nhash: %s\nexpectedValue: %s\nvalue: %s", test.key, test.name, spew.Sdump(logCtx), msg, ip, expectedValue, value)
|
|
t.Fail()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func timeMustParse(s string) *time.Time {
|
|
t, _, _ := SearchDateFromLog(s)
|
|
return &t
|
|
}
|
|
|
|
func testRegexFromMap(t *testing.T, log string, regex *types.LogRegex) error {
|
|
m := types.RegexMap{"test": regex}
|
|
|
|
return testActualGrepOnLog(t, log, m.Compile()[0])
|
|
}
|
|
|
|
func testActualGrepOnLog(t *testing.T, log, regex string) error {
|
|
|
|
f, err := ioutil.TempFile(t.TempDir(), "test_log")
|
|
if err != nil {
|
|
return errors.Wrap(err, "failed to create tmp file")
|
|
}
|
|
defer f.Sync()
|
|
|
|
_, err = f.WriteString(log)
|
|
if err != nil {
|
|
return errors.Wrap(err, "failed to write in tmp file")
|
|
}
|
|
|
|
out, err := exec.Command("grep", "-P", regex, f.Name()).Output()
|
|
if err != nil {
|
|
return errors.Wrap(err, "failed to grep in tmp file")
|
|
}
|
|
if string(out) == "" {
|
|
return errors.Wrap(err, "empty results when grepping in tmp file")
|
|
}
|
|
return nil
|
|
}
|