parse_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  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. t.Run(test.input, func(t *testing.T) {
  22. r := &RFC5424{}
  23. r.buf = []byte(test.input)
  24. r.len = len(r.buf)
  25. err := r.parsePRI()
  26. if err != nil {
  27. if test.expectedErr != "" {
  28. if err.Error() != test.expectedErr {
  29. t.Errorf("expected error %s, got %s", test.expectedErr, err.Error())
  30. }
  31. } else {
  32. t.Errorf("unexpected error: %s", err.Error())
  33. }
  34. } else {
  35. if test.expectedErr != "" {
  36. t.Errorf("expected error %s, got no error", test.expectedErr)
  37. } else {
  38. if r.PRI != test.expected {
  39. t.Errorf("expected %d, got %d", test.expected, r.PRI)
  40. }
  41. }
  42. }
  43. })
  44. }
  45. }
  46. func TestHostname(t *testing.T) {
  47. tests := []struct {
  48. input string
  49. expected string
  50. expectedErr string
  51. strictHostname bool
  52. }{
  53. {"127.0.0.1", "127.0.0.1", "", false},
  54. {"::1", "::1", "", false},
  55. {"-", "", "", false},
  56. {"foo.-bar", "", "hostname is not valid", true},
  57. {"foo-.bar", "", "hostname is not valid", true},
  58. {"foo123.bar", "foo123.bar", "", true},
  59. {"a..", "", "hostname is not valid", true},
  60. {"foo.bar", "foo.bar", "", false},
  61. {"foo,bar", "foo,bar", "", false},
  62. {"foo,bar", "", "hostname is not valid", true},
  63. {".", ".", "", true},
  64. {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "", "hostname is not valid", true},
  65. {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.bla", "", "hostname is not valid", true},
  66. {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.bla", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.bla", "", false},
  67. {"a.foo-", "", "hostname is not valid", true},
  68. }
  69. for _, test := range tests {
  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.Error())
  83. }
  84. } else {
  85. t.Errorf("unexpected error: %s", err.Error())
  86. }
  87. } else {
  88. if test.expectedErr != "" {
  89. t.Errorf("expected error %s, got no error", test.expectedErr)
  90. } else {
  91. if r.Hostname != test.expected {
  92. t.Errorf("expected %s, got %s", test.expected, r.Hostname)
  93. }
  94. }
  95. }
  96. })
  97. }
  98. }
  99. func TestParse(t *testing.T) {
  100. type expected struct {
  101. Timestamp time.Time
  102. Hostname string
  103. Tag string
  104. PID string
  105. Message string
  106. PRI int
  107. MsgID string
  108. }
  109. tests := []struct {
  110. name string
  111. input string
  112. expected expected
  113. expectedErr string
  114. opts []RFC5424Option
  115. }{
  116. {
  117. "valid msg",
  118. `<13>1 2021-05-18T11:58:40.828081+02:42 mantis sshd 49340 - [timeQuality isSynced="0" tzKnown="1"] blabla`, expected{
  119. Timestamp: time.Date(2021, 5, 18, 11, 58, 40, 828081000, time.FixedZone("+0242", 9720)),
  120. Hostname: "mantis",
  121. Tag: "sshd",
  122. PID: "49340",
  123. MsgID: "",
  124. Message: "blabla",
  125. PRI: 13,
  126. }, "", []RFC5424Option{},
  127. },
  128. {
  129. "valid msg with msgid",
  130. `<13>1 2021-05-18T11:58:40.828081+02:42 mantis foobar 49340 123123 [timeQuality isSynced="0" tzKnown="1"] blabla`, expected{
  131. Timestamp: time.Date(2021, 5, 18, 11, 58, 40, 828081000, time.FixedZone("+0242", 9720)),
  132. Hostname: "mantis",
  133. Tag: "foobar",
  134. PID: "49340",
  135. MsgID: "123123",
  136. Message: "blabla",
  137. PRI: 13,
  138. }, "", []RFC5424Option{},
  139. },
  140. {
  141. "valid msg with repeating SD",
  142. `<13>1 2021-05-18T11:58:40.828081+02:42 mantis foobar 49340 123123 [timeQuality isSynced="0" tzKnown="1"][foo="bar][a] blabla`, expected{
  143. Timestamp: time.Date(2021, 5, 18, 11, 58, 40, 828081000, time.FixedZone("+0242", 9720)),
  144. Hostname: "mantis",
  145. Tag: "foobar",
  146. PID: "49340",
  147. MsgID: "123123",
  148. Message: "blabla",
  149. PRI: 13,
  150. }, "", []RFC5424Option{},
  151. },
  152. {
  153. "invalid SD",
  154. `<13>1 2021-05-18T11:58:40.828081+02:00 mantis foobar 49340 123123 [timeQuality asd`, expected{}, "structured data must end with ']'", []RFC5424Option{},
  155. },
  156. {
  157. "invalid version",
  158. `<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{},
  159. },
  160. {
  161. "invalid message",
  162. `<13>1`, expected{}, "version must be followed by a space", []RFC5424Option{},
  163. },
  164. {
  165. "valid msg with empty fields",
  166. `<13>1 - foo - - - - blabla`, expected{
  167. Timestamp: time.Now().UTC().Round(0),
  168. Hostname: "foo",
  169. PRI: 13,
  170. Message: "blabla",
  171. }, "", []RFC5424Option{},
  172. },
  173. {
  174. "valid msg with empty fields",
  175. `<13>1 - - - - - - blabla`, expected{
  176. Timestamp: time.Now().UTC().Round(0),
  177. PRI: 13,
  178. Message: "blabla",
  179. }, "", []RFC5424Option{},
  180. },
  181. {
  182. "valid msg with escaped SD",
  183. `<13>1 2022-05-24T10:57:39Z testhostname unknown - sn="msgid" [foo="\]" bar="a\""][a b="[\]" c] testmessage`,
  184. expected{
  185. PRI: 13,
  186. Timestamp: time.Date(2022, 5, 24, 10, 57, 39, 0, time.UTC),
  187. Tag: "unknown",
  188. Hostname: "testhostname",
  189. MsgID: `sn="msgid"`,
  190. Message: `testmessage`,
  191. }, "", []RFC5424Option{},
  192. },
  193. {
  194. "valid complex msg",
  195. `<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:`,
  196. expected{
  197. Timestamp: time.Date(2022, 5, 24, 10, 57, 39, 0, time.UTC),
  198. Hostname: "myhostname",
  199. Tag: "unknown",
  200. PRI: 13,
  201. MsgID: `sn="msgid"`,
  202. 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:`,
  203. }, "", []RFC5424Option{},
  204. },
  205. {
  206. "partial message",
  207. `<13>1 2022-05-24T10:57:39Z foo bar -`,
  208. expected{},
  209. "EOL after ProcID",
  210. []RFC5424Option{},
  211. },
  212. {
  213. "partial message",
  214. `<13>1 2022-05-24T10:57:39Z foo bar `,
  215. expected{},
  216. "EOL after appname",
  217. []RFC5424Option{},
  218. },
  219. }
  220. for _, test := range tests {
  221. t.Run(test.name, func(t *testing.T) {
  222. r := NewRFC5424Parser(test.opts...)
  223. err := r.Parse([]byte(test.input))
  224. if err != nil {
  225. if test.expectedErr != "" {
  226. if err.Error() != test.expectedErr {
  227. t.Errorf("expected error '%s', got '%s'", test.expectedErr, err.Error())
  228. }
  229. } else {
  230. t.Errorf("unexpected error: '%s'", err.Error())
  231. }
  232. } else {
  233. if test.expectedErr != "" {
  234. t.Errorf("expected error '%s', got no error", test.expectedErr)
  235. } else {
  236. if r.Timestamp.Round(time.Second).String() != test.expected.Timestamp.Round(time.Second).String() {
  237. t.Errorf("expected timestamp '%s', got '%s'", test.expected.Timestamp, r.Timestamp)
  238. }
  239. if r.Hostname != test.expected.Hostname {
  240. t.Errorf("expected hostname '%s', got '%s'", test.expected.Hostname, r.Hostname)
  241. }
  242. if r.Tag != test.expected.Tag {
  243. t.Errorf("expected tag '%s', got '%s'", test.expected.Tag, r.Tag)
  244. }
  245. if r.PID != test.expected.PID {
  246. t.Errorf("expected pid '%s', got '%s'", test.expected.PID, r.PID)
  247. }
  248. if r.Message != test.expected.Message {
  249. t.Errorf("expected message '%s', got '%s'", test.expected.Message, r.Message)
  250. }
  251. if r.PRI != test.expected.PRI {
  252. t.Errorf("expected pri '%d', got '%d'", test.expected.PRI, r.PRI)
  253. }
  254. if r.MsgID != test.expected.MsgID {
  255. t.Errorf("expected msgid '%s', got '%s'", test.expected.MsgID, r.MsgID)
  256. }
  257. }
  258. }
  259. })
  260. }
  261. }