github.com/honeycombio/honeytail@v1.9.0/parsers/keyval/keyval_test.go (about)

     1  package keyval
     2  
     3  import (
     4  	"reflect"
     5  	"sync"
     6  	"testing"
     7  
     8  	"github.com/honeycombio/honeytail/event"
     9  )
    10  
    11  type testLineMap struct {
    12  	input    string
    13  	expected map[string]interface{}
    14  }
    15  
    16  var tlms = []testLineMap{
    17  	{ // strings, floats, and ints
    18  		input: `mystr="myval" myint=3 myfloat=4.234 mybool=true`,
    19  		expected: map[string]interface{}{
    20  			"mystr":   "myval",
    21  			"myint":   3,
    22  			"myfloat": 4.234,
    23  			"mybool":  true,
    24  		},
    25  	},
    26  	{ // missing keyval pairs
    27  		input: `foo bar 123 baz`,
    28  		expected: map[string]interface{}{
    29  			"foo": "",
    30  			"bar": "",
    31  			"123": "",
    32  			"baz": "",
    33  		},
    34  	},
    35  	{ // time
    36  		input: `time="2014-03-10 19:57:38.123456789 -0800 PST" myint=3 myfloat=4.234`,
    37  		expected: map[string]interface{}{
    38  			"time":    "2014-03-10 19:57:38.123456789 -0800 PST",
    39  			"myint":   3,
    40  			"myfloat": 4.234,
    41  		},
    42  	},
    43  }
    44  
    45  func TestParseLine(t *testing.T) {
    46  	jlp := KeyValLineParser{}
    47  	for _, tlm := range tlms {
    48  		resp, err := jlp.ParseLine(tlm.input)
    49  		if err != nil {
    50  			t.Error("jlp.ParseLine unexpectedly returned error ", err)
    51  		}
    52  		if !reflect.DeepEqual(resp, tlm.expected) {
    53  			t.Errorf("response %+v didn't match expected %+v", resp, tlm.expected)
    54  		}
    55  	}
    56  }
    57  
    58  func TestBrokenFilterRegex(t *testing.T) {
    59  	// test filter that doesn't compile
    60  	broken := &Parser{}
    61  	err := broken.Init(&Options{
    62  		FilterRegex: "regex [ won't compile",
    63  	})
    64  	if err == nil {
    65  		t.Error("Parser Init with broken regex should err, instead got nil")
    66  	}
    67  }
    68  
    69  func TestFilterRegex(t *testing.T) {
    70  	tsts := []struct {
    71  		filterString   string
    72  		invertFilter   bool
    73  		lines          []string
    74  		expectedEvents int
    75  	}{
    76  		{
    77  			"aaaa",
    78  			false,
    79  			[]string{
    80  				"key=val",
    81  				"key=val",
    82  				"key=val",
    83  			},
    84  			0, // no lines have 'aaaa'
    85  		},
    86  		{
    87  			"aaaa",
    88  			true,
    89  			[]string{
    90  				"key=val",
    91  				"key=val",
    92  				"key=val",
    93  			},
    94  			3, // all lines don't have 'aaaa'
    95  		},
    96  		{
    97  			"aoeu",
    98  			false,
    99  			[]string{
   100  				"key=val",
   101  				"key=val aoeu",
   102  				"key=val",
   103  			},
   104  			1, // only line two has 'aoeu'
   105  		},
   106  		{
   107  			"aoeu",
   108  			true,
   109  			[]string{
   110  				"key=val",
   111  				"key=val aoeu",
   112  				"key=val",
   113  			},
   114  			2, // lines one and three don't have 'aoeu'
   115  		},
   116  	}
   117  	for _, tst := range tsts {
   118  		p := &Parser{}
   119  		p.Init(&Options{
   120  			NumParsers:   5,
   121  			FilterRegex:  tst.filterString,
   122  			InvertFilter: tst.invertFilter,
   123  		})
   124  		lines := make(chan string)
   125  		send := make(chan event.Event)
   126  		// send input into lines in a goroutine then close the lines channel
   127  		go func() {
   128  			for _, line := range tst.lines {
   129  				lines <- line
   130  			}
   131  			close(lines)
   132  		}()
   133  		// read from the send channel and see if we got back what we expected
   134  		wg := sync.WaitGroup{}
   135  		wg.Add(1)
   136  		go func() {
   137  			var counter int
   138  			for range send {
   139  				counter++
   140  			}
   141  			if counter != tst.expectedEvents {
   142  				t.Errorf("expected %d messages out the send channel, got %d\n", tst.expectedEvents, counter)
   143  			}
   144  			wg.Done()
   145  		}()
   146  		p.ProcessLines(lines, send, nil)
   147  		close(send)
   148  		wg.Wait()
   149  	}
   150  }
   151  
   152  func TestDontReturnEmptyEvents(t *testing.T) {
   153  	p := &Parser{}
   154  	p.Init(&Options{})
   155  	lines := make(chan string)
   156  	send := make(chan event.Event)
   157  	// send input into lines in a goroutine then close the lines channel
   158  	go func() {
   159  		for _, line := range []string{"one", "two", "three"} {
   160  			lines <- line
   161  		}
   162  		close(lines)
   163  	}()
   164  	// read from the send channel and see if we got back what we expected
   165  	wg := sync.WaitGroup{}
   166  	wg.Add(1)
   167  	go func() {
   168  		var counter int
   169  		for range send {
   170  			counter++
   171  		}
   172  		if counter != 0 {
   173  			t.Errorf("expected no messages out the send channel, got %d\n", counter)
   174  		}
   175  		wg.Done()
   176  	}()
   177  	p.ProcessLines(lines, send, nil)
   178  	close(send)
   179  	wg.Wait()
   180  }
   181  
   182  // TestDontReturnUselessEvents a useless event is one with all keys and no
   183  // values
   184  func TestDontReturnUselessEvents(t *testing.T) {
   185  	p := &Parser{}
   186  	p.Init(&Options{})
   187  	lines := make(chan string)
   188  	send := make(chan event.Event)
   189  	// send input into lines in a goroutine then close the lines channel
   190  	go func() {
   191  		for _, line := range []string{"key=", "key2=", "key= key2="} {
   192  			lines <- line
   193  		}
   194  		close(lines)
   195  	}()
   196  	// read from the send channel and see if we got back what we expected
   197  	wg := sync.WaitGroup{}
   198  	wg.Add(1)
   199  	go func() {
   200  		var counter int
   201  		for range send {
   202  			counter++
   203  		}
   204  		if counter != 0 {
   205  			t.Errorf("expected no messages out the send channel, got %d\n", counter)
   206  		}
   207  		wg.Done()
   208  	}()
   209  	p.ProcessLines(lines, send, nil)
   210  	close(send)
   211  	wg.Wait()
   212  }
   213  
   214  func TestAllEmpty(t *testing.T) {
   215  	tsts := []struct {
   216  		incoming map[string]interface{}
   217  		empty    bool
   218  	}{
   219  		{
   220  			map[string]interface{}{
   221  				"k1": "v1",
   222  			},
   223  			false,
   224  		},
   225  		{
   226  			map[string]interface{}{
   227  				"k1": 3,
   228  			},
   229  			false,
   230  		},
   231  		{
   232  			map[string]interface{}{
   233  				"k1": []string{"foo", "bar"},
   234  			},
   235  			false,
   236  		},
   237  		{
   238  			map[string]interface{}{},
   239  			true,
   240  		},
   241  		{
   242  			map[string]interface{}{
   243  				"k1": "",
   244  			},
   245  			true,
   246  		},
   247  		{
   248  			map[string]interface{}{
   249  				"k1": "",
   250  				"k2": "",
   251  				"k3": "",
   252  			},
   253  			true,
   254  		},
   255  	}
   256  	for _, tst := range tsts {
   257  		res := allEmpty(tst.incoming)
   258  		if res != tst.empty {
   259  			t.Errorf("expected %v's empty val would be %v, got %v",
   260  				tst.incoming, tst.empty, res)
   261  		}
   262  	}
   263  }