Improve suricata input unit test debugging (#6815)

This commit is contained in:
Daniel Nelson 2020-01-02 16:26:48 -08:00 committed by GitHub
parent 318d8134cf
commit 1edb73916f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 84 additions and 266 deletions

View File

@ -1,7 +1,6 @@
package suricata package suricata
import ( import (
"bytes"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log" "log"
@ -9,35 +8,21 @@ import (
"net" "net"
"os" "os"
"path/filepath" "path/filepath"
"regexp"
"strings" "strings"
"testing" "testing"
"time" "time"
"github.com/influxdata/telegraf/plugins/inputs" "github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/testutil" "github.com/influxdata/telegraf/testutil"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/require"
) )
var ex2 = `{"timestamp":"2017-03-06T07:43:39.000397+0000","event_type":"stats","stats":{"capture":{"kernel_packets":905344474,"kernel_drops":78355440,"kernel_packets_delta":2376742,"kernel_drops_delta":82049}}}` var ex2 = `{"timestamp":"2017-03-06T07:43:39.000397+0000","event_type":"stats","stats":{"capture":{"kernel_packets":905344474,"kernel_drops":78355440,"kernel_packets_delta":2376742,"kernel_drops_delta":82049}}}`
var ex3 = `{"timestamp":"2017-03-06T07:43:39.000397+0000","event_type":"stats","stats":{"threads": { "foo": { "capture":{"kernel_packets":905344474,"kernel_drops":78355440}}}}}` var ex3 = `{"timestamp":"2017-03-06T07:43:39.000397+0000","event_type":"stats","stats":{"threads": { "W#05-wlp4s0": { "capture":{"kernel_packets":905344474,"kernel_drops":78355440}}}}}`
var ex4 = `{"timestamp":"2017-03-06T07:43:39.000397+0000","event_type":"stats","stats":{"threads": { "W1#en..bar1": { "capture":{"kernel_packets":905344474,"kernel_drops":78355440}}}}}`
var brokenType1 = `{"timestamp":"2017-03-06T07:43:39.000397+0000","event_type":"stats","stats":{"threads": { "W1#en..bar1": { "capture":{"kernel_packets":905344474,"kernel_drops": true}}}}}`
var brokenType2 = `{"timestamp":"2017-03-06T07:43:39.000397+0000","event_type":"stats","stats":{"threads": { "W1#en..bar1": { "capture":{"kernel_packets":905344474,"kernel_drops": ["foo"]}}}}}`
var brokenType3 = `{"timestamp":"2017-03-06T07:43:39.000397+0000","event_type":"stats","stats":{"threads": { "W1#en..bar1": { "capture":{"kernel_packets":905344474,"kernel_drops":"none this time"}}}}}`
var brokenType4 = `{"timestamp":"2017-03-06T07:43:39.000397+0000","event_type":"stats","stats":{"threads": { "W1#en..bar1": { "capture":{"kernel_packets":905344474,"kernel_drops":null}}}}}`
var brokenType5 = `{"timestamp":"2017-03-06T07:43:39.000397+0000","event_type":"stats","stats":{"foo": null}}`
var brokenStruct1 = `{"timestamp":"2017-03-06T07:43:39.000397+0000","event_type":"stats","stats":{"threads": ["foo"]}}`
var brokenStruct2 = `{"timestamp":"2017-03-06T07:43:39.000397+0000","event_type":"stats"}`
var brokenStruct3 = `{"timestamp":"2017-03-06T07:43:39.000397+0000","event_type":"stats","stats": "foobar"}`
var brokenStruct4 = `{"timestamp":"2017-03-06T07:43:39.000397+0000","event_type":"stats","stats": null}`
var singleDotRegexp = regexp.MustCompilePOSIX(`[^.]\.[^.]`)
func TestSuricataLarge(t *testing.T) { func TestSuricataLarge(t *testing.T) {
dir, err := ioutil.TempDir("", "test") dir, err := ioutil.TempDir("", "test")
if err != nil { require.NoError(t, err)
t.Fatal(err)
}
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63())) tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))
@ -49,32 +34,24 @@ func TestSuricataLarge(t *testing.T) {
}, },
} }
acc := testutil.Accumulator{} acc := testutil.Accumulator{}
acc.SetDebug(true) require.NoError(t, s.Start(&acc))
assert.NoError(t, s.Start(&acc)) defer s.Stop()
data, err := ioutil.ReadFile("testdata/test1.json") data, err := ioutil.ReadFile("testdata/test1.json")
if err != nil { require.NoError(t, err)
t.Fatal(err)
}
c, err := net.Dial("unix", tmpfn) c, err := net.Dial("unix", tmpfn)
if err != nil { require.NoError(t, err)
t.Fatal(err)
}
c.Write([]byte(data)) c.Write([]byte(data))
c.Write([]byte("\n")) c.Write([]byte("\n"))
c.Close() c.Close()
acc.Wait(1) acc.Wait(1)
s.Stop()
} }
func TestSuricata(t *testing.T) { func TestSuricata(t *testing.T) {
dir, err := ioutil.TempDir("", "test") dir, err := ioutil.TempDir("", "test")
if err != nil { require.NoError(t, err)
t.Fatal(err)
}
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63())) tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))
@ -86,20 +63,17 @@ func TestSuricata(t *testing.T) {
}, },
} }
acc := testutil.Accumulator{} acc := testutil.Accumulator{}
acc.SetDebug(true) require.NoError(t, s.Start(&acc))
assert.NoError(t, s.Start(&acc)) defer s.Stop()
c, err := net.Dial("unix", tmpfn) c, err := net.Dial("unix", tmpfn)
if err != nil { require.NoError(t, err)
t.Fatalf("failed: %s", err.Error())
}
c.Write([]byte(ex2)) c.Write([]byte(ex2))
c.Write([]byte("\n")) c.Write([]byte("\n"))
c.Close() c.Close()
acc.Wait(1) acc.Wait(1)
s.Stop()
s = Suricata{ s = Suricata{
Source: tmpfn, Source: tmpfn,
Delimiter: ".", Delimiter: ".",
@ -108,23 +82,45 @@ func TestSuricata(t *testing.T) {
}, },
} }
acc.AssertContainsTaggedFields(t, "suricata", expected := []telegraf.Metric{
map[string]interface{}{ testutil.MustMetric(
"capture.kernel_packets": float64(905344474), "suricata",
"capture.kernel_drops": float64(78355440), map[string]string{
"capture.kernel_packets_delta": float64(2376742), "thread": "total",
"capture.kernel_drops_delta": float64(82049), },
}, map[string]interface{}{
map[string]string{"thread": "total"}) "capture.kernel_packets": float64(905344474),
"capture.kernel_drops": float64(78355440),
acc = testutil.Accumulator{} "capture.kernel_packets_delta": float64(2376742),
acc.SetDebug(true) "capture.kernel_drops_delta": float64(82049),
assert.NoError(t, s.Start(&acc)) },
time.Unix(0, 0),
c, err = net.Dial("unix", tmpfn) ),
if err != nil {
log.Println(err)
} }
testutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())
}
func TestThreadStats(t *testing.T) {
dir, err := ioutil.TempDir("", "test")
require.NoError(t, err)
defer os.RemoveAll(dir)
tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))
s := Suricata{
Source: tmpfn,
Delimiter: ".",
Log: testutil.Logger{
Name: "inputs.suricata",
},
}
acc := testutil.Accumulator{}
require.NoError(t, s.Start(&acc))
defer s.Stop()
c, err := net.Dial("unix", tmpfn)
require.NoError(t, err)
c.Write([]byte("")) c.Write([]byte(""))
c.Write([]byte("\n")) c.Write([]byte("\n"))
c.Write([]byte("foobard}\n")) c.Write([]byte("foobard}\n"))
@ -133,21 +129,26 @@ func TestSuricata(t *testing.T) {
c.Close() c.Close()
acc.Wait(1) acc.Wait(1)
s.Stop() expected := []telegraf.Metric{
testutil.MustMetric(
"suricata",
map[string]string{
"thread": "W#05-wlp4s0",
},
map[string]interface{}{
"capture.kernel_packets": float64(905344474),
"capture.kernel_drops": float64(78355440),
},
time.Unix(0, 0),
),
}
acc.AssertContainsTaggedFields(t, "suricata", testutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics(), testutil.IgnoreTime())
map[string]interface{}{
"capture.kernel_packets": float64(905344474),
"capture.kernel_drops": float64(78355440),
},
map[string]string{"thread": "foo"})
} }
func TestSuricataInvalid(t *testing.T) { func TestSuricataInvalid(t *testing.T) {
dir, err := ioutil.TempDir("", "test") dir, err := ioutil.TempDir("", "test")
if err != nil { require.NoError(t, err)
t.Fatal(err)
}
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63())) tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))
@ -160,79 +161,16 @@ func TestSuricataInvalid(t *testing.T) {
acc := testutil.Accumulator{} acc := testutil.Accumulator{}
acc.SetDebug(true) acc.SetDebug(true)
assert.NoError(t, s.Start(&acc)) require.NoError(t, s.Start(&acc))
defer s.Stop()
c, err := net.Dial("unix", tmpfn) c, err := net.Dial("unix", tmpfn)
if err != nil { require.NoError(t, err)
log.Println(err)
}
c.Write([]byte("sfjiowef")) c.Write([]byte("sfjiowef"))
c.Write([]byte("\n")) c.Write([]byte("\n"))
c.Close() c.Close()
acc.WaitError(1) acc.WaitError(1)
s.Stop()
}
func splitAtSingleDot(in string) []string {
res := singleDotRegexp.FindAllStringIndex(in, -1)
if res == nil {
return []string{in}
}
ret := make([]string, 0)
startpos := 0
for _, v := range res {
ret = append(ret, in[startpos:v[0]+1])
startpos = v[1] - 1
}
return append(ret, in[startpos:])
}
func TestSuricataSplitDots(t *testing.T) {
dir, err := ioutil.TempDir("", "test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))
out := splitAtSingleDot("foo")
if len(out) != 1 {
t.Fatalf("splitting 'foo' should yield one result")
}
if out[0] != "foo" {
t.Fatalf("splitting 'foo' should yield one result, 'foo'")
}
s := Suricata{
Source: tmpfn,
Delimiter: ".",
Log: testutil.Logger{
Name: "inputs.suricata",
},
}
acc := testutil.Accumulator{}
acc.SetDebug(true)
assert.NoError(t, s.Start(&acc))
c, err := net.Dial("unix", tmpfn)
if err != nil {
log.Println(err)
}
c.Write([]byte(ex4))
c.Write([]byte("\n"))
c.Close()
acc.Wait(1)
acc.AssertContainsTaggedFields(t, "suricata",
map[string]interface{}{
"capture.kernel_packets": float64(905344474),
"capture.kernel_drops": float64(78355440),
},
map[string]string{"thread": "W1#en..bar1"})
s.Stop()
} }
func TestSuricataInvalidPath(t *testing.T) { func TestSuricataInvalidPath(t *testing.T) {
@ -245,16 +183,12 @@ func TestSuricataInvalidPath(t *testing.T) {
} }
acc := testutil.Accumulator{} acc := testutil.Accumulator{}
acc.SetDebug(true) require.Error(t, s.Start(&acc))
assert.Error(t, s.Start(&acc))
} }
func TestSuricataTooLongLine(t *testing.T) { func TestSuricataTooLongLine(t *testing.T) {
dir, err := ioutil.TempDir("", "test") dir, err := ioutil.TempDir("", "test")
if err != nil { require.NoError(t, err)
t.Fatal(err)
}
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63())) tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))
@ -265,28 +199,23 @@ func TestSuricataTooLongLine(t *testing.T) {
}, },
} }
acc := testutil.Accumulator{} acc := testutil.Accumulator{}
acc.SetDebug(true)
assert.NoError(t, s.Start(&acc)) require.NoError(t, s.Start(&acc))
defer s.Stop()
c, err := net.Dial("unix", tmpfn) c, err := net.Dial("unix", tmpfn)
if err != nil { require.NoError(t, err)
log.Println(err)
}
c.Write([]byte(strings.Repeat("X", 20000000))) c.Write([]byte(strings.Repeat("X", 20000000)))
c.Write([]byte("\n")) c.Write([]byte("\n"))
c.Close() c.Close()
acc.WaitError(1) acc.WaitError(1)
s.Stop()
} }
func TestSuricataEmptyJSON(t *testing.T) { func TestSuricataEmptyJSON(t *testing.T) {
dir, err := ioutil.TempDir("", "test") dir, err := ioutil.TempDir("", "test")
if err != nil { require.NoError(t, err)
t.Fatal(err)
}
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63())) tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))
@ -297,85 +226,23 @@ func TestSuricataEmptyJSON(t *testing.T) {
}, },
} }
acc := testutil.Accumulator{} acc := testutil.Accumulator{}
acc.SetDebug(true) require.NoError(t, s.Start(&acc))
defer s.Stop()
assert.NoError(t, s.Start(&acc))
c, err := net.Dial("unix", tmpfn) c, err := net.Dial("unix", tmpfn)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
} }
c.Write([]byte("\n")) c.Write([]byte("\n"))
c.Close() c.Close()
acc.WaitError(1) acc.WaitError(1)
s.Stop()
}
func TestSuricataInvalidInputs(t *testing.T) {
dir, err := ioutil.TempDir("", "test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
defer func() {
log.SetOutput(os.Stderr)
}()
tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))
for input, errmsg := range map[string]string{
brokenType1: `Unsupported type bool encountered`,
brokenType2: `Unsupported type []interface {} encountered`,
brokenType3: `Unsupported type string encountered`,
brokenType4: `Unsupported type <nil> encountered`,
brokenType5: `Unsupported type <nil> encountered`,
brokenStruct1: `The 'threads' sub-object does not have required structure`,
brokenStruct2: `Input does not contain necessary 'stats' sub-object`,
brokenStruct3: `The 'stats' sub-object does not have required structure`,
brokenStruct4: `The 'stats' sub-object does not have required structure`,
} {
var logBuf buffer
logBuf.Reset()
log.SetOutput(&logBuf)
acc := testutil.Accumulator{}
acc.SetDebug(true)
s := Suricata{
Source: tmpfn,
Delimiter: ".",
Log: testutil.Logger{
Name: "inputs.suricata",
},
}
assert.NoError(t, s.Start(&acc))
c, err := net.Dial("unix", tmpfn)
if err != nil {
t.Fatal(err)
}
c.Write([]byte(input))
c.Write([]byte("\n"))
c.Close()
for {
if bytes.Count(logBuf.Bytes(), []byte{'\n'}) > 0 {
break
}
time.Sleep(50 * time.Millisecond)
}
assert.Contains(t, logBuf.String(), errmsg)
s.Stop()
}
} }
func TestSuricataDisconnectSocket(t *testing.T) { func TestSuricataDisconnectSocket(t *testing.T) {
dir, err := ioutil.TempDir("", "test") dir, err := ioutil.TempDir("", "test")
if err != nil { require.NoError(t, err)
t.Fatal(err)
}
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63())) tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))
@ -386,47 +253,28 @@ func TestSuricataDisconnectSocket(t *testing.T) {
}, },
} }
acc := testutil.Accumulator{} acc := testutil.Accumulator{}
acc.SetDebug(true)
assert.NoError(t, s.Start(&acc)) require.NoError(t, s.Start(&acc))
defer s.Stop()
c, err := net.Dial("unix", tmpfn) c, err := net.Dial("unix", tmpfn)
if err != nil { require.NoError(t, err)
log.Println(err)
}
c.Write([]byte(ex2)) c.Write([]byte(ex2))
c.Write([]byte("\n")) c.Write([]byte("\n"))
c.Close() c.Close()
c, err = net.Dial("unix", tmpfn) c, err = net.Dial("unix", tmpfn)
if err != nil { require.NoError(t, err)
log.Println(err)
}
c.Write([]byte(ex3)) c.Write([]byte(ex3))
c.Write([]byte("\n")) c.Write([]byte("\n"))
c.Close() c.Close()
acc.Wait(2) acc.Wait(2)
s.Stop()
}
func TestSuricataPluginDesc(t *testing.T) {
v, ok := inputs.Inputs["suricata"]
if !ok {
t.Fatal("suricata plugin not registered")
}
desc := v().Description()
if desc != "Suricata stats plugin" {
t.Fatal("invalid description ", desc)
}
} }
func TestSuricataStartStop(t *testing.T) { func TestSuricataStartStop(t *testing.T) {
dir, err := ioutil.TempDir("", "test") dir, err := ioutil.TempDir("", "test")
if err != nil { require.NoError(t, err)
t.Fatal(err)
}
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63())) tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))
@ -437,36 +285,6 @@ func TestSuricataStartStop(t *testing.T) {
}, },
} }
acc := testutil.Accumulator{} acc := testutil.Accumulator{}
acc.SetDebug(true) require.NoError(t, s.Start(&acc))
assert.NoError(t, s.Start(&acc))
s.Stop() s.Stop()
} }
func TestSuricataGather(t *testing.T) {
dir, err := ioutil.TempDir("", "test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
tmpfn := filepath.Join(dir, fmt.Sprintf("t%d", rand.Int63()))
s := Suricata{
Source: tmpfn,
Log: testutil.Logger{
Name: "inputs.suricata",
},
}
acc := testutil.Accumulator{}
acc.SetDebug(true)
assert.NoError(t, s.Gather(&acc))
}
func TestSuricataSampleConfig(t *testing.T) {
v, ok := inputs.Inputs["suricata"]
if !ok {
t.Fatal("suricata plugin not registered")
}
if v().SampleConfig() != sampleConfig {
t.Fatal("wrong sampleconfig")
}
}