package logstorage import ( "reflect" "testing" ) func TestExtractFormatApply(t *testing.T) { f := func(pattern, s string, resultsExpected []string) { t.Helper() steps, err := parseExtractFormatSteps(pattern) if err != nil { t.Fatalf("unexpected error: %s", err) } ef := newExtractFormat(steps) ef.apply(s) if len(ef.fields) != len(resultsExpected) { t.Fatalf("unexpected number of results; got %d; want %d", len(ef.fields), len(resultsExpected)) } for i, f := range ef.fields { if v := *f.value; v != resultsExpected[i] { t.Fatalf("unexpected value for field %q; got %q; want %q", f.name, v, resultsExpected[i]) } } } 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 TestParseExtractFormatStepsSuccess(t *testing.T) { f := func(s string, stepsExpected []extractFormatStep) { t.Helper() steps, err := parseExtractFormatSteps(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("", []extractFormatStep{ { field: "foo", }, }) f("bar", []extractFormatStep{ { field: "foo", }, { prefix: "bar", }, }) f("<>bar", []extractFormatStep{ {}, { prefix: "bar", field: "foo", }, }) f("bar", []extractFormatStep{ { prefix: "bar", field: "foo", }, }) f("barabc", []extractFormatStep{ { prefix: "bar", field: "foo", }, { prefix: "abc", }, }) f("barabc<_>", []extractFormatStep{ { prefix: "bar", field: "foo", }, { prefix: "abc", }, }) f("bar", []extractFormatStep{ { field: "foo", }, { prefix: "bar", field: "baz", }, }) f("barbaz", []extractFormatStep{ { prefix: "bar", field: "foo", }, { prefix: "baz", }, }) f("<&gt;", []extractFormatStep{ { prefix: "<", field: "foo", }, { prefix: ">", }, }) } func TestParseExtractFormatStepFailure(t *testing.T) { f := func(s string) { t.Helper() _, err := parseExtractFormatSteps(s) if err == nil { t.Fatalf("expecting non-nil error when parsing %q", s) } } // empty string f("") // zero fields f("foobar") // Zero named fields f("<>") f("foo<>") f("<>foo") f("foo<_>bar<*>baz<>xxx") // missing delimiter between fields f("") f("<>") f("<>") f("bb<>aa") f("aa") f("aabb") // missing > f("'", "*", "", "*", "foo") // all the needed fields, unneeded fields do not intersect with fromField and output fields f("extract from x ''", "*", "f1,f2", "*", "f1,f2,foo") // all the needed fields, unneeded fields intersect with fromField f("extract from x ''", "*", "f2,x", "*", "f2,foo") // all the needed fields, unneeded fields intersect with output fields f("extract from x 'x'", "*", "f2,foo", "*", "bar,f2,foo") // all the needed fields, unneeded fields intersect with all the output fields f("extract from x 'x'", "*", "f2,foo,bar", "*", "bar,f2,foo,x") // needed fields do not intersect with fromField and output fields f("extract from x 'x'", "f1,f2", "", "f1,f2", "") // needed fields intersect with fromField f("extract from x 'x'", "f2,x", "", "f2,x", "") // needed fields intersect with output fields f("extract from x 'x'", "f2,foo", "", "f2,x", "") // needed fields intersect with fromField and output fields f("extract from x 'x'", "f2,foo,x,y", "", "f2,x,y", "") }