From a20549fadf430314ad3eedca237fd7ad48c59dd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Renard?= Date: Tue, 16 Feb 2021 07:55:58 +0100 Subject: [PATCH] Switch to testify & go modules (#21) --- Makefile | 36 +- README.md | 51 +- dependencies.txt | 1 - go.mod | 5 + go.sum | 10 + rfc3164/example_test.go | 1 + rfc3164/rfc3164.go | 11 +- rfc3164/rfc3164_test.go | 448 ++++++----- rfc5424/example_test.go | 1 + rfc5424/rfc5424.go | 39 +- rfc5424/rfc5424_test.go | 1683 +++++++++++++++++++++++---------------- syslogparser.go | 1 + syslogparser_test.go | 331 +++++--- 13 files changed, 1568 insertions(+), 1050 deletions(-) delete mode 100644 dependencies.txt create mode 100644 go.mod create mode 100644 go.sum diff --git a/Makefile b/Makefile index 3a6e8e4..c6dcac4 100644 --- a/Makefile +++ b/Makefile @@ -1,19 +1,25 @@ -SUBPACKAGES=. rfc3164 rfc5424 -help: - @echo "Available targets:" - @echo "- tests: run tests" - @echo "- installdependencies: installs dependencies declared in dependencies.txt" - @echo "- clean: cleans directory" - @echo "- benchmarks: run benchmarks" +GO ?= $(shell which go) -installdependencies: - @cat dependencies.txt | xargs go get +GO_PKGS ?= $(shell $(GO) list ./...) -tests: installdependencies - @for pkg in $(SUBPACKAGES); do cd $$pkg && go test -i && go test ; cd -;done +GO_TEST_PKGS ?= $(shell test -f go.mod && $(GO) list -f \ + '{{ if or .TestGoFiles .XTestGoFiles }}{{ .ImportPath }}{{ end }}' \ + $(GO_PKGS)) -clean: - find . -type 'f' -name '*.test' -print | xargs rm -f +GO_TEST_TIMEOUT ?= 15s -benchmarks: - @for pkg in $(SUBPACKAGES); do cd $$pkg && go test -gocheck.b ; cd -;done +GO_BENCH=go test -bench=. -benchmem + +all: test + +test: + $(GO) test \ + -race \ + -timeout $(GO_TEST_TIMEOUT) \ + $(GO_TEST_PKGS) + +#XXX: ugly +benchmark: + $(GO_BENCH) + cd rfc3164 && $(GO_BENCH) + cd rfc5424 && $(GO_BENCH) diff --git a/README.md b/README.md index e641153..1a792a5 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ You should see Detecting message format ------------------------ -You can use the `WhichRFC()` function. Like this: +You can use the `DetectRFC()` function. Like this: b := []byte(`<165>1 2003-10-11T22:14:15.003Z ...`) rfc, err := syslogparser.DetectRFC(b) @@ -101,24 +101,45 @@ You can use the `WhichRFC()` function. Like this: Running tests ------------- -Run `make tests` +Run `make test` Running benchmarks ------------------ -Run `make benchmarks` - - CommonTestSuite.BenchmarkParsePriority 20000000 85.9 ns/op - CommonTestSuite.BenchmarkParseVersion 500000000 4.59 ns/op - Rfc3164TestSuite.BenchmarkParseFull 10000000 187 ns/op - Rfc3164TestSuite.BenchmarkParseHeader 5000000 686 ns/op - Rfc3164TestSuite.BenchmarkParseHostname 50000000 43.4 ns/op - Rfc3164TestSuite.BenchmarkParseTag 50000000 63.5 ns/op - Rfc3164TestSuite.BenchmarkParseTimestamp 5000000 616 ns/op - Rfc3164TestSuite.BenchmarkParsemessage 10000000 187 ns/op - Rfc5424TestSuite.BenchmarkParseFull 1000000 1345 ns/op - Rfc5424TestSuite.BenchmarkParseHeader 1000000 1353 ns/op - Rfc5424TestSuite.BenchmarkParseTimestamp 1000000 2045 ns/op +Run `make benchmark` + + go test -bench=. -benchmem + goos: linux + goarch: amd64 + pkg: github.com/jeromer/syslogparser + BenchmarkParsePriority-8 41772079 31.2 ns/op 0 B/op 0 allocs/op + BenchmarkParseVersion-8 270007530 4.45 ns/op 0 B/op 0 allocs/op + BenchmarkDetectRFC-8 78742269 16.2 ns/op 0 B/op 0 allocs/op + PASS + ok github.com/jeromer/syslogparser 5.257s + + cd rfc3164 && go test -bench=. -benchmem + goos: linux + goarch: amd64 + pkg: github.com/jeromer/syslogparser/rfc3164 + BenchmarkParseTimestamp-8 2693362 467 ns/op 16 B/op 1 allocs/op + BenchmarkParseHostname-8 34919636 32.8 ns/op 16 B/op 1 allocs/op + BenchmarkParseTag-8 20970715 56.0 ns/op 8 B/op 1 allocs/op + BenchmarkParseHeader-8 2549106 478 ns/op 32 B/op 2 allocs/op + BenchmarkParsemessage-8 8280796 143 ns/op 72 B/op 3 allocs/op + BenchmarkParseFull-8 8070195 139 ns/op 120 B/op 3 allocs/op + PASS + ok github.com/jeromer/syslogparser/rfc3164 8.428s + + cd rfc5424 && go test -bench=. -benchmem + goos: linux + goarch: amd64 + pkg: github.com/jeromer/syslogparser/rfc5424 + BenchmarkParseTimestamp-8 846019 1385 ns/op 352 B/op 18 allocs/op + BenchmarkParseHeader-8 1424103 840 ns/op 106 B/op 12 allocs/op + BenchmarkParseFull-8 1444834 825 ns/op 112 B/op 12 allocs/op + PASS + ok github.com/jeromer/syslogparser/rfc5424 6.195s [RFC 5424]: https://tools.ietf.org/html/rfc5424 [RFC 3164]: https://tools.ietf.org/html/rfc3164 diff --git a/dependencies.txt b/dependencies.txt deleted file mode 100644 index a7b459b..0000000 --- a/dependencies.txt +++ /dev/null @@ -1 +0,0 @@ -gopkg.in/check.v1 diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..b688a40 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/jeromer/syslogparser + +go 1.14 + +require github.com/stretchr/testify v1.7.0 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..b380ae4 --- /dev/null +++ b/go.sum @@ -0,0 +1,10 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/rfc3164/example_test.go b/rfc3164/example_test.go index 7f68935..418dd6a 100644 --- a/rfc3164/example_test.go +++ b/rfc3164/example_test.go @@ -2,6 +2,7 @@ package rfc3164_test import ( "fmt" + "github.com/jeromer/syslogparser/rfc3164" ) diff --git a/rfc3164/rfc3164.go b/rfc3164/rfc3164.go index 6a0e0f0..3fc3831 100644 --- a/rfc3164/rfc3164.go +++ b/rfc3164/rfc3164.go @@ -2,8 +2,9 @@ package rfc3164 import ( "bytes" - "github.com/jeromer/syslogparser" "time" + + "github.com/jeromer/syslogparser" ) type Parser struct { @@ -56,9 +57,9 @@ func (p *Parser) Parse() error { p.priority = pri } else { p.priority = syslogparser.Priority{ - 0, - syslogparser.Facility{0}, - syslogparser.Severity{0}, + P: 0, + F: syslogparser.Facility{Value: 0}, + S: syslogparser.Severity{Value: 0}, } } @@ -226,7 +227,7 @@ func (p *Parser) parseTag() (string, error) { if endOfTag { if !found { tag = p.buff[from:p.cursor] - found = true + // found = true } p.cursor++ diff --git a/rfc3164/rfc3164_test.go b/rfc3164/rfc3164_test.go index d8dda5e..3dcd3ea 100644 --- a/rfc3164/rfc3164_test.go +++ b/rfc3164/rfc3164_test.go @@ -6,219 +6,319 @@ import ( "time" "github.com/jeromer/syslogparser" - . "gopkg.in/check.v1" + "github.com/stretchr/testify/suite" ) -// Hooks up gocheck into the gotest runner. -func Test(t *testing.T) { TestingT(t) } - -type Rfc3164TestSuite struct { +type RFC3164TestSuite struct { + suite.Suite } var ( - _ = Suite(&Rfc3164TestSuite{}) - // XXX : corresponds to the length of the last tried timestamp format // XXX : Jan 2 15:04:05 lastTriedTimestampLen = 15 ) -func (s *Rfc3164TestSuite) TestParser_Valid(c *C) { - buff := []byte("<34>Oct 11 22:14:15 mymachine very.large.syslog.message.tag: 'su root' failed for lonvick on /dev/pts/8") +func (s *RFC3164TestSuite) TestParser_Valid() { + buff := []byte( + "<34>Oct 11 22:14:15 mymachine very.large.syslog.message.tag: 'su root' failed for lonvick on /dev/pts/8", + ) p := NewParser(buff) - expectedP := &Parser{ - buff: buff, - cursor: 0, - l: len(buff), - location: time.UTC, - ParsePriority: true, - } - - c.Assert(p, DeepEquals, expectedP) + s.Require().Equal( + p, + &Parser{ + buff: buff, + cursor: 0, + l: len(buff), + location: time.UTC, + ParsePriority: true, + }, + ) err := p.Parse() - c.Assert(err, IsNil) - - now := time.Now() - - obtained := p.Dump() - expected := syslogparser.LogParts{ - "timestamp": time.Date(now.Year(), time.October, 11, 22, 14, 15, 0, time.UTC), - "hostname": "mymachine", - "tag": "very.large.syslog.message.tag", - "content": "'su root' failed for lonvick on /dev/pts/8", - "priority": 34, - "facility": 4, - "severity": 2, - } - - c.Assert(obtained, DeepEquals, expected) + s.Require().Nil(err) + s.Require().Equal( + p.Dump(), + syslogparser.LogParts{ + "timestamp": time.Date( + time.Now().Year(), + time.October, + 11, 22, 14, 15, 0, + time.UTC, + ), + "hostname": "mymachine", + "tag": "very.large.syslog.message.tag", + "content": "'su root' failed for lonvick on /dev/pts/8", + "priority": 34, + "facility": 4, + "severity": 2, + }, + ) } -func (s *Rfc3164TestSuite) TestParser_WithoutPriority(c *C) { - buff := []byte("Oct 11 22:14:15 mymachine very.large.syslog.message.tag: 'su root' failed for lonvick on /dev/pts/8") +func (s *RFC3164TestSuite) TestParser_WithoutPriority() { + buff := []byte( + "Oct 11 22:14:15 mymachine very.large.syslog.message.tag: 'su root' failed for lonvick on /dev/pts/8", + ) p := NewParser(buff) p.ParsePriority = false - expectedP := &Parser{ - buff: buff, - cursor: 0, - l: len(buff), - location: time.UTC, - ParsePriority: false, - } - c.Assert(p, DeepEquals, expectedP) + s.Require().Equal( + p, + &Parser{ + buff: buff, + cursor: 0, + l: len(buff), + location: time.UTC, + ParsePriority: false, + }, + ) err := p.Parse() - c.Assert(err, IsNil) - - now := time.Now() - - obtained := p.Dump() - expected := syslogparser.LogParts{ - "timestamp": time.Date(now.Year(), time.October, 11, 22, 14, 15, 0, time.UTC), - "hostname": "mymachine", - "tag": "very.large.syslog.message.tag", - "content": "'su root' failed for lonvick on /dev/pts/8", - } - - c.Assert(obtained, DeepEquals, expected) + s.Require().Nil(err) + s.Require().Equal( + p.Dump(), + syslogparser.LogParts{ + "timestamp": time.Date( + time.Now().Year(), + time.October, + 11, 22, 14, 15, 0, + time.UTC, + ), + "hostname": "mymachine", + "tag": "very.large.syslog.message.tag", + "content": "'su root' failed for lonvick on /dev/pts/8", + }, + ) } -func (s *Rfc3164TestSuite) TestParseWithout_Hostname(c *C) { - buff := []byte("<30>Jun 23 13:17:42 chronyd[1119]: Selected source 192.168.65.1") +func (s *RFC3164TestSuite) TestParseWithout_Hostname() { + buff := []byte( + "<30>Jun 23 13:17:42 chronyd[1119]: Selected source 192.168.65.1", + ) p := NewParser(buff) p.Hostname("testhost") err := p.Parse() - c.Assert(err, IsNil) - - now := time.Now() - - obtained := p.Dump() - expected := syslogparser.LogParts{ - "timestamp": time.Date(now.Year(), time.June, 23, 13, 17, 42, 0, time.UTC), - "hostname": "testhost", - "tag": "chronyd", - "content": "Selected source 192.168.65.1", - "priority": 30, - "facility": 3, - "severity": 6, - } - - c.Assert(obtained, DeepEquals, expected) + s.Require().Nil(err) + + s.Require().Equal( + p.Dump(), + syslogparser.LogParts{ + "timestamp": time.Date( + time.Now().Year(), + time.June, + 23, 13, 17, 42, 0, + time.UTC, + ), + "hostname": "testhost", + "tag": "chronyd", + "content": "Selected source 192.168.65.1", + "priority": 30, + "facility": 3, + "severity": 6, + }, + ) } -func (s *Rfc3164TestSuite) TestParseHeader_Valid(c *C) { - buff := []byte("Oct 11 22:14:15 mymachine ") - now := time.Now() - hdr := header{ - timestamp: time.Date(now.Year(), time.October, 11, 22, 14, 15, 0, time.UTC), - hostname: "mymachine", +func (s *RFC3164TestSuite) TestParseHeader() { + testCases := []struct { + description string + input string + expectedHdr header + expectedCursorPos int + expectedErr error + }{ + { + description: "valid headers", + input: "Oct 11 22:14:15 mymachine ", + expectedHdr: header{ + hostname: "mymachine", + timestamp: time.Date( + time.Now().Year(), + time.October, + 11, 22, 14, 15, 0, + time.UTC, + ), + }, + expectedCursorPos: 25, + expectedErr: nil, + }, + { + description: "invalid timestamp", + input: "Oct 34 32:72:82 mymachine ", + expectedHdr: header{}, + expectedCursorPos: lastTriedTimestampLen + 1, + expectedErr: syslogparser.ErrTimestampUnknownFormat, + }, } - s.assertRfc3164Header(c, hdr, buff, 25, nil) -} - -func (s *Rfc3164TestSuite) TestParseHeader_InvalidTimestamp(c *C) { - buff := []byte("Oct 34 32:72:82 mymachine ") - hdr := header{} + for _, tc := range testCases { + p := NewParser([]byte(tc.input)) + obtained, err := p.parseHeader() - s.assertRfc3164Header(c, hdr, buff, lastTriedTimestampLen+1, syslogparser.ErrTimestampUnknownFormat) + s.Require().Equal(err, tc.expectedErr, tc.description) + s.Require().Equal(obtained, tc.expectedHdr, tc.description) + s.Require().Equal(p.cursor, tc.expectedCursorPos, tc.description) + } } -func (s *Rfc3164TestSuite) TestParsemessage_Valid(c *C) { +func (s *RFC3164TestSuite) TestParsemessage_Valid() { content := "foo bar baz blah quux" + buff := []byte("sometag[123]: " + content) + hdr := rfc3164message{ tag: "sometag", content: content, } - s.assertRfc3164message(c, hdr, buff, len(buff), syslogparser.ErrEOL) -} - -func (s *Rfc3164TestSuite) TestParseTimestamp_Invalid(c *C) { - buff := []byte("Oct 34 32:72:82") - ts := new(time.Time) - - s.assertTimestamp(c, *ts, buff, lastTriedTimestampLen, syslogparser.ErrTimestampUnknownFormat) -} - -func (s *Rfc3164TestSuite) TestParseTimestamp_TrailingSpace(c *C) { - // XXX : no year specified. Assumed current year - // XXX : no timezone specified. Assume UTC - buff := []byte("Oct 11 22:14:15 ") - - now := time.Now() - ts := time.Date(now.Year(), time.October, 11, 22, 14, 15, 0, time.UTC) - - s.assertTimestamp(c, ts, buff, len(buff), nil) -} - -func (s *Rfc3164TestSuite) TestParseTimestamp_OneDigitForMonths(c *C) { - // XXX : no year specified. Assumed current year - // XXX : no timezone specified. Assume UTC - buff := []byte("Oct 1 22:14:15") - - now := time.Now() - ts := time.Date(now.Year(), time.October, 1, 22, 14, 15, 0, time.UTC) + p := NewParser(buff) + obtained, err := p.parsemessage() - s.assertTimestamp(c, ts, buff, len(buff), nil) + s.Require().Equal(err, syslogparser.ErrEOL) + s.Require().Equal(obtained, hdr) + s.Require().Equal(p.cursor, len(buff)) } -func (s *Rfc3164TestSuite) TestParseTimestamp_Valid(c *C) { - // XXX : no year specified. Assumed current year - // XXX : no timezone specified. Assume UTC - buff := []byte("Oct 11 22:14:15") - - now := time.Now() - ts := time.Date(now.Year(), time.October, 11, 22, 14, 15, 0, time.UTC) +func (s *RFC3164TestSuite) TestParseTimestamp() { + testCases := []struct { + description string + input string + expectedTS time.Time + expectedCursorPos int + expectedErr error + }{ + { + description: "invalid", + input: "Oct 34 32:72:82", + expectedCursorPos: lastTriedTimestampLen, + expectedErr: syslogparser.ErrTimestampUnknownFormat, + }, + { + description: "trailing space", + input: "Oct 11 22:14:15 ", + expectedTS: time.Date( + time.Now().Year(), + time.October, + 11, 22, 14, 15, 0, + time.UTC, + ), + expectedCursorPos: 16, + expectedErr: nil, + }, + { + description: "one digit for month", + input: "Oct 1 22:14:15", + expectedTS: time.Date( + time.Now().Year(), + time.October, + 1, 22, 14, 15, 0, + time.UTC, + ), + expectedCursorPos: 15, + expectedErr: nil, + }, + { + description: "valid timestamp", + input: "Oct 11 22:14:15", + expectedTS: time.Date( + time.Now().Year(), + time.October, + 11, 22, 14, 15, 0, + time.UTC, + ), + expectedCursorPos: 15, + expectedErr: nil, + }, + } - s.assertTimestamp(c, ts, buff, len(buff), nil) + for _, tc := range testCases { + p := NewParser([]byte(tc.input)) + obtained, err := p.parseTimestamp() + + s.Require().Equal( + obtained, tc.expectedTS, tc.description, + ) + s.Require().Equal( + p.cursor, tc.expectedCursorPos, tc.description, + ) + s.Require().Equal( + err, tc.expectedErr, tc.description, + ) + } } -func (s *Rfc3164TestSuite) TestParseTag_Pid(c *C) { - buff := []byte("apache2[10]:") - tag := "apache2" - - s.assertTag(c, tag, buff, len(buff), nil) -} +func (s *RFC3164TestSuite) TestParseTag() { + testCases := []struct { + description string + input string + expectedTag string + expectedCursorPos int + expectedErr error + }{ + { + description: "with pid", + input: "apache2[10]:", + expectedTag: "apache2", + expectedCursorPos: 12, + expectedErr: nil, + }, + { + description: "without pid", + input: "apache2:", + expectedTag: "apache2", + expectedCursorPos: 8, + expectedErr: nil, + }, + { + description: "trailing space", + input: "apache2: ", + expectedTag: "apache2", + expectedCursorPos: 9, + expectedErr: nil, + }, + } -func (s *Rfc3164TestSuite) TestParseTag_NoPid(c *C) { - buff := []byte("apache2:") - tag := "apache2" + for _, tc := range testCases { + p := NewParser([]byte(tc.input)) + obtained, err := p.parseTag() - s.assertTag(c, tag, buff, len(buff), nil) -} + s.Require().Equal( + obtained, tc.expectedTag, tc.description, + ) -func (s *Rfc3164TestSuite) TestParseTag_TrailingSpace(c *C) { - buff := []byte("apache2: ") - tag := "apache2" + s.Require().Equal( + p.cursor, tc.expectedCursorPos, tc.description, + ) - s.assertTag(c, tag, buff, len(buff), nil) + s.Require().Equal( + err, tc.expectedErr, tc.description, + ) + } } -func (s *Rfc3164TestSuite) TestParseContent_Valid(c *C) { +func (s *RFC3164TestSuite) TestParseContent_Valid() { buff := []byte(" foo bar baz quux ") content := string(bytes.Trim(buff, " ")) p := NewParser(buff) obtained, err := p.parseContent() - c.Assert(err, Equals, syslogparser.ErrEOL) - c.Assert(obtained, Equals, content) - c.Assert(p.cursor, Equals, len(content)) + + s.Require().Equal(err, syslogparser.ErrEOL) + s.Require().Equal(obtained, content) + s.Require().Equal(p.cursor, len(content)) } -func (s *Rfc3164TestSuite) BenchmarkParseTimestamp(c *C) { +func BenchmarkParseTimestamp(b *testing.B) { buff := []byte("Oct 11 22:14:15") p := NewParser(buff) - for i := 0; i < c.N; i++ { + for i := 0; i < b.N; i++ { _, err := p.parseTimestamp() if err != nil { panic(err) @@ -228,12 +328,12 @@ func (s *Rfc3164TestSuite) BenchmarkParseTimestamp(c *C) { } } -func (s *Rfc3164TestSuite) BenchmarkParseHostname(c *C) { +func BenchmarkParseHostname(b *testing.B) { buff := []byte("gimli.local") p := NewParser(buff) - for i := 0; i < c.N; i++ { + for i := 0; i < b.N; i++ { _, err := p.parseHostname() if err != nil { panic(err) @@ -243,12 +343,12 @@ func (s *Rfc3164TestSuite) BenchmarkParseHostname(c *C) { } } -func (s *Rfc3164TestSuite) BenchmarkParseTag(c *C) { +func BenchmarkParseTag(b *testing.B) { buff := []byte("apache2[10]:") p := NewParser(buff) - for i := 0; i < c.N; i++ { + for i := 0; i < b.N; i++ { _, err := p.parseTag() if err != nil { panic(err) @@ -258,12 +358,12 @@ func (s *Rfc3164TestSuite) BenchmarkParseTag(c *C) { } } -func (s *Rfc3164TestSuite) BenchmarkParseHeader(c *C) { +func BenchmarkParseHeader(b *testing.B) { buff := []byte("Oct 11 22:14:15 mymachine ") p := NewParser(buff) - for i := 0; i < c.N; i++ { + for i := 0; i < b.N; i++ { _, err := p.parseHeader() if err != nil { panic(err) @@ -273,12 +373,12 @@ func (s *Rfc3164TestSuite) BenchmarkParseHeader(c *C) { } } -func (s *Rfc3164TestSuite) BenchmarkParsemessage(c *C) { +func BenchmarkParsemessage(b *testing.B) { buff := []byte("sometag[123]: foo bar baz blah quux") p := NewParser(buff) - for i := 0; i < c.N; i++ { + for i := 0; i < b.N; i++ { _, err := p.parsemessage() if err != syslogparser.ErrEOL { panic(err) @@ -288,12 +388,12 @@ func (s *Rfc3164TestSuite) BenchmarkParsemessage(c *C) { } } -func (s *Rfc3164TestSuite) BenchmarkParseFull(c *C) { +func BenchmarkParseFull(b *testing.B) { msg := "<34>Oct 11 22:14:15 mymachine su: 'su root' failed for lonvick on /dev/pts/8" p := NewParser([]byte(msg)) - for i := 0; i < c.N; i++ { + for i := 0; i < b.N; i++ { _, err := p.parsemessage() if err != syslogparser.ErrEOL { panic(err) @@ -304,34 +404,8 @@ func (s *Rfc3164TestSuite) BenchmarkParseFull(c *C) { } -func (s *Rfc3164TestSuite) assertTimestamp(c *C, ts time.Time, b []byte, expC int, e error) { - p := NewParser(b) - obtained, err := p.parseTimestamp() - c.Assert(obtained, Equals, ts) - c.Assert(p.cursor, Equals, expC) - c.Assert(err, Equals, e) -} - -func (s *Rfc3164TestSuite) assertTag(c *C, t string, b []byte, expC int, e error) { - p := NewParser(b) - obtained, err := p.parseTag() - c.Assert(obtained, Equals, t) - c.Assert(p.cursor, Equals, expC) - c.Assert(err, Equals, e) -} - -func (s *Rfc3164TestSuite) assertRfc3164Header(c *C, hdr header, b []byte, expC int, e error) { - p := NewParser(b) - obtained, err := p.parseHeader() - c.Assert(err, Equals, e) - c.Assert(obtained, Equals, hdr) - c.Assert(p.cursor, Equals, expC) -} - -func (s *Rfc3164TestSuite) assertRfc3164message(c *C, msg rfc3164message, b []byte, expC int, e error) { - p := NewParser(b) - obtained, err := p.parsemessage() - c.Assert(err, Equals, e) - c.Assert(obtained, Equals, msg) - c.Assert(p.cursor, Equals, expC) +func TestRFC3164TestSuite(t *testing.T) { + suite.Run( + t, new(RFC3164TestSuite), + ) } diff --git a/rfc5424/example_test.go b/rfc5424/example_test.go index 517a114..ed3600a 100644 --- a/rfc5424/example_test.go +++ b/rfc5424/example_test.go @@ -2,6 +2,7 @@ package rfc5424_test import ( "fmt" + "github.com/jeromer/syslogparser/rfc5424" ) diff --git a/rfc5424/rfc5424.go b/rfc5424/rfc5424.go index 8225ac5..ed5a09d 100644 --- a/rfc5424/rfc5424.go +++ b/rfc5424/rfc5424.go @@ -1,14 +1,12 @@ -// Note to self : never try to code while looking after your kids -// The result might look like this : https://pbs.twimg.com/media/BXqSuYXIEAAscVA.png - package rfc5424 import ( "fmt" - "github.com/jeromer/syslogparser" "math" "strconv" "time" + + "github.com/jeromer/syslogparser" ) const ( @@ -16,19 +14,19 @@ const ( ) var ( - ErrYearInvalid = &syslogparser.ParserError{"Invalid year in timestamp"} - ErrMonthInvalid = &syslogparser.ParserError{"Invalid month in timestamp"} - ErrDayInvalid = &syslogparser.ParserError{"Invalid day in timestamp"} - ErrHourInvalid = &syslogparser.ParserError{"Invalid hour in timestamp"} - ErrMinuteInvalid = &syslogparser.ParserError{"Invalid minute in timestamp"} - ErrSecondInvalid = &syslogparser.ParserError{"Invalid second in timestamp"} - ErrSecFracInvalid = &syslogparser.ParserError{"Invalid fraction of second in timestamp"} - ErrTimeZoneInvalid = &syslogparser.ParserError{"Invalid time zone in timestamp"} - ErrInvalidTimeFormat = &syslogparser.ParserError{"Invalid time format"} - ErrInvalidAppName = &syslogparser.ParserError{"Invalid app name"} - ErrInvalidProcId = &syslogparser.ParserError{"Invalid proc ID"} - ErrInvalidMsgId = &syslogparser.ParserError{"Invalid msg ID"} - ErrNoStructuredData = &syslogparser.ParserError{"No structured data"} + ErrYearInvalid = &syslogparser.ParserError{ErrorString: "Invalid year in timestamp"} + ErrMonthInvalid = &syslogparser.ParserError{ErrorString: "Invalid month in timestamp"} + ErrDayInvalid = &syslogparser.ParserError{ErrorString: "Invalid day in timestamp"} + ErrHourInvalid = &syslogparser.ParserError{ErrorString: "Invalid hour in timestamp"} + ErrMinuteInvalid = &syslogparser.ParserError{ErrorString: "Invalid minute in timestamp"} + ErrSecondInvalid = &syslogparser.ParserError{ErrorString: "Invalid second in timestamp"} + ErrSecFracInvalid = &syslogparser.ParserError{ErrorString: "Invalid fraction of second in timestamp"} + ErrTimeZoneInvalid = &syslogparser.ParserError{ErrorString: "Invalid time zone in timestamp"} + ErrInvalidTimeFormat = &syslogparser.ParserError{ErrorString: "Invalid time format"} + ErrInvalidAppName = &syslogparser.ParserError{ErrorString: "Invalid app name"} + ErrInvalidProcId = &syslogparser.ParserError{ErrorString: "Invalid proc ID"} + ErrInvalidMsgId = &syslogparser.ParserError{ErrorString: "Invalid msg ID"} + ErrNoStructuredData = &syslogparser.ParserError{ErrorString: "No structured data"} ) type Parser struct { @@ -340,7 +338,6 @@ func parseDay(buff []byte, cursor *int, l int) (int, error) { // FULL-TIME = PARTIAL-TIME TIME-OFFSET func parseFullTime(buff []byte, cursor *int, l int) (fullTime, error) { - var loc = new(time.Location) var ft fullTime pt, err := parsePartialTime(buff, cursor, l) @@ -348,7 +345,7 @@ func parseFullTime(buff []byte, cursor *int, l int) (fullTime, error) { return ft, err } - loc, err = parseTimeOffset(buff, cursor, l) + loc, err := parseTimeOffset(buff, cursor, l) if err != nil { return ft, err } @@ -427,7 +424,7 @@ func parseSecFrac(buff []byte, cursor *int, l int) (float64, error) { max := *cursor + maxDigitLen from := *cursor - to := from + to := 0 for to = from; to < max; to++ { if to >= l { @@ -540,7 +537,7 @@ func parseStructuredData(buff []byte, cursor *int, l int) (string, error) { } from := *cursor - to := from + to := 0 for to = from; to < l; to++ { if found { diff --git a/rfc5424/rfc5424_test.go b/rfc5424/rfc5424_test.go index bd15153..20daf47 100644 --- a/rfc5424/rfc5424_test.go +++ b/rfc5424/rfc5424_test.go @@ -2,114 +2,140 @@ package rfc5424 import ( "fmt" + "strings" "testing" "time" "github.com/jeromer/syslogparser" - . "gopkg.in/check.v1" + "github.com/stretchr/testify/suite" ) -// Hooks up gocheck into the gotest runner. -func Test(t *testing.T) { TestingT(t) } - -type Rfc5424TestSuite struct { -} +type RFC5424TestSuite struct { + suite.Suite +} + +func (s *RFC5424TestSuite) TestParser() { + tmpTZ, err := time.Parse("-07:00", "-07:00") + s.Require().Nil(err) + + testCases := []struct { + description string + input string + expectedParts syslogparser.LogParts + }{ + { + description: "no STRUCTURED-DATA 1/2", + input: "<34>1 2003-10-11T22:14:15.003Z mymachine.example.com su - ID47 - 'su root' failed for lonvick on /dev/pts/8", + expectedParts: syslogparser.LogParts{ + "priority": 34, + "facility": 4, + "severity": 2, + "version": 1, + "timestamp": time.Date( + 2003, time.October, 11, + 22, 14, 15, 3*10e5, + time.UTC, + ), + "hostname": "mymachine.example.com", + "app_name": "su", + "proc_id": "-", + "msg_id": "ID47", + "structured_data": "-", + "message": "'su root' failed for lonvick on /dev/pts/8", + }, + }, + { + description: "no STRUCTURED_DATA 2/2", + input: "<165>1 2003-08-24T05:14:15.000003-07:00 192.0.2.1 myproc 8710 - - %% It's time to make the do-nuts.", + expectedParts: syslogparser.LogParts{ + "priority": 165, + "facility": 20, + "severity": 5, + "version": 1, + "timestamp": time.Date( + 2003, time.August, 24, + 5, 14, 15, 3*10e2, + tmpTZ.Location(), + ), + "hostname": "192.0.2.1", + "app_name": "myproc", + "proc_id": "8710", + "msg_id": "-", + "structured_data": "-", + "message": "%% It's time to make the do-nuts.", + }, + }, + { + description: "with STRUCTURED_DATA", + input: `<165>1 2003-10-11T22:14:15.003Z mymachine.example.com evntslog - ID47 [exampleSDID@32473 iut="3" eventSource="Application" eventID="1011"] An application event log entry...`, + expectedParts: syslogparser.LogParts{ + "priority": 165, + "facility": 20, + "severity": 5, + "version": 1, + "timestamp": time.Date( + 2003, time.October, 11, + 22, 14, 15, 3*10e5, + time.UTC, + ), + "hostname": "mymachine.example.com", + "app_name": "evntslog", + "proc_id": "-", + "msg_id": "ID47", + "structured_data": `[exampleSDID@32473 iut="3" eventSource="Application" eventID="1011"]`, + "message": "An application event log entry...", + }, + }, + { + description: "STRUCTURED_DATA only", + input: `<165>1 2003-10-11T22:14:15.003Z mymachine.example.com evntslog - ID47 [exampleSDID@32473 iut="3" eventSource= "Application" eventID="1011"][examplePriority@32473 class="high"]`, + expectedParts: syslogparser.LogParts{ + "priority": 165, + "facility": 20, + "severity": 5, + "version": 1, + "timestamp": time.Date( + 2003, time.October, 11, + 22, 14, 15, 3*10e5, + time.UTC, + ), + "hostname": "mymachine.example.com", + "app_name": "evntslog", + "proc_id": "-", + "msg_id": "ID47", + "structured_data": `[exampleSDID@32473 iut="3" eventSource= "Application" eventID="1011"][examplePriority@32473 class="high"]`, + "message": "", + }, + }, + } -var _ = Suite(&Rfc5424TestSuite{}) - -func (s *Rfc5424TestSuite) TestParser_Valid(c *C) { - fixtures := []string{ - // no STRUCTURED-DATA - "<34>1 2003-10-11T22:14:15.003Z mymachine.example.com su - ID47 - 'su root' failed for lonvick on /dev/pts/8", - "<165>1 2003-08-24T05:14:15.000003-07:00 192.0.2.1 myproc 8710 - - %% It's time to make the do-nuts.", - // with STRUCTURED-DATA - `<165>1 2003-10-11T22:14:15.003Z mymachine.example.com evntslog - ID47 [exampleSDID@32473 iut="3" eventSource="Application" eventID="1011"] An application event log entry...`, - - // STRUCTURED-DATA Only - `<165>1 2003-10-11T22:14:15.003Z mymachine.example.com evntslog - ID47 [exampleSDID@32473 iut="3" eventSource= "Application" eventID="1011"][examplePriority@32473 class="high"]`, - } - - tmpTs, err := time.Parse("-07:00", "-07:00") - c.Assert(err, IsNil) - - expected := []syslogparser.LogParts{ - syslogparser.LogParts{ - "priority": 34, - "facility": 4, - "severity": 2, - "version": 1, - "timestamp": time.Date(2003, time.October, 11, 22, 14, 15, 3*10e5, time.UTC), - "hostname": "mymachine.example.com", - "app_name": "su", - "proc_id": "-", - "msg_id": "ID47", - "structured_data": "-", - "message": "'su root' failed for lonvick on /dev/pts/8", - }, - syslogparser.LogParts{ - "priority": 165, - "facility": 20, - "severity": 5, - "version": 1, - "timestamp": time.Date(2003, time.August, 24, 5, 14, 15, 3*10e2, tmpTs.Location()), - "hostname": "192.0.2.1", - "app_name": "myproc", - "proc_id": "8710", - "msg_id": "-", - "structured_data": "-", - "message": "%% It's time to make the do-nuts.", - }, - syslogparser.LogParts{ - "priority": 165, - "facility": 20, - "severity": 5, - "version": 1, - "timestamp": time.Date(2003, time.October, 11, 22, 14, 15, 3*10e5, time.UTC), - "hostname": "mymachine.example.com", - "app_name": "evntslog", - "proc_id": "-", - "msg_id": "ID47", - "structured_data": `[exampleSDID@32473 iut="3" eventSource="Application" eventID="1011"]`, - "message": "An application event log entry...", - }, - syslogparser.LogParts{ - "priority": 165, - "facility": 20, - "severity": 5, - "version": 1, - "timestamp": time.Date(2003, time.October, 11, 22, 14, 15, 3*10e5, time.UTC), - "hostname": "mymachine.example.com", - "app_name": "evntslog", - "proc_id": "-", - "msg_id": "ID47", - "structured_data": `[exampleSDID@32473 iut="3" eventSource= "Application" eventID="1011"][examplePriority@32473 class="high"]`, - "message": "", - }, - } - - c.Assert(len(fixtures), Equals, len(expected)) - start := 0 - for i, buff := range fixtures { - expectedP := &Parser{ - buff: []byte(buff), - cursor: start, - l: len(buff), - } + for _, tc := range testCases { + buff := []byte(tc.input) - p := NewParser([]byte(buff)) - c.Assert(p, DeepEquals, expectedP) + p := NewParser(buff) + s.Require().Equal( + p, + &Parser{ + buff: buff, + cursor: 0, + l: len(tc.input), + }, + tc.description, + ) err := p.Parse() - c.Assert(err, IsNil) + s.Require().Nil(err) obtained := p.Dump() for k, v := range obtained { - c.Assert(v, DeepEquals, expected[i][k]) + s.Require().Equal( + v, tc.expectedParts[k], tc.description, + ) } } } -func (s *Rfc5424TestSuite) TestParseHeader_Valid(c *C) { +func (s *RFC5424TestSuite) TestParseHeader() { ts := time.Date(2003, time.October, 11, 22, 14, 15, 3*10e5, time.UTC) tsString := "2003-10-11T22:14:15.003Z" hostname := "mymachine.example.com" @@ -118,461 +144,760 @@ func (s *Rfc5424TestSuite) TestParseHeader_Valid(c *C) { msgId := "ID47" nilValue := string(NILVALUE) headerFmt := "<165>1 %s %s %s %s %s " - - fixtures := []string{ - // HEADER complete - fmt.Sprintf(headerFmt, tsString, hostname, appName, procId, msgId), - // TIMESTAMP as NILVALUE - fmt.Sprintf(headerFmt, nilValue, hostname, appName, procId, msgId), - // HOSTNAME as NILVALUE - fmt.Sprintf(headerFmt, tsString, nilValue, appName, procId, msgId), - // APP-NAME as NILVALUE - fmt.Sprintf(headerFmt, tsString, hostname, nilValue, procId, msgId), - // PROCID as NILVALUE - fmt.Sprintf(headerFmt, tsString, hostname, appName, nilValue, msgId), - // MSGID as NILVALUE - fmt.Sprintf(headerFmt, tsString, hostname, appName, procId, nilValue), - } - pri := syslogparser.Priority{ P: 165, F: syslogparser.Facility{Value: 20}, S: syslogparser.Severity{Value: 5}, } - - expected := []header{ - // HEADER complete - header{ - priority: pri, - version: 1, - timestamp: ts, - hostname: hostname, - appName: appName, - procId: procId, - msgId: msgId, - }, - // TIMESTAMP as NILVALUE - header{ - priority: pri, - version: 1, - timestamp: *new(time.Time), - hostname: hostname, - appName: appName, - procId: procId, - msgId: msgId, - }, - // HOSTNAME as NILVALUE - header{ - priority: pri, - version: 1, - timestamp: ts, - hostname: nilValue, - appName: appName, - procId: procId, - msgId: msgId, - }, - // APP-NAME as NILVALUE - header{ - priority: pri, - version: 1, - timestamp: ts, - hostname: hostname, - appName: nilValue, - procId: procId, - msgId: msgId, - }, - // PROCID as NILVALUE - header{ - priority: pri, - version: 1, - timestamp: ts, - hostname: hostname, - appName: appName, - procId: nilValue, - msgId: msgId, - }, - // MSGID as NILVALUE - header{ - priority: pri, - version: 1, - timestamp: ts, - hostname: hostname, - appName: appName, - procId: procId, - msgId: nilValue, - }, - } - - for i, f := range fixtures { - p := NewParser([]byte(f)) - obtained, err := p.parseHeader() - c.Assert(err, IsNil) - c.Assert(obtained, Equals, expected[i]) - c.Assert(p.cursor, Equals, len(f)) + testCases := []struct { + description string + input string + expectedHdr header + }{ + { + description: "HEADER complete", + input: fmt.Sprintf(headerFmt, tsString, hostname, appName, procId, msgId), + expectedHdr: header{ + priority: pri, + version: 1, + timestamp: ts, + hostname: hostname, + appName: appName, + procId: procId, + msgId: msgId, + }, + }, + { + description: "TIMESTAMP as NILVALUE", + input: fmt.Sprintf(headerFmt, nilValue, hostname, appName, procId, msgId), + expectedHdr: header{ + priority: pri, + version: 1, + timestamp: *new(time.Time), + hostname: hostname, + appName: appName, + procId: procId, + msgId: msgId, + }, + }, + { + description: "HOSTNAME as NILVALUE", + input: fmt.Sprintf(headerFmt, tsString, nilValue, appName, procId, msgId), + expectedHdr: header{ + priority: pri, + version: 1, + timestamp: ts, + hostname: nilValue, + appName: appName, + procId: procId, + msgId: msgId, + }, + }, + { + description: "APP-NAME as NILVALUE", + input: fmt.Sprintf(headerFmt, tsString, hostname, nilValue, procId, msgId), + expectedHdr: header{ + priority: pri, + version: 1, + timestamp: ts, + hostname: hostname, + appName: nilValue, + procId: procId, + msgId: msgId, + }, + }, + { + description: "PROCID as NILVALUE", + input: fmt.Sprintf(headerFmt, tsString, hostname, appName, nilValue, msgId), + expectedHdr: header{ + priority: pri, + version: 1, + timestamp: ts, + hostname: hostname, + appName: appName, + procId: nilValue, + msgId: msgId, + }, + }, + { + description: "MSGID as NILVALUE", + input: fmt.Sprintf(headerFmt, tsString, hostname, appName, procId, nilValue), + expectedHdr: header{ + priority: pri, + version: 1, + timestamp: ts, + hostname: hostname, + appName: appName, + procId: procId, + msgId: nilValue, + }, + }, } -} - -func (s *Rfc5424TestSuite) TestParseTimestamp_UTC(c *C) { - buff := []byte("1985-04-12T23:20:50.52Z") - ts := time.Date(1985, time.April, 12, 23, 20, 50, 52*10e6, time.UTC) - - s.assertTimestamp(c, ts, buff, 23, nil) -} - -func (s *Rfc5424TestSuite) TestParseTimestamp_NumericTimezone(c *C) { - tz := "-04:00" - buff := []byte("1985-04-12T19:20:50.52" + tz) - - tmpTs, err := time.Parse("-07:00", tz) - c.Assert(err, IsNil) - - ts := time.Date(1985, time.April, 12, 19, 20, 50, 52*10e6, tmpTs.Location()) - - s.assertTimestamp(c, ts, buff, len(buff), nil) -} - -func (s *Rfc5424TestSuite) TestParseTimestamp_MilliSeconds(c *C) { - buff := []byte("2003-10-11T22:14:15.003Z") - - ts := time.Date(2003, time.October, 11, 22, 14, 15, 3*10e5, time.UTC) - - s.assertTimestamp(c, ts, buff, len(buff), nil) -} - -func (s *Rfc5424TestSuite) TestParseTimestamp_MicroSeconds(c *C) { - tz := "-07:00" - buff := []byte("2003-08-24T05:14:15.000003" + tz) - - tmpTs, err := time.Parse("-07:00", tz) - c.Assert(err, IsNil) - - ts := time.Date(2003, time.August, 24, 5, 14, 15, 3*10e2, tmpTs.Location()) - - s.assertTimestamp(c, ts, buff, len(buff), nil) -} - -func (s *Rfc5424TestSuite) TestParseTimestamp_NanoSeconds(c *C) { - buff := []byte("2003-08-24T05:14:15.000000003-07:00") - ts := new(time.Time) - - s.assertTimestamp(c, *ts, buff, 26, syslogparser.ErrTimestampUnknownFormat) -} - -func (s *Rfc5424TestSuite) TestParseTimestamp_NilValue(c *C) { - buff := []byte("-") - ts := new(time.Time) - - s.assertTimestamp(c, *ts, buff, 1, nil) -} - -func (s *Rfc5424TestSuite) TestFindNextSpace_NoSpace(c *C) { - buff := []byte("aaaaaa") - - s.assertFindNextSpace(c, 0, buff, syslogparser.ErrNoSpace) -} - -func (s *Rfc5424TestSuite) TestFindNextSpace_SpaceFound(c *C) { - buff := []byte("foo bar baz") - - s.assertFindNextSpace(c, 4, buff, nil) -} - -func (s *Rfc5424TestSuite) TestParseYear_Invalid(c *C) { - buff := []byte("1a2b") - expected := 0 - - s.assertParseYear(c, expected, buff, 4, ErrYearInvalid) -} - -func (s *Rfc5424TestSuite) TestParseYear_TooShort(c *C) { - buff := []byte("123") - expected := 0 - - s.assertParseYear(c, expected, buff, 0, syslogparser.ErrEOL) -} - -func (s *Rfc5424TestSuite) TestParseYear_Valid(c *C) { - buff := []byte("2013") - expected := 2013 - - s.assertParseYear(c, expected, buff, 4, nil) -} - -func (s *Rfc5424TestSuite) TestParseMonth_InvalidString(c *C) { - buff := []byte("ab") - expected := 0 - - s.assertParseMonth(c, expected, buff, 2, ErrMonthInvalid) -} - -func (s *Rfc5424TestSuite) TestParseMonth_InvalidRange(c *C) { - buff := []byte("00") - expected := 0 - - s.assertParseMonth(c, expected, buff, 2, ErrMonthInvalid) - - // ---- - - buff = []byte("13") - s.assertParseMonth(c, expected, buff, 2, ErrMonthInvalid) -} - -func (s *Rfc5424TestSuite) TestParseMonth_TooShort(c *C) { - buff := []byte("1") - expected := 0 - - s.assertParseMonth(c, expected, buff, 0, syslogparser.ErrEOL) -} - -func (s *Rfc5424TestSuite) TestParseMonth_Valid(c *C) { - buff := []byte("02") - expected := 2 - - s.assertParseMonth(c, expected, buff, 2, nil) -} - -func (s *Rfc5424TestSuite) TestParseDay_InvalidString(c *C) { - buff := []byte("ab") - expected := 0 - - s.assertParseDay(c, expected, buff, 2, ErrDayInvalid) -} - -func (s *Rfc5424TestSuite) TestParseDay_TooShort(c *C) { - buff := []byte("1") - expected := 0 - - s.assertParseDay(c, expected, buff, 0, syslogparser.ErrEOL) -} - -func (s *Rfc5424TestSuite) TestParseDay_InvalidRange(c *C) { - buff := []byte("00") - expected := 0 - - s.assertParseDay(c, expected, buff, 2, ErrDayInvalid) - - // ---- - - buff = []byte("32") - - s.assertParseDay(c, expected, buff, 2, ErrDayInvalid) -} - -func (s *Rfc5424TestSuite) TestParseDay_Valid(c *C) { - buff := []byte("02") - expected := 2 - - s.assertParseDay(c, expected, buff, 2, nil) -} - -func (s *Rfc5424TestSuite) TestParseFullDate_Invalid(c *C) { - buff := []byte("2013+10-28") - fd := fullDate{} - - s.assertParseFullDate(c, fd, buff, 4, syslogparser.ErrTimestampUnknownFormat) + for _, tc := range testCases { + p := NewParser([]byte(tc.input)) + obtained, err := p.parseHeader() - // --- + s.Require().Nil( + err, tc.description, + ) - buff = []byte("2013-10+28") - s.assertParseFullDate(c, fd, buff, 7, syslogparser.ErrTimestampUnknownFormat) -} + s.Require().Equal( + obtained, tc.expectedHdr, tc.description, + ) -func (s *Rfc5424TestSuite) TestParseFullDate_Valid(c *C) { - buff := []byte("2013-10-28") - fd := fullDate{ - year: 2013, - month: 10, - day: 28, + s.Require().Equal( + p.cursor, len(tc.input), tc.description, + ) } - - s.assertParseFullDate(c, fd, buff, len(buff), nil) -} - -func (s *Rfc5424TestSuite) TestParseHour_InvalidString(c *C) { - buff := []byte("azer") - expected := 0 - - s.assertParseHour(c, expected, buff, 2, ErrHourInvalid) } -func (s *Rfc5424TestSuite) TestParseHour_TooShort(c *C) { - buff := []byte("1") - expected := 0 - - s.assertParseHour(c, expected, buff, 0, syslogparser.ErrEOL) -} - -func (s *Rfc5424TestSuite) TestParseHour_InvalidRange(c *C) { - buff := []byte("-1") - expected := 0 - - s.assertParseHour(c, expected, buff, 2, ErrHourInvalid) - - // ---- - - buff = []byte("24") - - s.assertParseHour(c, expected, buff, 2, ErrHourInvalid) -} - -func (s *Rfc5424TestSuite) TestParseHour_Valid(c *C) { - buff := []byte("12") - expected := 12 - - s.assertParseHour(c, expected, buff, 2, nil) -} - -func (s *Rfc5424TestSuite) TestParseMinute_InvalidString(c *C) { - buff := []byte("azer") - expected := 0 - - s.assertParseMinute(c, expected, buff, 2, ErrMinuteInvalid) -} - -func (s *Rfc5424TestSuite) TestParseMinute_TooShort(c *C) { - buff := []byte("1") - expected := 0 - - s.assertParseMinute(c, expected, buff, 0, syslogparser.ErrEOL) -} - -func (s *Rfc5424TestSuite) TestParseMinute_InvalidRange(c *C) { - buff := []byte("-1") - expected := 0 +func (s *RFC5424TestSuite) TestParseTimestamp() { + tz := "-04:00" + tmpTZ, err := time.Parse("-07:00", tz) + s.Require().Nil(err) + s.Require().NotNil(tmpTZ) + + testCases := []struct { + description string + input string + expectedTS time.Time + expectedCursorPos int + expectedErr error + }{ + { + description: "UTC timestamp", + input: "1985-04-12T23:20:50.52Z", + expectedTS: time.Date( + 1985, time.April, 12, + 23, 20, 50, 52*10e6, + time.UTC, + ), + expectedCursorPos: 23, + expectedErr: nil, + }, + { + description: "numeric timezone", + input: "1985-04-12T19:20:50.52" + tz, + expectedTS: time.Date( + 1985, time.April, 12, + 19, 20, 50, 52*10e6, + tmpTZ.Location(), + ), + expectedCursorPos: 28, + expectedErr: nil, + }, + { + description: "timestamp with ms", + input: "2003-10-11T22:14:15.003Z", + expectedTS: time.Date( + 2003, time.October, 11, + 22, 14, 15, 3*10e5, + time.UTC, + ), + expectedCursorPos: 24, + expectedErr: nil, + }, + { + description: "timestamp with us", + input: "2003-08-24T05:14:15.000003" + tz, + expectedTS: time.Date( + 2003, time.August, 24, + 5, 14, 15, 3*10e2, + tmpTZ.Location(), + ), + expectedCursorPos: 32, + expectedErr: nil, + }, + { + description: "timestamp with ns", + input: "2003-08-24T05:14:15.000000003-07:00", + expectedCursorPos: 26, + expectedErr: syslogparser.ErrTimestampUnknownFormat, + }, + { + description: "nil timestamp", + input: "-", + expectedCursorPos: 1, + expectedErr: nil, + }, + } - s.assertParseMinute(c, expected, buff, 2, ErrMinuteInvalid) + for _, tc := range testCases { + p := NewParser([]byte(tc.input)) + obtained, err := p.parseTimestamp() - // ---- + s.Require().Equal( + err, tc.expectedErr, tc.description, + ) - buff = []byte("60") + tfmt := time.RFC3339Nano + s.Require().Equal( + obtained.Format(tfmt), + tc.expectedTS.Format(tfmt), + tc.description, + ) - s.assertParseMinute(c, expected, buff, 2, ErrMinuteInvalid) + s.Require().Equal( + p.cursor, tc.expectedCursorPos, tc.description, + ) + } } -func (s *Rfc5424TestSuite) TestParseMinute_Valid(c *C) { - buff := []byte("12") - expected := 12 +func (s *RFC5424TestSuite) TestParseYear() { + testCases := []struct { + description string + input string + expectedYear int + expectedCursorPos int + expectedErr error + }{ + { + description: "invalid year", + input: "1a2b", + expectedYear: 0, + expectedCursorPos: 4, + expectedErr: ErrYearInvalid, + }, + { + description: "year too short", + input: "123", + expectedYear: 0, + expectedCursorPos: 0, + expectedErr: syslogparser.ErrEOL, + }, + { + description: "valid", + input: "2013", + expectedYear: 2013, + expectedCursorPos: 4, + expectedErr: nil, + }, + } - s.assertParseMinute(c, expected, buff, 2, nil) + for _, tc := range testCases { + cursor := 0 + obtained, err := parseYear( + []byte(tc.input), + &cursor, + len(tc.input), + ) + + s.Require().Equal( + obtained, tc.expectedYear, tc.description, + ) + s.Require().Equal( + err, tc.expectedErr, tc.description, + ) + s.Require().Equal( + cursor, tc.expectedCursorPos, tc.description, + ) + } } -func (s *Rfc5424TestSuite) TestParseSecond_InvalidString(c *C) { - buff := []byte("azer") - expected := 0 +func (s *RFC5424TestSuite) TestParseMonth() { + testCases := []struct { + description string + input string + expectedMonth int + expectedCursorPos int + expectedErr error + }{ + { + description: "invalid string", + input: "ab", + expectedMonth: 0, + expectedCursorPos: 2, + expectedErr: ErrMonthInvalid, + }, + { + description: "invalid range 1/2", + input: "00", + expectedMonth: 0, + expectedCursorPos: 2, + expectedErr: ErrMonthInvalid, + }, + { + description: "invalid range 2/2", + input: "13", + expectedMonth: 0, + expectedCursorPos: 2, + expectedErr: ErrMonthInvalid, + }, + { + description: "too short", + input: "1", + expectedMonth: 0, + expectedCursorPos: 0, + expectedErr: syslogparser.ErrEOL, + }, + { + description: "valid", + input: "02", + expectedMonth: 2, + expectedCursorPos: 2, + expectedErr: nil, + }, + } - s.assertParseSecond(c, expected, buff, 2, ErrSecondInvalid) + for _, tc := range testCases { + cursor := 0 + obtained, err := parseMonth( + []byte(tc.input), + &cursor, + len(tc.input), + ) + + s.Require().Equal( + obtained, tc.expectedMonth, tc.description, + ) + s.Require().Equal( + err, tc.expectedErr, tc.description, + ) + s.Require().Equal( + cursor, tc.expectedCursorPos, tc.description, + ) + } } -func (s *Rfc5424TestSuite) TestParseSecond_TooShort(c *C) { - buff := []byte("1") - expected := 0 +func (s *RFC5424TestSuite) TestParseDay() { + testCases := []struct { + description string + input string + expectedDay int + expectedCursorPos int + expectedErr error + }{ + { + description: "invalid string", + input: "ab", + expectedDay: 0, + expectedCursorPos: 2, + expectedErr: ErrDayInvalid, + }, + { + description: "too short", + input: "1", + expectedDay: 0, + expectedCursorPos: 0, + expectedErr: syslogparser.ErrEOL, + }, + { + description: "invalid range 1/2", + input: "00", + expectedDay: 0, + expectedCursorPos: 2, + expectedErr: ErrDayInvalid, + }, + { + description: "invalid range 2/2", + input: "32", + expectedDay: 0, + expectedCursorPos: 2, + expectedErr: ErrDayInvalid, + }, + { + description: "valid", + input: "02", + expectedDay: 2, + expectedCursorPos: 2, + expectedErr: nil, + }, + } - s.assertParseSecond(c, expected, buff, 0, syslogparser.ErrEOL) + for _, tc := range testCases { + cursor := 0 + obtained, err := parseDay( + []byte(tc.input), + &cursor, + len(tc.input), + ) + + s.Require().Equal( + obtained, tc.expectedDay, tc.description, + ) + s.Require().Equal( + err, tc.expectedErr, tc.description, + ) + s.Require().Equal( + cursor, tc.expectedCursorPos, tc.description, + ) + } } -func (s *Rfc5424TestSuite) TestParseSecond_InvalidRange(c *C) { - buff := []byte("-1") - expected := 0 - - s.assertParseSecond(c, expected, buff, 2, ErrSecondInvalid) - - // ---- - - buff = []byte("60") +func (s *RFC5424TestSuite) TestParseFullDate() { + testCases := []struct { + description string + input string + expectedDate fullDate + expectedCursorPos int + expectedErr error + }{ + { + description: "invalid separator 1/2", + input: "2013+10-28", + expectedDate: fullDate{}, + expectedCursorPos: 4, + expectedErr: syslogparser.ErrTimestampUnknownFormat, + }, + { + description: "invalid separator 2/2", + input: "2013-10+28", + expectedDate: fullDate{}, + expectedCursorPos: 7, + expectedErr: syslogparser.ErrTimestampUnknownFormat, + }, + { + description: "valid", + input: "2013-10-28", + expectedDate: fullDate{2013, 10, 28}, + expectedCursorPos: 10, + expectedErr: nil, + }, + } - s.assertParseSecond(c, expected, buff, 2, ErrSecondInvalid) + for _, tc := range testCases { + cursor := 0 + obtained, err := parseFullDate( + []byte(tc.input), + &cursor, + len(tc.input), + ) + + s.Require().Equal( + err, tc.expectedErr, tc.description, + ) + s.Require().Equal( + obtained, tc.expectedDate, tc.description, + ) + s.Require().Equal( + cursor, tc.expectedCursorPos, tc.description, + ) + } } -func (s *Rfc5424TestSuite) TestParseSecond_Valid(c *C) { - buff := []byte("12") - expected := 12 +func (s *RFC5424TestSuite) TestParseHour() { + testCases := []struct { + description string + input string + expectedHour int + expectedCursorPos int + expectedErr error + }{ + { + description: "invalid", + input: "azer", + expectedHour: 0, + expectedCursorPos: 2, + expectedErr: ErrHourInvalid, + }, + { + description: "too short", + input: "1", + expectedHour: 0, + expectedCursorPos: 0, + expectedErr: syslogparser.ErrEOL, + }, + { + description: "invalid range 1/2", + input: "-1", + expectedHour: 0, + expectedCursorPos: 2, + expectedErr: ErrHourInvalid, + }, + { + description: "invalid range 2/2", + input: "24", + expectedHour: 0, + expectedCursorPos: 2, + expectedErr: ErrHourInvalid, + }, + { + description: "valid", + input: "12", + expectedHour: 12, + expectedCursorPos: 2, + expectedErr: nil, + }, + } - s.assertParseSecond(c, expected, buff, 2, nil) + for _, tc := range testCases { + cursor := 0 + obtained, err := parseHour( + []byte(tc.input), + &cursor, + len(tc.input), + ) + + s.Require().Equal( + obtained, tc.expectedHour, tc.description, + ) + s.Require().Equal( + err, tc.expectedErr, tc.description, + ) + s.Require().Equal( + cursor, tc.expectedCursorPos, tc.description, + ) + } } -func (s *Rfc5424TestSuite) TestParseSecFrac_InvalidString(c *C) { - buff := []byte("azerty") - expected := 0.0 +func (s *RFC5424TestSuite) TestParseMinute() { + testCases := []struct { + description string + input string + expectedMinute int + expectedCursorPos int + expectedErr error + }{ + { + description: "invalid", + input: "azer", + expectedMinute: 0, + expectedCursorPos: 2, + expectedErr: ErrMinuteInvalid, + }, + { + description: "too short", + input: "1", + expectedMinute: 0, + expectedCursorPos: 0, + expectedErr: syslogparser.ErrEOL, + }, + { + description: "invalid range 1/2", + input: "-1", + expectedMinute: 0, + expectedCursorPos: 2, + expectedErr: ErrMinuteInvalid, + }, + { + description: "invalid range 2/2", + input: "60", + expectedMinute: 0, + expectedCursorPos: 2, + expectedErr: ErrMinuteInvalid, + }, + { + description: "valid", + input: "12", + expectedMinute: 12, + expectedCursorPos: 2, + expectedErr: nil, + }, + } - s.assertParseSecFrac(c, expected, buff, 0, ErrSecFracInvalid) + for _, tc := range testCases { + cursor := 0 + obtained, err := parseMinute( + []byte(tc.input), + &cursor, + len(tc.input), + ) + + s.Require().Equal( + obtained, tc.expectedMinute, tc.description, + ) + s.Require().Equal( + err, tc.expectedErr, tc.description, + ) + s.Require().Equal( + cursor, tc.expectedCursorPos, tc.description, + ) + } } -func (s *Rfc5424TestSuite) TestParseSecFrac_NanoSeconds(c *C) { - buff := []byte("123456789") - expected := 0.123456 +func (s *RFC5424TestSuite) TestParseSecond() { + testCases := []struct { + description string + input string + expectedSecond int + expectedCursorPos int + expectedErr error + }{ + { + description: "invalid", + input: "azer", + expectedSecond: 0, + expectedCursorPos: 2, + expectedErr: ErrSecondInvalid, + }, + { + description: "too short", + input: "1", + expectedSecond: 0, + expectedCursorPos: 0, + expectedErr: syslogparser.ErrEOL, + }, + { + description: "invalid range 1/2", + input: "-1", + expectedSecond: 0, + expectedCursorPos: 2, + expectedErr: ErrSecondInvalid, + }, + { + description: "invalid range 2/2", + input: "60", + expectedSecond: 0, + expectedCursorPos: 2, + expectedErr: ErrSecondInvalid, + }, + { + description: "valid", + input: "12", + expectedSecond: 12, + expectedCursorPos: 2, + expectedErr: nil, + }, + } - s.assertParseSecFrac(c, expected, buff, 6, nil) + for _, tc := range testCases { + cursor := 0 + obtained, err := parseSecond( + []byte(tc.input), + &cursor, + len(tc.input), + ) + + s.Require().Equal( + obtained, tc.expectedSecond, tc.description, + ) + s.Require().Equal( + err, tc.expectedErr, tc.description, + ) + s.Require().Equal( + cursor, tc.expectedCursorPos, tc.description, + ) + } } -func (s *Rfc5424TestSuite) TestParseSecFrac_Valid(c *C) { - buff := []byte("0") - - expected := 0.0 - s.assertParseSecFrac(c, expected, buff, 1, nil) - - buff = []byte("52") - expected = 0.52 - s.assertParseSecFrac(c, expected, buff, 2, nil) - - buff = []byte("003") - expected = 0.003 - s.assertParseSecFrac(c, expected, buff, 3, nil) +func (s *RFC5424TestSuite) TestParseSecFrac() { + testCases := []struct { + description string + input string + expectedSecFrac float64 + expectedCursorPos int + expectedErr error + }{ + { + description: "invalid", + input: "azerty", + expectedSecFrac: 0, + expectedCursorPos: 0, + expectedErr: ErrSecFracInvalid, + }, + { + description: "nanoseconds", + input: "123456789", + expectedSecFrac: 0.123456, + expectedCursorPos: 6, + expectedErr: nil, + }, + { + description: "valid 1/4", + input: "0", + expectedSecFrac: 0, + expectedCursorPos: 1, + expectedErr: nil, + }, + { + description: "valid 2/4", + input: "52", + expectedSecFrac: 0.52, + expectedCursorPos: 2, + expectedErr: nil, + }, + { + description: "valid 3/4", + input: "003", + expectedSecFrac: 0.003, + expectedCursorPos: 3, + expectedErr: nil, + }, + { + description: "valid 4/4", + input: "000003", + expectedSecFrac: 0.000003, + expectedCursorPos: 6, + expectedErr: nil, + }, + } - buff = []byte("000003") - expected = 0.000003 - s.assertParseSecFrac(c, expected, buff, 6, nil) + for _, tc := range testCases { + cursor := 0 + obtained, err := parseSecFrac( + []byte(tc.input), + &cursor, + len(tc.input), + ) + + s.Require().Equal( + obtained, tc.expectedSecFrac, tc.description, + ) + s.Require().Equal( + err, tc.expectedErr, tc.description, + ) + s.Require().Equal( + cursor, tc.expectedCursorPos, tc.description, + ) + } } -func (s *Rfc5424TestSuite) TestParseNumericalTimeOffset_Valid(c *C) { +func (s *RFC5424TestSuite) TestParseNumericalTimeOffset() { buff := []byte("+02:00") cursor := 0 l := len(buff) tmpTs, err := time.Parse("-07:00", string(buff)) - c.Assert(err, IsNil) + s.Require().Nil(err) obtained, err := parseNumericalTimeOffset(buff, &cursor, l) - c.Assert(err, IsNil) + s.Require().Nil(err) expected := tmpTs.Location() - c.Assert(obtained, DeepEquals, expected) + s.Require().Equal(obtained, expected) - c.Assert(cursor, Equals, 6) + s.Require().Equal(cursor, 6) } -func (s *Rfc5424TestSuite) TestParseTimeOffset_Valid(c *C) { +func (s *RFC5424TestSuite) TestParseTimeOffset() { buff := []byte("Z") cursor := 0 l := len(buff) obtained, err := parseTimeOffset(buff, &cursor, l) - c.Assert(err, IsNil) - c.Assert(obtained, DeepEquals, time.UTC) - c.Assert(cursor, Equals, 1) + s.Require().Nil(err) + s.Require().Equal(obtained, time.UTC) + s.Require().Equal(cursor, 1) } -func (s *Rfc5424TestSuite) TestGetHourMin_Valid(c *C) { +func (s *RFC5424TestSuite) TestGetHourMin() { buff := []byte("12:34") cursor := 0 l := len(buff) - expectedHour := 12 - expectedMinute := 34 + expectedH := 12 + expectedM := 34 - obtainedHour, obtainedMinute, err := getHourMinute(buff, &cursor, l) - c.Assert(err, IsNil) - c.Assert(obtainedHour, Equals, expectedHour) - c.Assert(obtainedMinute, Equals, expectedMinute) + obtainedH, obtainedM, err := getHourMinute( + buff, &cursor, l, + ) - c.Assert(cursor, Equals, l) + s.Require().Nil(err) + s.Require().Equal(obtainedH, expectedH) + s.Require().Equal(obtainedM, expectedM) + + s.Require().Equal(cursor, l) } -func (s *Rfc5424TestSuite) TestParsePartialTime_Valid(c *C) { +func (s *RFC5424TestSuite) TestParsePartialTime() { buff := []byte("05:14:15.000003") cursor := 0 l := len(buff) - obtained, err := parsePartialTime(buff, &cursor, l) + obtained, err := parsePartialTime( + buff, &cursor, l, + ) + expected := partialTime{ hour: 5, minute: 14, @@ -580,22 +905,25 @@ func (s *Rfc5424TestSuite) TestParsePartialTime_Valid(c *C) { secFrac: 0.000003, } - c.Assert(err, IsNil) - c.Assert(obtained, DeepEquals, expected) - c.Assert(cursor, Equals, l) + s.Require().Nil(err) + s.Require().Equal(obtained, expected) + s.Require().Equal(cursor, l) } -func (s *Rfc5424TestSuite) TestParseFullTime_Valid(c *C) { +func (s *RFC5424TestSuite) TestParseFullTime() { tz := "-02:00" buff := []byte("05:14:15.000003" + tz) cursor := 0 l := len(buff) tmpTs, err := time.Parse("-07:00", string(tz)) - c.Assert(err, IsNil) + s.Require().Nil(err) - obtainedFt, err := parseFullTime(buff, &cursor, l) - expectedFt := fullTime{ + obtained, err := parseFullTime( + buff, &cursor, l, + ) + + expected := fullTime{ pt: partialTime{ hour: 5, minute: 14, @@ -605,115 +933,209 @@ func (s *Rfc5424TestSuite) TestParseFullTime_Valid(c *C) { loc: tmpTs.Location(), } - c.Assert(err, IsNil) - c.Assert(obtainedFt, DeepEquals, expectedFt) - c.Assert(cursor, Equals, 21) + s.Require().Nil(err) + s.Require().Equal(obtained, expected) + s.Require().Equal(cursor, 21) } -func (s *Rfc5424TestSuite) TestToNSec(c *C) { - fixtures := []float64{ - 0.52, - 0.003, - 0.000003, - } - - expected := []int{ - 520000000, - 3000000, - 3000, +func (s *RFC5424TestSuite) TestToNSec() { + testCases := map[float64]int{ + 0.52: 520000000, + 0.003: 3000000, + 0.000003: 3000, } - c.Assert(len(fixtures), Equals, len(expected)) - for i, f := range fixtures { - obtained, err := toNSec(f) - c.Assert(err, IsNil) - c.Assert(obtained, Equals, expected[i]) + for src, expected := range testCases { + obtained, err := toNSec(src) + s.Require().Nil(err) + s.Require().Equal(obtained, expected) } } -func (s *Rfc5424TestSuite) TestParseAppName_Valid(c *C) { - buff := []byte("su ") - appName := "su" - - s.assertParseAppName(c, appName, buff, 2, nil) -} - -func (s *Rfc5424TestSuite) TestParseAppName_TooLong(c *C) { - // > 48chars - buff := []byte("suuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu ") - appName := "" - - s.assertParseAppName(c, appName, buff, 48, ErrInvalidAppName) -} - -func (s *Rfc5424TestSuite) TestParseProcId_Valid(c *C) { - buff := []byte("123foo ") - procId := "123foo" - - s.assertParseProcId(c, procId, buff, 6, nil) -} - -func (s *Rfc5424TestSuite) TestParseProcId_TooLong(c *C) { - // > 128chars - buff := []byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab ") - procId := "" - - s.assertParseProcId(c, procId, buff, 128, ErrInvalidProcId) -} - -func (s *Rfc5424TestSuite) TestParseMsgId_Valid(c *C) { - buff := []byte("123foo ") - procId := "123foo" - - s.assertParseMsgId(c, procId, buff, 6, nil) -} - -func (s *Rfc5424TestSuite) TestParseMsgId_TooLong(c *C) { - // > 32chars - buff := []byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ") - procId := "" - - s.assertParseMsgId(c, procId, buff, 32, ErrInvalidMsgId) -} - -func (s *Rfc5424TestSuite) TestParseStructuredData_NilValue(c *C) { - // > 32chars - buff := []byte("-") - sdData := "-" +func (s *RFC5424TestSuite) TestParseAppName() { + testCases := []struct { + description string + input string + expectedAppName string + expectedCursorPos int + expectedErr error + }{ + { + description: "valid", + input: "su ", + expectedAppName: "su", + expectedCursorPos: 2, + expectedErr: nil, + }, + { + description: "too long", + input: "suuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu ", + expectedAppName: "", + expectedCursorPos: 48, + expectedErr: ErrInvalidAppName, + }, + } - s.assertParseSdName(c, sdData, buff, 1, nil) + for _, tc := range testCases { + p := NewParser([]byte(tc.input)) + obtained, err := p.parseAppName() + + s.Require().Equal( + err, tc.expectedErr, tc.description, + ) + s.Require().Equal( + obtained, tc.expectedAppName, tc.description, + ) + s.Require().Equal( + p.cursor, tc.expectedCursorPos, tc.description, + ) + } } -func (s *Rfc5424TestSuite) TestParseStructuredData_SingleStructuredData(c *C) { - sdData := `[exampleSDID@32473 iut="3" eventSource="Application"eventID="1011"]` - buff := []byte(sdData) +func (s *RFC5424TestSuite) TestParseProcID() { + testCases := []struct { + description string + input string + expectedProcID string + expectedCursorPos int + expectedErr error + }{ + { + description: "valid", + input: "123foo ", + expectedProcID: "123foo", + expectedCursorPos: 6, + expectedErr: nil, + }, + { + description: "too long", + input: strings.Repeat("a", 129), + expectedProcID: "", + expectedCursorPos: 128, + expectedErr: ErrInvalidProcId, + }, + } - s.assertParseSdName(c, sdData, buff, len(buff), nil) + for _, tc := range testCases { + p := NewParser([]byte(tc.input)) + obtained, err := p.parseProcId() + + s.Require().Equal( + err, tc.expectedErr, tc.description, + ) + s.Require().Equal( + obtained, tc.expectedProcID, tc.description, + ) + s.Require().Equal( + p.cursor, tc.expectedCursorPos, tc.description, + ) + } } -func (s *Rfc5424TestSuite) TestParseStructuredData_MultipleStructuredData(c *C) { - sdData := `[exampleSDID@32473 iut="3" eventSource="Application"eventID="1011"][examplePriority@32473 class="high"]` - buff := []byte(sdData) +func (s *RFC5424TestSuite) TestParseMsgID() { + testCases := []struct { + description string + input string + expectedMsgID string + expectedCursorPos int + expectedErr error + }{ + { + description: "valid", + input: "123foo ", + expectedMsgID: "123foo", + expectedCursorPos: 6, + expectedErr: nil, + }, + { + description: "too long", + input: strings.Repeat("a", 33), + expectedMsgID: "", + expectedCursorPos: 32, + expectedErr: ErrInvalidMsgId, + }, + } - s.assertParseSdName(c, sdData, buff, len(buff), nil) + for _, tc := range testCases { + p := NewParser([]byte(tc.input)) + obtained, err := p.parseMsgId() + + s.Require().Equal( + err, tc.expectedErr, tc.description, + ) + s.Require().Equal( + obtained, tc.expectedMsgID, tc.description, + ) + s.Require().Equal( + p.cursor, tc.expectedCursorPos, tc.description, + ) + } } -func (s *Rfc5424TestSuite) TestParseStructuredData_MultipleStructuredDataInvalid(c *C) { - a := `[exampleSDID@32473 iut="3" eventSource="Application"eventID="1011"]` - sdData := a + ` [examplePriority@32473 class="high"]` - buff := []byte(sdData) +func (s *RFC5424TestSuite) TestParseStructuredData() { + testCases := []struct { + description string + input string + expectedData string + expectedCursorPos int + expectedErr error + }{ + { + description: "nil", + input: "-", + expectedData: "-", + expectedCursorPos: 1, + expectedErr: nil, + }, + { + description: "single", + input: `[exampleSDID@32473 iut="3" eventSource="Application"eventID="1011"]`, + expectedData: `[exampleSDID@32473 iut="3" eventSource="Application"eventID="1011"]`, + expectedCursorPos: 67, + expectedErr: nil, + }, + { + description: "multiple", + input: `[exampleSDID@32473 iut="3" eventSource="Application"eventID="1011"][examplePriority@32473 class="high"]`, + expectedData: `[exampleSDID@32473 iut="3" eventSource="Application"eventID="1011"][examplePriority@32473 class="high"]`, + expectedCursorPos: 103, + expectedErr: nil, + }, + { + description: "multiple invalid", + input: `[exampleSDID@32473 iut="3" eventSource="Application"eventID="1011"] [examplePriority@32473 class="high"]`, + expectedData: `[exampleSDID@32473 iut="3" eventSource="Application"eventID="1011"]`, + expectedCursorPos: 67, + expectedErr: nil, + }, + } - s.assertParseSdName(c, a, buff, len(a), nil) + for _, tc := range testCases { + cursor := 0 + obtained, err := parseStructuredData( + []byte(tc.input), + &cursor, + len(tc.input), + ) + + s.Require().Equal( + err, tc.expectedErr, tc.description, + ) + s.Require().Equal( + obtained, tc.expectedData, tc.description, + ) + s.Require().Equal( + cursor, tc.expectedCursorPos, tc.description, + ) + } } -// ------------- - -func (s *Rfc5424TestSuite) BenchmarkParseTimestamp(c *C) { +func BenchmarkParseTimestamp(b *testing.B) { buff := []byte("2003-08-24T05:14:15.000003-07:00") p := NewParser(buff) - for i := 0; i < c.N; i++ { + for i := 0; i < b.N; i++ { _, err := p.parseTimestamp() if err != nil { panic(err) @@ -723,12 +1145,12 @@ func (s *Rfc5424TestSuite) BenchmarkParseTimestamp(c *C) { } } -func (s *Rfc5424TestSuite) BenchmarkParseHeader(c *C) { +func BenchmarkParseHeader(b *testing.B) { buff := []byte("<165>1 2003-10-11T22:14:15.003Z mymachine.example.com su 123 ID47") p := NewParser(buff) - for i := 0; i < c.N; i++ { + for i := 0; i < b.N; i++ { _, err := p.parseHeader() if err != nil { panic(err) @@ -738,12 +1160,12 @@ func (s *Rfc5424TestSuite) BenchmarkParseHeader(c *C) { } } -func (s *Rfc5424TestSuite) BenchmarkParseFull(c *C) { +func BenchmarkParseFull(b *testing.B) { msg := `<165>1 2003-10-11T22:14:15.003Z mymachine.example.com evntslog - ID47 [exampleSDID@32473 iut="3" eventSource="Application" eventID="1011"] An application event log entry...` p := NewParser([]byte(msg)) - for i := 0; i < c.N; i++ { + for i := 0; i < b.N; i++ { _, err := p.parseHeader() if err != nil { panic(err) @@ -753,121 +1175,8 @@ func (s *Rfc5424TestSuite) BenchmarkParseFull(c *C) { } } -// ------------- - -func (s *Rfc5424TestSuite) assertTimestamp(c *C, ts time.Time, b []byte, expC int, e error) { - p := NewParser(b) - obtained, err := p.parseTimestamp() - c.Assert(err, Equals, e) - - tFmt := time.RFC3339Nano - c.Assert(obtained.Format(tFmt), Equals, ts.Format(tFmt)) - - c.Assert(p.cursor, Equals, expC) -} - -func (s *Rfc5424TestSuite) assertFindNextSpace(c *C, nextSpace int, b []byte, e error) { - obtained, err := syslogparser.FindNextSpace(b, 0, len(b)) - c.Assert(obtained, Equals, nextSpace) - c.Assert(err, Equals, e) -} - -func (s *Rfc5424TestSuite) assertParseYear(c *C, year int, b []byte, expC int, e error) { - cursor := 0 - obtained, err := parseYear(b, &cursor, len(b)) - c.Assert(obtained, Equals, year) - c.Assert(err, Equals, e) - c.Assert(cursor, Equals, expC) -} - -func (s *Rfc5424TestSuite) assertParseMonth(c *C, month int, b []byte, expC int, e error) { - cursor := 0 - obtained, err := parseMonth(b, &cursor, len(b)) - c.Assert(obtained, Equals, month) - c.Assert(err, Equals, e) - c.Assert(cursor, Equals, expC) -} - -func (s *Rfc5424TestSuite) assertParseDay(c *C, day int, b []byte, expC int, e error) { - cursor := 0 - obtained, err := parseDay(b, &cursor, len(b)) - c.Assert(obtained, Equals, day) - c.Assert(err, Equals, e) - c.Assert(cursor, Equals, expC) -} - -func (s *Rfc5424TestSuite) assertParseFullDate(c *C, fd fullDate, b []byte, expC int, e error) { - cursor := 0 - obtained, err := parseFullDate(b, &cursor, len(b)) - c.Assert(err, Equals, e) - c.Assert(obtained, Equals, fd) - c.Assert(cursor, Equals, expC) -} - -func (s *Rfc5424TestSuite) assertParseHour(c *C, hour int, b []byte, expC int, e error) { - cursor := 0 - obtained, err := parseHour(b, &cursor, len(b)) - c.Assert(obtained, Equals, hour) - c.Assert(err, Equals, e) - c.Assert(cursor, Equals, expC) -} - -func (s *Rfc5424TestSuite) assertParseMinute(c *C, minute int, b []byte, expC int, e error) { - cursor := 0 - obtained, err := parseMinute(b, &cursor, len(b)) - c.Assert(obtained, Equals, minute) - c.Assert(err, Equals, e) - c.Assert(cursor, Equals, expC) -} - -func (s *Rfc5424TestSuite) assertParseSecond(c *C, second int, b []byte, expC int, e error) { - cursor := 0 - obtained, err := parseSecond(b, &cursor, len(b)) - c.Assert(obtained, Equals, second) - c.Assert(err, Equals, e) - c.Assert(cursor, Equals, expC) -} - -func (s *Rfc5424TestSuite) assertParseSecFrac(c *C, secFrac float64, b []byte, expC int, e error) { - cursor := 0 - obtained, err := parseSecFrac(b, &cursor, len(b)) - c.Assert(obtained, Equals, secFrac) - c.Assert(err, Equals, e) - c.Assert(cursor, Equals, expC) -} - -func (s *Rfc5424TestSuite) assertParseAppName(c *C, appName string, b []byte, expC int, e error) { - p := NewParser(b) - obtained, err := p.parseAppName() - - c.Assert(err, Equals, e) - c.Assert(obtained, Equals, appName) - c.Assert(p.cursor, Equals, expC) -} - -func (s *Rfc5424TestSuite) assertParseProcId(c *C, procId string, b []byte, expC int, e error) { - p := NewParser(b) - obtained, err := p.parseProcId() - - c.Assert(err, Equals, e) - c.Assert(obtained, Equals, procId) - c.Assert(p.cursor, Equals, expC) -} - -func (s *Rfc5424TestSuite) assertParseMsgId(c *C, msgId string, b []byte, expC int, e error) { - p := NewParser(b) - obtained, err := p.parseMsgId() - - c.Assert(err, Equals, e) - c.Assert(obtained, Equals, msgId) - c.Assert(p.cursor, Equals, expC) -} - -func (s *Rfc5424TestSuite) assertParseSdName(c *C, sdData string, b []byte, expC int, e error) { - cursor := 0 - obtained, err := parseStructuredData(b, &cursor, len(b)) - - c.Assert(err, Equals, e) - c.Assert(obtained, Equals, sdData) - c.Assert(cursor, Equals, expC) +func TestRFC5424TestSuite(t *testing.T) { + suite.Run( + t, new(RFC5424TestSuite), + ) } diff --git a/syslogparser.go b/syslogparser.go index 3073e20..d49e97d 100644 --- a/syslogparser.go +++ b/syslogparser.go @@ -139,6 +139,7 @@ func IsDigit(c byte) bool { return c >= '0' && c <= '9' } +// TODO: this should return a *Priority func newPriority(p int) Priority { // The Priority value is calculated by first multiplying the Facility // number by 8 and then adding the numerical value of the Severity. diff --git a/syslogparser_test.go b/syslogparser_test.go index 8285329..83abd61 100644 --- a/syslogparser_test.go +++ b/syslogparser_test.go @@ -3,146 +3,254 @@ package syslogparser import ( "testing" - . "gopkg.in/check.v1" + "github.com/stretchr/testify/suite" ) -// Hooks up gocheck into the gotest runner. -func Test(t *testing.T) { TestingT(t) } - type CommonTestSuite struct { + suite.Suite } -var _ = Suite(&CommonTestSuite{}) - -func (s *CommonTestSuite) TestParsePriority_Empty(c *C) { - pri := newPriority(0) - buff := []byte("") - start := 0 - - s.assertPriority(c, pri, buff, start, start, ErrPriorityEmpty) -} - -func (s *CommonTestSuite) TestParsePriority_NoStart(c *C) { - pri := newPriority(0) - buff := []byte("7>") - start := 0 +func (s *CommonTestSuite) TestParsePriority() { + testCases := []struct { + description string + input []byte + expectedPri Priority + expectedCursorPos int + expectedErr error + }{ + { + description: "empty priority", + input: []byte(""), + expectedPri: newPriority(0), + expectedCursorPos: 0, + expectedErr: ErrPriorityEmpty, + }, + { + description: "no start", + input: []byte("7>"), + expectedPri: newPriority(0), + expectedCursorPos: 0, + expectedErr: ErrPriorityNoStart, + }, + { + description: "no end", + input: []byte("<77"), + expectedPri: newPriority(0), + expectedCursorPos: 0, + expectedErr: ErrPriorityNoEnd, + }, + { + description: "too short", + input: []byte("<>"), + expectedPri: newPriority(0), + expectedCursorPos: 0, + expectedErr: ErrPriorityTooShort, + }, + { + description: "too long", + input: []byte("<1233>"), + expectedPri: newPriority(0), + expectedCursorPos: 0, + expectedErr: ErrPriorityTooLong, + }, + { + description: "no digits", + input: []byte("<7a8>"), + expectedPri: newPriority(0), + expectedCursorPos: 0, + expectedErr: ErrPriorityNonDigit, + }, + { + description: "all good", + input: []byte("<190>"), + expectedPri: newPriority(190), + expectedCursorPos: 5, + expectedErr: nil, + }, + } - s.assertPriority(c, pri, buff, start, start, ErrPriorityNoStart) -} + for _, tc := range testCases { + cursor := 0 -func (s *CommonTestSuite) TestParsePriority_NoEnd(c *C) { - pri := newPriority(0) - buff := []byte("<77") - start := 0 + obtained, err := ParsePriority( + tc.input, &cursor, len(tc.input), + ) - s.assertPriority(c, pri, buff, start, start, ErrPriorityNoEnd) -} + s.Require().Equal( + obtained, tc.expectedPri, tc.description, + ) -func (s *CommonTestSuite) TestParsePriority_TooShort(c *C) { - pri := newPriority(0) - buff := []byte("<>") - start := 0 + s.Require().Equal( + cursor, tc.expectedCursorPos, tc.description, + ) - s.assertPriority(c, pri, buff, start, start, ErrPriorityTooShort) + s.Require().Equal( + err, tc.expectedErr, tc.description, + ) + } } -func (s *CommonTestSuite) TestParsePriority_TooLong(c *C) { - pri := newPriority(0) - buff := []byte("<1233>") - start := 0 - - s.assertPriority(c, pri, buff, start, start, ErrPriorityTooLong) +func (s *CommonTestSuite) TestNewPriority() { + s.Require().Equal( + newPriority(165), + Priority{ + P: 165, + F: Facility{Value: 20}, + S: Severity{Value: 5}, + }, + ) } -func (s *CommonTestSuite) TestParsePriority_NoDigits(c *C) { - pri := newPriority(0) - buff := []byte("<7a8>") - start := 0 +func (s *CommonTestSuite) TestParseVersion() { + testCases := []struct { + description string + input []byte + expectedVersion int + expectedCursorPos int + expectedErr error + }{ + { + description: "not found", + input: []byte("<123>"), + expectedVersion: NO_VERSION, + expectedCursorPos: 5, + expectedErr: ErrVersionNotFound, + }, + { + description: "non digit", + input: []byte("<123>a"), + expectedVersion: NO_VERSION, + expectedCursorPos: 6, + expectedErr: nil, + }, + { + description: "all good", + input: []byte("<123>1"), + expectedVersion: 1, + expectedCursorPos: 6, + expectedErr: nil, + }, + } - s.assertPriority(c, pri, buff, start, start, ErrPriorityNonDigit) -} + for _, tc := range testCases { + cursor := 5 -func (s *CommonTestSuite) TestParsePriority_Ok(c *C) { - pri := newPriority(190) - buff := []byte("<190>") - start := 0 + obtained, err := ParseVersion( + tc.input, &cursor, len(tc.input), + ) - s.assertPriority(c, pri, buff, start, start+5, nil) -} + s.Require().Equal( + obtained, tc.expectedVersion, tc.description, + ) -func (s *CommonTestSuite) TestNewPriority(c *C) { - obtained := newPriority(165) + s.Require().Equal( + cursor, tc.expectedCursorPos, tc.description, + ) - expected := Priority{ - P: 165, - F: Facility{Value: 20}, - S: Severity{Value: 5}, + s.Require().Equal( + err, tc.expectedErr, tc.description, + ) } - - c.Assert(obtained, DeepEquals, expected) } -func (s *CommonTestSuite) TestParseVersion_NotFound(c *C) { - buff := []byte("<123>") - start := 5 +func (s *CommonTestSuite) TestParseHostname() { + testCases := []struct { + description string + input []byte + expectedHostname string + expectedCursorPos int + }{ + { + description: "invalid", + input: []byte("foo name"), + expectedHostname: "foo", + expectedCursorPos: 3, + }, + { + description: "valid", + input: []byte("ubuntu11.somehost.com" + " "), + expectedHostname: "ubuntu11.somehost.com", + expectedCursorPos: len("ubuntu11.somehost.com"), + }, + } - s.assertVersion(c, NO_VERSION, buff, start, start, ErrVersionNotFound) -} + for _, tc := range testCases { + cursor := 0 -func (s *CommonTestSuite) TestParseVersion_NonDigit(c *C) { - buff := []byte("<123>a") - start := 5 + obtained, err := ParseHostname( + tc.input, &cursor, len(tc.input), + ) - s.assertVersion(c, NO_VERSION, buff, start, start+1, nil) -} + s.Require().Equal( + obtained, tc.expectedHostname, tc.description, + ) -func (s *CommonTestSuite) TestParseVersion_Ok(c *C) { - buff := []byte("<123>1") - start := 5 + s.Require().Equal( + cursor, tc.expectedCursorPos, tc.description, + ) - s.assertVersion(c, 1, buff, start, start+1, nil) + s.Require().Nil(err) + } } -func (s *CommonTestSuite) TestParseHostname_Invalid(c *C) { - // XXX : no year specified. Assumed current year - // XXX : no timezone specified. Assume UTC - buff := []byte("foo name") - start := 0 - hostname := "foo" +func (s *CommonTestSuite) TestDetectRFC_3164() { + p, err := DetectRFC([]byte("<34>Oct 11 22:14:15 ...")) - s.assertHostname(c, hostname, buff, start, 3, nil) + s.Require().Nil(err) + s.Require().Equal(p, RFC(RFC_3164)) } -func (s *CommonTestSuite) TestParseHostname_Valid(c *C) { - // XXX : no year specified. Assumed current year - // XXX : no timezone specified. Assume UTC - hostname := "ubuntu11.somehost.com" - buff := []byte(hostname + " ") - start := 0 +func (s *CommonTestSuite) TestDetectRFC_5424() { + p, err := DetectRFC( + []byte("<165>1 2003-10-11T22:14:15.003Z ..."), + ) - s.assertHostname(c, hostname, buff, start, len(hostname), nil) + s.Require().Nil(err) + s.Require().Equal(p, RFC(RFC_5424)) } -func (s *CommonTestSuite) TestDetectRFC_3164(c *C) { - p, err := DetectRFC([]byte("<34>Oct 11 22:14:15 ...")) +func (s *CommonTestSuite) TestFindNextSpace() { + testCases := []struct { + description string + input []byte + expectedCursorPos int + expectedErr error + }{ + { + description: "no space", + input: []byte("aaaaaa"), + expectedCursorPos: 0, + expectedErr: ErrNoSpace, + }, + { + description: "space found", + input: []byte("foo bar baz"), + expectedCursorPos: 4, + expectedErr: nil, + }, + } - c.Assert(err, Equals, nil) - c.Assert(p, Equals, RFC(RFC_3164)) -} + for _, tc := range testCases { + obtained, err := FindNextSpace( + tc.input, 0, len(tc.input), + ) -func (s *CommonTestSuite) TestDetectRFC_5424(c *C) { - p, err := DetectRFC([]byte("<165>1 2003-10-11T22:14:15.003Z ...")) + s.Require().Equal( + obtained, tc.expectedCursorPos, tc.description, + ) - c.Assert(err, Equals, nil) - c.Assert(p, Equals, RFC(RFC_5424)) + s.Require().Equal( + err, tc.expectedErr, tc.description, + ) + } } -func (s *CommonTestSuite) BenchmarkParsePriority(c *C) { +func BenchmarkParsePriority(b *testing.B) { buff := []byte("<190>") var start int l := len(buff) - for i := 0; i < c.N; i++ { + for i := 0; i < b.N; i++ { start = 0 _, err := ParsePriority(buff, &start, l) if err != nil { @@ -151,12 +259,12 @@ func (s *CommonTestSuite) BenchmarkParsePriority(c *C) { } } -func (s *CommonTestSuite) BenchmarkParseVersion(c *C) { +func BenchmarkParseVersion(b *testing.B) { buff := []byte("<123>1") start := 5 l := len(buff) - for i := 0; i < c.N; i++ { + for i := 0; i < b.N; i++ { start = 0 _, err := ParseVersion(buff, &start, l) if err != nil { @@ -165,10 +273,10 @@ func (s *CommonTestSuite) BenchmarkParseVersion(c *C) { } } -func (s *CommonTestSuite) BenchmarkDetectRFC(c *C) { +func BenchmarkDetectRFC(b *testing.B) { buff := []byte("<165>1 2003-10-11T22:14:15.003Z ...") - for i := 0; i < c.N; i++ { + for i := 0; i < b.N; i++ { _, err := DetectRFC(buff) if err != nil { panic(err) @@ -176,23 +284,8 @@ func (s *CommonTestSuite) BenchmarkDetectRFC(c *C) { } } -func (s *CommonTestSuite) assertPriority(c *C, p Priority, b []byte, cursor int, expC int, e error) { - obtained, err := ParsePriority(b, &cursor, len(b)) - c.Assert(obtained, DeepEquals, p) - c.Assert(cursor, Equals, expC) - c.Assert(err, Equals, e) -} - -func (s *CommonTestSuite) assertVersion(c *C, version int, b []byte, cursor int, expC int, e error) { - obtained, err := ParseVersion(b, &cursor, len(b)) - c.Assert(obtained, Equals, version) - c.Assert(cursor, Equals, expC) - c.Assert(err, Equals, e) -} - -func (s *CommonTestSuite) assertHostname(c *C, h string, b []byte, cursor int, expC int, e error) { - obtained, err := ParseHostname(b, &cursor, len(b)) - c.Assert(obtained, Equals, h) - c.Assert(cursor, Equals, expC) - c.Assert(err, Equals, e) +func TestCommonTestSuite(t *testing.T) { + suite.Run( + t, new(CommonTestSuite), + ) }