github.com/crowdsecurity/crowdsec@v1.6.1/pkg/acquisition/modules/syslog/internal/parser/rfc3164/parse_test.go (about) 1 package rfc3164 2 3 import ( 4 "fmt" 5 "testing" 6 "time" 7 ) 8 9 func TestPri(t *testing.T) { 10 tests := []struct { 11 input string 12 expected int 13 expectedErr string 14 }{ 15 {"<0>", 0, ""}, 16 {"<19>", 19, ""}, 17 {"<200>", 200, ""}, 18 {"<4999>", 0, "PRI must be up to 3 characters long"}, 19 {"<123", 0, "PRI must end with '>'"}, 20 {"123>", 0, "PRI must start with '<'"}, 21 {"<abc>", 0, "PRI must be a number"}, 22 } 23 24 for _, test := range tests { 25 test := test 26 t.Run(test.input, func(t *testing.T) { 27 r := &RFC3164{} 28 r.buf = []byte(test.input) 29 r.len = len(r.buf) 30 err := r.parsePRI() 31 if err != nil { 32 if test.expectedErr != "" { 33 if err.Error() != test.expectedErr { 34 t.Errorf("expected error %s, got %s", test.expectedErr, err) 35 } 36 } else { 37 t.Errorf("unexpected error: %s", err) 38 } 39 } else { 40 if test.expectedErr != "" { 41 t.Errorf("expected error %s, got no error", test.expectedErr) 42 } else if r.PRI != test.expected { 43 t.Errorf("expected %d, got %d", test.expected, r.PRI) 44 } 45 } 46 }) 47 } 48 } 49 50 func TestTimestamp(t *testing.T) { 51 52 tests := []struct { 53 input string 54 expected string 55 expectedErr string 56 currentYear bool 57 }{ 58 {"May 20 09:33:54", "0000-05-20T09:33:54Z", "", false}, 59 {"May 20 09:33:54", fmt.Sprintf("%d-05-20T09:33:54Z", time.Now().Year()), "", true}, 60 {"May 20 09:33:54 2022", "2022-05-20T09:33:54Z", "", false}, 61 {"May 1 09:33:54 2022", "2022-05-01T09:33:54Z", "", false}, 62 {"May 01 09:33:54 2021", "2021-05-01T09:33:54Z", "", true}, 63 {"foobar", "", "timestamp is not valid", false}, 64 } 65 66 for _, test := range tests { 67 test := test 68 t.Run(test.input, func(t *testing.T) { 69 opts := []RFC3164Option{} 70 if test.currentYear { 71 opts = append(opts, WithCurrentYear()) 72 } 73 r := NewRFC3164Parser(opts...) 74 r.buf = []byte(test.input) 75 r.len = len(r.buf) 76 err := r.parseTimestamp() 77 if err != nil { 78 if test.expectedErr != "" { 79 if err.Error() != test.expectedErr { 80 t.Errorf("expected error %s, got %s", test.expectedErr, err) 81 } 82 } else { 83 t.Errorf("unexpected error: %s", err) 84 } 85 } else { 86 if test.expectedErr != "" { 87 t.Errorf("expected error %s, got no error", test.expectedErr) 88 } else if r.Timestamp.Format(time.RFC3339) != test.expected { 89 t.Errorf("expected %s, got %s", test.expected, r.Timestamp.Format(time.RFC3339)) 90 } 91 } 92 }) 93 } 94 } 95 96 func TestHostname(t *testing.T) { 97 tests := []struct { 98 input string 99 expected string 100 expectedErr string 101 strictHostname bool 102 }{ 103 {"127.0.0.1", "127.0.0.1", "", false}, 104 {"::1", "::1", "", false}, 105 {"foo.-bar", "", "hostname is not valid", true}, 106 {"foo-.bar", "", "hostname is not valid", true}, 107 {"foo123.bar", "foo123.bar", "", true}, 108 {"a..", "", "hostname is not valid", true}, 109 {"foo.bar", "foo.bar", "", false}, 110 {"foo,bar", "foo,bar", "", false}, 111 {"foo,bar", "", "hostname is not valid", true}, 112 {"", "", "hostname is empty", false}, 113 {".", ".", "", true}, 114 {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "", "hostname is not valid", true}, 115 {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.bla", "", "hostname is not valid", true}, 116 {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.bla", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.bla", "", false}, 117 {"a.foo-", "", "hostname is not valid", true}, 118 } 119 120 for _, test := range tests { 121 test := test 122 t.Run(test.input, func(t *testing.T) { 123 opts := []RFC3164Option{} 124 if test.strictHostname { 125 opts = append(opts, WithStrictHostname()) 126 } 127 r := NewRFC3164Parser(opts...) 128 r.buf = []byte(test.input) 129 r.len = len(r.buf) 130 err := r.parseHostname() 131 if err != nil { 132 if test.expectedErr != "" { 133 if err.Error() != test.expectedErr { 134 t.Errorf("expected error %s, got %s", test.expectedErr, err) 135 } 136 } else { 137 t.Errorf("unexpected error: %s", err) 138 } 139 } else { 140 if test.expectedErr != "" { 141 t.Errorf("expected error %s, got no error", test.expectedErr) 142 } else if r.Hostname != test.expected { 143 t.Errorf("expected %s, got %s", test.expected, r.Hostname) 144 } 145 } 146 }) 147 } 148 } 149 150 func TestTag(t *testing.T) { 151 tests := []struct { 152 input string 153 expected string 154 expectedPID string 155 expectedErr string 156 }{ 157 {"foobar", "foobar", "", ""}, 158 {"foobar[42]", "foobar", "42", ""}, 159 {"", "", "", "tag is empty"}, 160 {"foobar[", "", "", "pid inside tag must be closed with ']'"}, 161 {"foobar[42", "", "", "pid inside tag must be closed with ']'"}, 162 {"foobar[asd]", "foobar", "", "pid inside tag must be a number"}, 163 } 164 165 for _, test := range tests { 166 test := test 167 t.Run(test.input, func(t *testing.T) { 168 r := &RFC3164{} 169 r.buf = []byte(test.input) 170 r.len = len(r.buf) 171 err := r.parseTag() 172 if err != nil { 173 if test.expectedErr != "" { 174 if err.Error() != test.expectedErr { 175 t.Errorf("expected error %s, got %s", test.expectedErr, err) 176 } 177 } else { 178 t.Errorf("unexpected error: %s", err) 179 } 180 } else { 181 if test.expectedErr != "" { 182 t.Errorf("expected error %s, got no error", test.expectedErr) 183 } else { 184 if r.Tag != test.expected { 185 t.Errorf("expected %s, got %s", test.expected, r.Tag) 186 } 187 if r.PID != test.expectedPID { 188 t.Errorf("expected %s, got %s", test.expected, r.Message) 189 } 190 } 191 } 192 }) 193 } 194 } 195 196 func TestMessage(t *testing.T) { 197 tests := []struct { 198 input string 199 expected string 200 expectedErr string 201 }{ 202 {"foobar: pouet", "pouet", ""}, 203 {"foobar[42]: test", "test", ""}, 204 {"foobar[123]: this is a test", "this is a test", ""}, 205 {"foobar[123]: ", "", "message is empty"}, 206 {"foobar[123]:", "", "message is empty"}, 207 } 208 209 for _, test := range tests { 210 test := test 211 t.Run(test.input, func(t *testing.T) { 212 r := &RFC3164{} 213 r.buf = []byte(test.input) 214 r.len = len(r.buf) 215 err := r.parseMessage() 216 if err != nil { 217 if test.expectedErr != "" { 218 if err.Error() != test.expectedErr { 219 t.Errorf("expected error %s, got %s", test.expectedErr, err) 220 } 221 } else { 222 t.Errorf("unexpected error: %s", err) 223 } 224 } else { 225 if test.expectedErr != "" { 226 t.Errorf("expected error %s, got no error", test.expectedErr) 227 } else if r.Message != test.expected { 228 t.Errorf("expected message %s, got %s", test.expected, r.Tag) 229 } 230 } 231 }) 232 } 233 } 234 235 func TestParse(t *testing.T) { 236 type expected struct { 237 Timestamp time.Time 238 Hostname string 239 Tag string 240 PID string 241 Message string 242 PRI int 243 } 244 tests := []struct { 245 input string 246 expected expected 247 expectedErr string 248 opts []RFC3164Option 249 }{ 250 { 251 "<12>May 20 09:33:54 UDMPRO,a2edd0c6ae48,udm-1.10.0.3686 kernel: foo", expected{ 252 Timestamp: time.Date(0, time.May, 20, 9, 33, 54, 0, time.UTC), 253 Hostname: "UDMPRO,a2edd0c6ae48,udm-1.10.0.3686", 254 Tag: "kernel", 255 PID: "", 256 Message: "foo", 257 PRI: 12, 258 }, "", []RFC3164Option{}, 259 }, 260 { 261 "<12>May 20 09:33:54 UDMPRO,a2edd0c6ae48,udm-1.10.0.3686 kernel: foo", expected{ 262 Timestamp: time.Date(time.Now().Year(), time.May, 20, 9, 33, 54, 0, time.UTC), 263 Hostname: "UDMPRO,a2edd0c6ae48,udm-1.10.0.3686", 264 Tag: "kernel", 265 PID: "", 266 Message: "foo", 267 PRI: 12, 268 }, "", []RFC3164Option{WithCurrentYear()}, 269 }, 270 { 271 "<12>May 20 09:33:54 UDMPRO,a2edd0c6ae48,udm-1.10.0.3686 kernel: foo", expected{}, "hostname is not valid", []RFC3164Option{WithStrictHostname()}, 272 }, 273 { 274 "foobar", expected{}, "PRI must start with '<'", []RFC3164Option{}, 275 }, 276 { 277 "<12>", expected{}, "timestamp is not valid", []RFC3164Option{}, 278 }, 279 { 280 "<12 May 02 09:33:54 foo.bar", expected{}, "PRI must be a number", []RFC3164Option{}, 281 }, 282 { 283 "<12>May 02 09:33:54", expected{}, "hostname is empty", []RFC3164Option{}, 284 }, 285 { 286 "<12>May 02 09:33:54 foo.bar", expected{}, "tag is empty", []RFC3164Option{}, 287 }, 288 { 289 "<12>May 02 09:33:54 foo.bar bla[42", expected{}, "pid inside tag must be closed with ']'", []RFC3164Option{}, 290 }, 291 { 292 "<12>May 02 09:33:54 foo.bar bla[42]", expected{}, "message is empty", []RFC3164Option{}, 293 }, 294 { 295 "<12>May 02 09:33:54 foo.bar bla[42]: ", expected{}, "message is empty", []RFC3164Option{}, 296 }, 297 { 298 "<12>May 02 09:33:54 foo.bar bla", expected{}, "message is empty", []RFC3164Option{}, 299 }, 300 { 301 "<12>May 02 09:33:54 foo.bar bla:", expected{}, "message is empty", []RFC3164Option{}, 302 }, 303 { 304 "", expected{}, "message is empty", []RFC3164Option{}, 305 }, 306 { 307 `<13>1 2021-05-18T11:58:40.828081+02:00 mantis sshd 49340 - [timeQuality isSynced="0" tzKnown="1"] blabla`, expected{}, "timestamp is not valid", []RFC3164Option{}, 308 }, 309 { 310 `<46>Jun 2 06:55:39 localhost haproxy[27213]: Connect from 100.100.100.99:52611 to 100.100.100.99:443 (https_shared-merged/HTTP)\\n 10.0.0.1}`, expected{ 311 Timestamp: time.Date(time.Now().Year(), time.June, 2, 6, 55, 39, 0, time.UTC), 312 Hostname: "localhost", 313 Tag: "haproxy", 314 PID: "27213", 315 Message: `Connect from 100.100.100.99:52611 to 100.100.100.99:443 (https_shared-merged/HTTP)\\n 10.0.0.1}`, 316 PRI: 46, 317 }, "", []RFC3164Option{WithCurrentYear()}, 318 }, 319 { 320 `<46>Jun 2 06:55:39 2022 localhost haproxy[27213]: Connect from 100.100.100.99:52611 to 100.100.100.99:443 (https_shared-merged/HTTP)\\n 10.0.0.1}`, expected{ 321 Timestamp: time.Date(2022, time.June, 2, 6, 55, 39, 0, time.UTC), 322 Hostname: "localhost", 323 Tag: "haproxy", 324 PID: "27213", 325 Message: `Connect from 100.100.100.99:52611 to 100.100.100.99:443 (https_shared-merged/HTTP)\\n 10.0.0.1}`, 326 PRI: 46, 327 }, "", []RFC3164Option{}, 328 }, 329 } 330 331 for _, test := range tests { 332 test := test 333 t.Run(test.input, func(t *testing.T) { 334 r := NewRFC3164Parser(test.opts...) 335 err := r.Parse([]byte(test.input)) 336 if err != nil { 337 if test.expectedErr != "" { 338 if err.Error() != test.expectedErr { 339 t.Errorf("expected error '%s', got '%s'", test.expectedErr, err) 340 } 341 } else { 342 t.Errorf("unexpected error: '%s'", err) 343 } 344 } else { 345 if test.expectedErr != "" { 346 t.Errorf("expected error '%s', got no error", test.expectedErr) 347 } else { 348 if r.Timestamp != test.expected.Timestamp { 349 t.Errorf("expected timestamp '%s', got '%s'", test.expected.Timestamp, r.Timestamp) 350 } 351 if r.Hostname != test.expected.Hostname { 352 t.Errorf("expected hostname '%s', got '%s'", test.expected.Hostname, r.Hostname) 353 } 354 if r.Tag != test.expected.Tag { 355 t.Errorf("expected tag '%s', got '%s'", test.expected.Tag, r.Tag) 356 } 357 if r.PID != test.expected.PID { 358 t.Errorf("expected pid '%s', got '%s'", test.expected.PID, r.PID) 359 } 360 if r.Message != test.expected.Message { 361 t.Errorf("expected message '%s', got '%s'", test.expected.Message, r.Message) 362 } 363 if r.PRI != test.expected.PRI { 364 t.Errorf("expected pri '%d', got '%d'", test.expected.PRI, r.PRI) 365 } 366 } 367 } 368 }) 369 } 370 }