parse_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. package rfc5424
  2. import (
  3. "testing"
  4. "time"
  5. )
  6. func TestPri(t *testing.T) {
  7. tests := []struct {
  8. input string
  9. expected int
  10. expectedErr string
  11. }{
  12. {"<0>", 0, ""},
  13. {"<19>", 19, ""},
  14. {"<200>", 200, ""},
  15. {"<4999>", 0, "PRI must be up to 3 characters long"},
  16. {"<123", 0, "PRI must end with '>'"},
  17. {"123>", 0, "PRI must start with '<'"},
  18. {"<abc>", 0, "PRI must be a number"},
  19. }
  20. for _, test := range tests {
  21. test := test
  22. t.Run(test.input, func(t *testing.T) {
  23. r := &RFC5424{}
  24. r.buf = []byte(test.input)
  25. r.len = len(r.buf)
  26. err := r.parsePRI()
  27. if err != nil {
  28. if test.expectedErr != "" {
  29. if err.Error() != test.expectedErr {
  30. t.Errorf("expected error %s, got %s", test.expectedErr, err)
  31. }
  32. } else {
  33. t.Errorf("unexpected error: %s", err)
  34. }
  35. } else {
  36. if test.expectedErr != "" {
  37. t.Errorf("expected error %s, got no error", test.expectedErr)
  38. } else if r.PRI != test.expected {
  39. t.Errorf("expected %d, got %d", test.expected, r.PRI)
  40. }
  41. }
  42. })
  43. }
  44. }
  45. func TestHostname(t *testing.T) {
  46. tests := []struct {
  47. input string
  48. expected string
  49. expectedErr string
  50. strictHostname bool
  51. }{
  52. {"127.0.0.1", "127.0.0.1", "", false},
  53. {"::1", "::1", "", false},
  54. {"-", "", "", false},
  55. {"foo.-bar", "", "hostname is not valid", true},
  56. {"foo-.bar", "", "hostname is not valid", true},
  57. {"foo123.bar", "foo123.bar", "", true},
  58. {"a..", "", "hostname is not valid", true},
  59. {"foo.bar", "foo.bar", "", false},
  60. {"foo,bar", "foo,bar", "", false},
  61. {"foo,bar", "", "hostname is not valid", true},
  62. {".", ".", "", true},
  63. {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "", "hostname is not valid", true},
  64. {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.bla", "", "hostname is not valid", true},
  65. {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.bla", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.bla", "", false},
  66. {"a.foo-", "", "hostname is not valid", true},
  67. }
  68. for _, test := range tests {
  69. test := test
  70. t.Run(test.input, func(t *testing.T) {
  71. opts := []RFC5424Option{}
  72. if test.strictHostname {
  73. opts = append(opts, WithStrictHostname())
  74. }
  75. r := NewRFC5424Parser(opts...)
  76. r.buf = []byte(test.input)
  77. r.len = len(r.buf)
  78. err := r.parseHostname()
  79. if err != nil {
  80. if test.expectedErr != "" {
  81. if err.Error() != test.expectedErr {
  82. t.Errorf("expected error %s, got %s", test.expectedErr, err)
  83. }
  84. } else {
  85. t.Errorf("unexpected error: %s", err)
  86. }
  87. } else {
  88. if test.expectedErr != "" {
  89. t.Errorf("expected error %s, got no error", test.expectedErr)
  90. } else if r.Hostname != test.expected {
  91. t.Errorf("expected %s, got %s", test.expected, r.Hostname)
  92. }
  93. }
  94. })
  95. }
  96. }
  97. func TestParse(t *testing.T) {
  98. type expected struct {
  99. Timestamp time.Time
  100. Hostname string
  101. Tag string
  102. PID string
  103. Message string
  104. PRI int
  105. MsgID string
  106. }
  107. tests := []struct {
  108. name string
  109. input string
  110. expected expected
  111. expectedErr string
  112. opts []RFC5424Option
  113. }{
  114. {
  115. "valid msg",
  116. `<13>1 2021-05-18T11:58:40.828081+02:42 mantis sshd 49340 - [timeQuality isSynced="0" tzKnown="1"] blabla`, expected{
  117. Timestamp: time.Date(2021, 5, 18, 11, 58, 40, 828081000, time.FixedZone("+0242", 9720)),
  118. Hostname: "mantis",
  119. Tag: "sshd",
  120. PID: "49340",
  121. MsgID: "",
  122. Message: "blabla",
  123. PRI: 13,
  124. }, "", []RFC5424Option{},
  125. },
  126. {
  127. "valid msg with msgid",
  128. `<13>1 2021-05-18T11:58:40.828081+02:42 mantis foobar 49340 123123 [timeQuality isSynced="0" tzKnown="1"] blabla`, expected{
  129. Timestamp: time.Date(2021, 5, 18, 11, 58, 40, 828081000, time.FixedZone("+0242", 9720)),
  130. Hostname: "mantis",
  131. Tag: "foobar",
  132. PID: "49340",
  133. MsgID: "123123",
  134. Message: "blabla",
  135. PRI: 13,
  136. }, "", []RFC5424Option{},
  137. },
  138. {
  139. "valid msg with repeating SD",
  140. `<13>1 2021-05-18T11:58:40.828081+02:42 mantis foobar 49340 123123 [timeQuality isSynced="0" tzKnown="1"][foo="bar][a] blabla`, expected{
  141. Timestamp: time.Date(2021, 5, 18, 11, 58, 40, 828081000, time.FixedZone("+0242", 9720)),
  142. Hostname: "mantis",
  143. Tag: "foobar",
  144. PID: "49340",
  145. MsgID: "123123",
  146. Message: "blabla",
  147. PRI: 13,
  148. }, "", []RFC5424Option{},
  149. },
  150. {
  151. "invalid SD",
  152. `<13>1 2021-05-18T11:58:40.828081+02:00 mantis foobar 49340 123123 [timeQuality asd`, expected{}, "structured data must end with ']'", []RFC5424Option{},
  153. },
  154. {
  155. "invalid version",
  156. `<13>42 2021-05-18T11:58:40.828081+02:00 mantis foobar 49340 123123 [timeQuality isSynced="0" tzKnown="1"] blabla`, expected{}, "version must be 1", []RFC5424Option{},
  157. },
  158. {
  159. "invalid message",
  160. `<13>1`, expected{}, "version must be followed by a space", []RFC5424Option{},
  161. },
  162. {
  163. "valid msg with empty fields",
  164. `<13>1 - foo - - - - blabla`, expected{
  165. Timestamp: time.Now().UTC().Round(0),
  166. Hostname: "foo",
  167. PRI: 13,
  168. Message: "blabla",
  169. }, "", []RFC5424Option{},
  170. },
  171. {
  172. "valid msg with empty fields",
  173. `<13>1 - - - - - - blabla`, expected{
  174. Timestamp: time.Now().UTC().Round(0),
  175. PRI: 13,
  176. Message: "blabla",
  177. }, "", []RFC5424Option{},
  178. },
  179. {
  180. "valid msg with escaped SD",
  181. `<13>1 2022-05-24T10:57:39Z testhostname unknown - sn="msgid" [foo="\]" bar="a\""][a b="[\]" c] testmessage`,
  182. expected{
  183. PRI: 13,
  184. Timestamp: time.Date(2022, 5, 24, 10, 57, 39, 0, time.UTC),
  185. Tag: "unknown",
  186. Hostname: "testhostname",
  187. MsgID: `sn="msgid"`,
  188. Message: `testmessage`,
  189. }, "", []RFC5424Option{},
  190. },
  191. {
  192. "valid complex msg",
  193. `<13>1 2022-05-24T10:57:39Z myhostname unknown - sn="msgid" [all@0 request="/dist/precache-manifest.58b57debe6bc4f96698da0dc314461e9.js" src_ip_geo_country="DE" MONTH="May" COMMONAPACHELOG="1.1.1.1 - - [24/May/2022:10:57:37 +0200\] \"GET /dist/precache-manifest.58b57debe6bc4f96698da0dc314461e9.js HTTP/2.0\" 304 0" auth="-" HOUR="10" gl2_remote_ip="172.31.32.142" ident="-" gl2_remote_port="43375" BASE10NUM="[2.0, 304, 0\]" pid="-1" program="nginx" gl2_source_input="623ed3440183476d61cff974" INT="+0200" is_private_ip="false" YEAR="2022" src_ip_geo_city="Achern" clientip="1.1.1.1" USERNAME="-" src_ip_geo_location="48.6306,8.0743" gl2_source_node="8620c2bb-dbb7-4535-b1ce-83df223acd8d" MINUTE="57" timestamp="2022-05-24T08:57:37.000Z" src_ip_asn="3320" level="5" IP="1.1.1.1" IPV4="1.1.1.1" verb="GET" gl2_message_id="01G3TMJFAMFS4H60QSF7M029R0" TIME="10:57:37" USER="-" src_ip_asn_owner="Deutsche Telekom AG" response="304" bytes="0" SECOND="37" httpversion="2.0" _id="906ce155-db3f-11ec-b25f-0a189ba2c64e" facility="user" MONTHDAY="24"] source: sn="www.foobar.com" | message: 1.1.1.1 - - [24/May/2022:10:57:37 +0200] "GET /dist/precache-manifest.58b57debe6bc4f96698da0dc314461e9.js HTTP/2.0" 304 0 "https://www.foobar.com/sw.js" "Mozilla/5.0 (Linux; Android 9; ANE-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.61 Mobile Safari/537.36" "-" "www.foobar.com" sn="www.foobar.com" rt=0.000 ua="-" us="-" ut="-" ul="-" cs=HIT { request: /dist/precache-manifest.58b57debe6bc4f96698da0dc314461e9.js | src_ip_geo_country: DE | MONTH: May | COMMONAPACHELOG: 1.1.1.1 - - [24/May/2022:10:57:37 +0200] "GET /dist/precache-manifest.58b57debe6bc4f96698da0dc314461e9.js HTTP/2.0" 304 0 | auth: - | HOUR: 10 | gl2_remote_ip: 172.31.32.142 | ident: - | gl2_remote_port: 43375 | BASE10NUM: [2.0, 304, 0] | pid: -1 | program: nginx | gl2_source_input: 623ed3440183476d61cff974 | INT: +0200 | is_private_ip: false | YEAR: 2022 | src_ip_geo_city: Achern | clientip: 1.1.1.1 | USERNAME:`,
  194. expected{
  195. Timestamp: time.Date(2022, 5, 24, 10, 57, 39, 0, time.UTC),
  196. Hostname: "myhostname",
  197. Tag: "unknown",
  198. PRI: 13,
  199. MsgID: `sn="msgid"`,
  200. Message: `source: sn="www.foobar.com" | message: 1.1.1.1 - - [24/May/2022:10:57:37 +0200] "GET /dist/precache-manifest.58b57debe6bc4f96698da0dc314461e9.js HTTP/2.0" 304 0 "https://www.foobar.com/sw.js" "Mozilla/5.0 (Linux; Android 9; ANE-LX1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.61 Mobile Safari/537.36" "-" "www.foobar.com" sn="www.foobar.com" rt=0.000 ua="-" us="-" ut="-" ul="-" cs=HIT { request: /dist/precache-manifest.58b57debe6bc4f96698da0dc314461e9.js | src_ip_geo_country: DE | MONTH: May | COMMONAPACHELOG: 1.1.1.1 - - [24/May/2022:10:57:37 +0200] "GET /dist/precache-manifest.58b57debe6bc4f96698da0dc314461e9.js HTTP/2.0" 304 0 | auth: - | HOUR: 10 | gl2_remote_ip: 172.31.32.142 | ident: - | gl2_remote_port: 43375 | BASE10NUM: [2.0, 304, 0] | pid: -1 | program: nginx | gl2_source_input: 623ed3440183476d61cff974 | INT: +0200 | is_private_ip: false | YEAR: 2022 | src_ip_geo_city: Achern | clientip: 1.1.1.1 | USERNAME:`,
  201. }, "", []RFC5424Option{},
  202. },
  203. {
  204. "partial message",
  205. `<13>1 2022-05-24T10:57:39Z foo bar -`,
  206. expected{},
  207. "EOL after ProcID",
  208. []RFC5424Option{},
  209. },
  210. {
  211. "partial message",
  212. `<13>1 2022-05-24T10:57:39Z foo bar `,
  213. expected{},
  214. "EOL after appname",
  215. []RFC5424Option{},
  216. },
  217. }
  218. for _, test := range tests {
  219. test := test
  220. t.Run(test.name, func(t *testing.T) {
  221. r := NewRFC5424Parser(test.opts...)
  222. err := r.Parse([]byte(test.input))
  223. if err != nil {
  224. if test.expectedErr != "" {
  225. if err.Error() != test.expectedErr {
  226. t.Errorf("expected error '%s', got '%s'", test.expectedErr, err)
  227. }
  228. } else {
  229. t.Errorf("unexpected error: '%s'", err)
  230. }
  231. } else {
  232. if test.expectedErr != "" {
  233. t.Errorf("expected error '%s', got no error", test.expectedErr)
  234. } else {
  235. if r.Timestamp.Round(time.Second).String() != test.expected.Timestamp.Round(time.Second).String() {
  236. t.Errorf("expected timestamp '%s', got '%s'", test.expected.Timestamp, r.Timestamp)
  237. }
  238. if r.Hostname != test.expected.Hostname {
  239. t.Errorf("expected hostname '%s', got '%s'", test.expected.Hostname, r.Hostname)
  240. }
  241. if r.Tag != test.expected.Tag {
  242. t.Errorf("expected tag '%s', got '%s'", test.expected.Tag, r.Tag)
  243. }
  244. if r.PID != test.expected.PID {
  245. t.Errorf("expected pid '%s', got '%s'", test.expected.PID, r.PID)
  246. }
  247. if r.Message != test.expected.Message {
  248. t.Errorf("expected message '%s', got '%s'", test.expected.Message, r.Message)
  249. }
  250. if r.PRI != test.expected.PRI {
  251. t.Errorf("expected pri '%d', got '%d'", test.expected.PRI, r.PRI)
  252. }
  253. if r.MsgID != test.expected.MsgID {
  254. t.Errorf("expected msgid '%s', got '%s'", test.expected.MsgID, r.MsgID)
  255. }
  256. }
  257. }
  258. })
  259. }
  260. }