package logstorage import ( "reflect" "testing" ) func TestPatternApply(t *testing.T) { f := func(patternStr, s string, resultsExpected []string) { t.Helper() checkFields := func(ptn *pattern) { t.Helper() if len(ptn.fields) != len(resultsExpected) { t.Fatalf("unexpected number of results; got %d; want %d", len(ptn.fields), len(resultsExpected)) } for i, f := range ptn.fields { if v := *f.value; v != resultsExpected[i] { t.Fatalf("unexpected value for field %q; got %q; want %q", f.name, v, resultsExpected[i]) } } } ptn, err := parsePattern(patternStr) if err != nil { t.Fatalf("cannot parse %q: %s", patternStr, err) } ptn.apply(s) checkFields(ptn) // clone pattern and check fields again ptnCopy := ptn.clone() ptnCopy.apply(s) checkFields(ptn) } f("", "", []string{""}) f("", "abc", []string{"abc"}) f("bar", "", []string{""}) f("bar", "bar", []string{""}) f("bar", "bazbar", []string{"baz"}) f("bar", "a bazbar xdsf", []string{"a baz"}) f("bar<>", "a bazbar xdsf", []string{"a baz"}) f("bar<>x", "a bazbar xdsf", []string{"a baz"}) f("foo", "", []string{""}) f("foo", "foo", []string{""}) f("foo", "a foo xdf sdf", []string{" xdf sdf"}) f("foo", "a foo foobar", []string{" foobar"}) f("foobaz", "a foo foobar", []string{""}) f("foobaz", "a foobaz bar", []string{""}) f("foobaz", "a foo foobar baz", []string{" foobar "}) f("foobaz", "a foo foobar bazabc", []string{" foobar "}) f("ip= <> path= ", "x=a, ip=1.2.3.4 method=GET host='abc' path=/foo/bar some tail here", []string{"1.2.3.4", "/foo/bar"}) // escaped pattern f("ip=<>", "foo ip=<1.2.3.4> bar", []string{"1.2.3.4"}) f("ip=<>", "foo ip= bar", []string{"foo&bar"}) // quoted fields f(`"msg":,`, `{"foo":"bar","msg":"foo,b\"ar\n\t","baz":"x"}`, []string{`foo,b"ar` + "\n\t"}) f(`foo=`, "foo=`bar baz,abc` def", []string{"bar baz,abc"}) f(`foo= `, "foo=`bar baz,abc` def", []string{"bar baz,abc"}) f(``, `"foo,\"bar"`, []string{`foo,"bar`}) f(`,"bar`, `"foo,\"bar"`, []string{`foo,"bar`}) } func TestParsePatternFailure(t *testing.T) { f := func(patternStr string) { t.Helper() ptn, err := parsePattern(patternStr) if err == nil { t.Fatalf("expecting error when parsing %q; got %v", patternStr, ptn) } } // Missing named fields f("") f("foobar") f("<>") f("<>foo<>bar") // Missing delimiter between fields f("") f("abcdef") f("abc") f("abc<_>") f("abc<_><_>") } func TestParsePatternStepsSuccess(t *testing.T) { f := func(s string, stepsExpected []patternStep) { t.Helper() steps, err := parsePatternSteps(s) if err != nil { t.Fatalf("unexpected error when parsing %q: %s", s, err) } if !reflect.DeepEqual(steps, stepsExpected) { t.Fatalf("unexpected steps for [%s]; got %v; want %v", s, steps, stepsExpected) } } f("", nil) f("foobar", []patternStep{ { prefix: "foobar", }, }) f("<>", []patternStep{ {}, }) f("foo<>", []patternStep{ { prefix: "foo", }, }) f("", []patternStep{ { field: "foo", }, { field: "bar", }, }) f("", []patternStep{ { field: "foo", }, }) f("bar", []patternStep{ { field: "foo", }, { prefix: "bar", }, }) f("<>bar", []patternStep{ {}, { prefix: "bar", field: "foo", }, }) f("bar", []patternStep{ { prefix: "bar", field: "foo", }, }) f("barabc", []patternStep{ { prefix: "bar", field: "foo", }, { prefix: "abc", }, }) f("barabc<_>", []patternStep{ { prefix: "bar", field: "foo", }, { prefix: "abc", }, }) f("bar", []patternStep{ { field: "foo", }, { prefix: "bar", field: "baz", }, }) f("barbaz", []patternStep{ { prefix: "bar", field: "foo", }, { prefix: "baz", }, }) f("<&>", []patternStep{ { prefix: "<&>", }, }) f("<&gt;", []patternStep{ { prefix: "<", field: "foo", }, { prefix: ">", }, }) f("barf<:foo:bar:baz>", []patternStep{ { field: "foo", opt: "q", }, { prefix: "bar", field: "baz:c:y", opt: "abc", }, { prefix: "f", field: "foo:bar:baz", }, }) } func TestParsePatternStepsFailure(t *testing.T) { f := func(s string) { t.Helper() steps, err := parsePatternSteps(s) if err == nil { t.Fatalf("expecting non-nil error when parsing %q; got steps: %v", s, steps) } } // missing > f("