github.com/honeycombio/honeytail@v1.9.0/parsers/syslog/syslog_test.go (about)

     1  package syslog
     2  
     3  import (
     4  	"reflect"
     5  	"regexp"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/stretchr/testify/assert"
    10  
    11  	"github.com/honeycombio/honeytail/event"
    12  	"github.com/honeycombio/honeytail/parsers"
    13  )
    14  
    15  const (
    16  	commonLogFormatTimeLayout = "02/Jan/2006:15:04:05 -0700"
    17  	iso8601TimeLayout         = "2006-01-02T15:04:05-07:00"
    18  )
    19  
    20  // Test Init(...) success/fail
    21  
    22  type testInitMap struct {
    23  	options      *Options
    24  	expectedPass bool
    25  }
    26  
    27  var testInitCases = []testInitMap{
    28  	{
    29  		expectedPass: true,
    30  		options: &Options{
    31  			Mode:       "rfc3164",
    32  			NumParsers: 5,
    33  		},
    34  	},
    35  	{
    36  		expectedPass: false,
    37  		options: &Options{
    38  			Mode: "foo", // unsupported syslog mode should cause a failure
    39  		},
    40  	},
    41  }
    42  
    43  func TestInit(t *testing.T) {
    44  	for _, testCase := range testInitCases {
    45  		p := &Parser{}
    46  		err := p.Init(testCase.options)
    47  		if (err == nil) != testCase.expectedPass {
    48  			if err == nil {
    49  				t.Error("Parser Init(...) passed; expected it to fail.")
    50  			} else {
    51  				t.Error("Parser Init(...) failed; expected it to pass. Error:", err)
    52  			}
    53  		} else {
    54  			t.Logf("Init pass status is %t as expected", (err == nil))
    55  		}
    56  	}
    57  }
    58  
    59  type testLineMap struct {
    60  	mode        string
    61  	processList string
    62  	input       string
    63  	expected    map[string]interface{}
    64  	err         bool
    65  }
    66  
    67  var tlms = []testLineMap{
    68  	// these test cases taken from https://github.com/jeromer/syslogparser/
    69  	{
    70  		input: "<34>Oct 11 22:14:15 mymachine su: 'su root' failed for lonvick on /dev/pts/8",
    71  		mode:  "rfc3164",
    72  		expected: map[string]interface{}{
    73  			"timestamp": time.Date(time.Now().Year(), 10, 11, 22, 14, 15, 0, time.UTC),
    74  			"hostname":  "mymachine",
    75  			"process":   "su",
    76  			"content":   "'su root' failed for lonvick on /dev/pts/8",
    77  			"priority":  34,
    78  			"facility":  4,
    79  			"severity":  2,
    80  		},
    81  	},
    82  	{
    83  		input: "<34>Oct 11 22:14:15 mymachine su: 'su root' failed for lonvick on /dev/pts/8",
    84  		mode:  "rfc3164",
    85  		// should parse, because su is in the list of processes
    86  		processList: "su,sshd",
    87  		expected: map[string]interface{}{
    88  			"timestamp": time.Date(time.Now().Year(), 10, 11, 22, 14, 15, 0, time.UTC),
    89  			"hostname":  "mymachine",
    90  			"process":   "su",
    91  			"content":   "'su root' failed for lonvick on /dev/pts/8",
    92  			"priority":  34,
    93  			"facility":  4,
    94  			"severity":  2,
    95  		},
    96  	},
    97  	{
    98  		input: "<34>Oct 11 22:14:15 mymachine su: 'su root' failed for lonvick on /dev/pts/8",
    99  		mode:  "rfc3164",
   100  		// should not parse (but not return an error) since su is not in the list of processes
   101  		processList: "sshd",
   102  		expected:    nil,
   103  	},
   104  	{
   105  		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...`,
   106  		mode:  "rfc5424",
   107  		expected: map[string]interface{}{
   108  			"version":         1,
   109  			"timestamp":       time.Date(2003, 10, 11, 22, 14, 15, int(time.Millisecond*3), time.UTC),
   110  			"structured_data": `[exampleSDID@32473 iut="3" eventSource="Application" eventID="1011"]`,
   111  			"proc_id":         "-",
   112  			"hostname":        "mymachine.example.com",
   113  			"severity":        5,
   114  			"facility":        20,
   115  			"priority":        165,
   116  			"message":         "An application event log entry...",
   117  			"msg_id":          "ID47",
   118  			"process":         "evntslog",
   119  		},
   120  	},
   121  }
   122  
   123  func TestParseLine(t *testing.T) {
   124  	for _, tlm := range tlms {
   125  		p := &Parser{}
   126  		err := p.Init(&Options{
   127  			Mode:        tlm.mode,
   128  			ProcessList: tlm.processList,
   129  		})
   130  		assert.NoError(t, err, "could not instantiate parser with mode: %s", tlm.mode)
   131  		resp, err := p.lineParser.ParseLine(tlm.input)
   132  		t.Logf("%+v", resp)
   133  		if tlm.err {
   134  			assert.Error(t, err, "p.ParseLine did not return error as expected")
   135  		} else {
   136  			assert.NoError(t, err, "p.ParseLine unexpectedly returned error %v", err)
   137  		}
   138  		if !reflect.DeepEqual(resp, tlm.expected) {
   139  			t.Errorf("response %+v didn't match expected %+v", resp, tlm.expected)
   140  		}
   141  	}
   142  }
   143  
   144  type testLineMaps struct {
   145  	line        string
   146  	trimmedLine string
   147  	resp        map[string]interface{}
   148  	typedResp   map[string]interface{}
   149  	ev          event.Event
   150  }
   151  
   152  // Test event emitted from ProcessLines
   153  func TestProcessLines(t *testing.T) {
   154  	preReg := &parsers.ExtRegexp{regexp.MustCompile("^(?P<pre_hostname>[a-zA-Z-.]+): ")}
   155  	tlm := []testLineMaps{
   156  		{
   157  			line: "somehost: <34>Oct 11 22:14:15 mymachine su: 'su root' failed for lonvick on /dev/pts/8",
   158  			ev: event.Event{
   159  				Timestamp: time.Date(time.Now().Year(), 10, 11, 22, 14, 15, 0, time.UTC),
   160  				Data: map[string]interface{}{
   161  					"pre_hostname": "somehost",
   162  					"timestamp":    time.Date(time.Now().Year(), 10, 11, 22, 14, 15, 0, time.UTC),
   163  					"hostname":     "mymachine",
   164  					"process":      "su",
   165  					"content":      "'su root' failed for lonvick on /dev/pts/8",
   166  					"priority":     34,
   167  					"facility":     4,
   168  					"severity":     2,
   169  				},
   170  			},
   171  		},
   172  	}
   173  	p := &Parser{}
   174  	err := p.Init(&Options{
   175  		Mode:       "rfc3164",
   176  		NumParsers: 5,
   177  	})
   178  	assert.NoError(t, err, "Couldn't instantiate Parser")
   179  
   180  	lines := make(chan string)
   181  	send := make(chan event.Event)
   182  	go func() {
   183  		for _, pair := range tlm {
   184  			lines <- pair.line
   185  		}
   186  		close(lines)
   187  	}()
   188  	go p.ProcessLines(lines, send, preReg)
   189  	for _, pair := range tlm {
   190  		resp := <-send
   191  		if !reflect.DeepEqual(resp, pair.ev) {
   192  			t.Fatalf("line resp didn't match up for %s. Expected: %+v, actual: %+v",
   193  				pair.line, pair.ev, resp)
   194  		}
   195  	}
   196  }