123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457 |
- package exprhelpers
- import (
- "fmt"
- "time"
- log "github.com/sirupsen/logrus"
- "testing"
- "github.com/antonmedv/expr"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- )
- var (
- TestFolder = "tests"
- )
- func TestVisitor(t *testing.T) {
- if err := Init(); err != nil {
- log.Fatalf(err.Error())
- }
- tests := []struct {
- name string
- filter string
- result bool
- env map[string]interface{}
- err error
- }{
- {
- name: "debug : no variable",
- filter: "'crowdsec' startsWith 'crowdse'",
- result: true,
- err: nil,
- env: map[string]interface{}{},
- },
- {
- name: "debug : simple variable",
- filter: "'crowdsec' startsWith static_one && 1 == 1",
- result: true,
- err: nil,
- env: map[string]interface{}{"static_one": string("crowdse")},
- },
- {
- name: "debug : simple variable re-used",
- filter: "static_one.foo == 'bar' && static_one.foo != 'toto'",
- result: true,
- err: nil,
- env: map[string]interface{}{"static_one": map[string]string{"foo": "bar"}},
- },
- {
- name: "debug : can't compile",
- filter: "static_one.foo.toto == 'lol'",
- result: false,
- err: fmt.Errorf("bad syntax"),
- env: map[string]interface{}{"static_one": map[string]string{"foo": "bar"}},
- },
- {
- name: "debug : can't compile #2",
- filter: "static_one.f!oo.to/to == 'lol'",
- result: false,
- err: fmt.Errorf("bad syntax"),
- env: map[string]interface{}{"static_one": map[string]string{"foo": "bar"}},
- },
- {
- name: "debug : can't compile #3",
- filter: "",
- result: false,
- err: fmt.Errorf("bad syntax"),
- env: map[string]interface{}{"static_one": map[string]string{"foo": "bar"}},
- },
- }
- log.SetLevel(log.DebugLevel)
- clog := log.WithFields(log.Fields{
- "type": "test",
- })
- for _, test := range tests {
- compiledFilter, err := expr.Compile(test.filter, expr.Env(GetExprEnv(test.env)))
- if err != nil && test.err == nil {
- log.Fatalf("compile: %s", err.Error())
- }
- debugFilter, err := NewDebugger(test.filter, expr.Env(GetExprEnv(test.env)))
- if err != nil && test.err == nil {
- log.Fatalf("debug: %s", err.Error())
- }
- if compiledFilter != nil {
- result, err := expr.Run(compiledFilter, GetExprEnv(test.env))
- if err != nil && test.err == nil {
- log.Fatalf("run : %s", err.Error())
- }
- if isOk := assert.Equal(t, test.result, result); !isOk {
- t.Fatalf("test '%s' : NOK", test.filter)
- }
- }
- if debugFilter != nil {
- debugFilter.Run(clog, test.result, GetExprEnv(test.env))
- }
- }
- }
- func TestRegexpInFile(t *testing.T) {
- if err := Init(); err != nil {
- log.Fatalf(err.Error())
- }
- err := FileInit(TestFolder, "test_data_re.txt", "regex")
- if err != nil {
- log.Fatalf(err.Error())
- }
- tests := []struct {
- name string
- filter string
- result bool
- err error
- }{
- {
- name: "RegexpInFile() test: lower case word in data file",
- filter: "RegexpInFile('crowdsec', 'test_data_re.txt')",
- result: false,
- err: nil,
- },
- {
- name: "RegexpInFile() test: Match exactly",
- filter: "RegexpInFile('Crowdsec', 'test_data_re.txt')",
- result: true,
- err: nil,
- },
- {
- name: "RegexpInFile() test: match with word before",
- filter: "RegexpInFile('test Crowdsec', 'test_data_re.txt')",
- result: true,
- err: nil,
- },
- {
- name: "RegexpInFile() test: match with word before and other case",
- filter: "RegexpInFile('test CrowdSec', 'test_data_re.txt')",
- result: true,
- err: nil,
- },
- }
- for _, test := range tests {
- compiledFilter, err := expr.Compile(test.filter, expr.Env(GetExprEnv(map[string]interface{}{})))
- if err != nil {
- log.Fatalf(err.Error())
- }
- result, err := expr.Run(compiledFilter, GetExprEnv(map[string]interface{}{}))
- if err != nil {
- log.Fatalf(err.Error())
- }
- if isOk := assert.Equal(t, test.result, result); !isOk {
- t.Fatalf("test '%s' : NOK", test.name)
- }
- }
- }
- func TestFileInit(t *testing.T) {
- if err := Init(); err != nil {
- log.Fatalf(err.Error())
- }
- tests := []struct {
- name string
- filename string
- types string
- result int
- err error
- }{
- {
- name: "file with type:string",
- filename: "test_data.txt",
- types: "string",
- result: 3,
- },
- {
- name: "file with type:string and empty lines + commentaries",
- filename: "test_empty_line.txt",
- types: "string",
- result: 3,
- },
- {
- name: "file with type:re",
- filename: "test_data_re.txt",
- types: "regex",
- result: 2,
- },
- {
- name: "file without type",
- filename: "test_data_no_type.txt",
- types: "",
- },
- }
- for _, test := range tests {
- err := FileInit(TestFolder, test.filename, test.types)
- if err != nil {
- log.Fatalf(err.Error())
- }
- if test.types == "string" {
- if _, ok := dataFile[test.filename]; !ok {
- t.Fatalf("test '%s' : NOK", test.name)
- }
- if isOk := assert.Equal(t, test.result, len(dataFile[test.filename])); !isOk {
- t.Fatalf("test '%s' : NOK", test.name)
- }
- } else if test.types == "regex" {
- if _, ok := dataFileRegex[test.filename]; !ok {
- t.Fatalf("test '%s' : NOK", test.name)
- }
- if isOk := assert.Equal(t, test.result, len(dataFileRegex[test.filename])); !isOk {
- t.Fatalf("test '%s' : NOK", test.name)
- }
- } else {
- if _, ok := dataFileRegex[test.filename]; ok {
- t.Fatalf("test '%s' : NOK", test.name)
- }
- if _, ok := dataFile[test.filename]; ok {
- t.Fatalf("test '%s' : NOK", test.name)
- }
- }
- log.Printf("test '%s' : OK", test.name)
- }
- }
- func TestFile(t *testing.T) {
- if err := Init(); err != nil {
- log.Fatalf(err.Error())
- }
- err := FileInit(TestFolder, "test_data.txt", "string")
- if err != nil {
- log.Fatalf(err.Error())
- }
- tests := []struct {
- name string
- filter string
- result bool
- err error
- }{
- {
- name: "File() test: word in file",
- filter: "'Crowdsec' in File('test_data.txt')",
- result: true,
- err: nil,
- },
- {
- name: "File() test: word in file but different case",
- filter: "'CrowdSecurity' in File('test_data.txt')",
- result: false,
- err: nil,
- },
- {
- name: "File() test: word not in file",
- filter: "'test' in File('test_data.txt')",
- result: false,
- err: nil,
- },
- {
- name: "File() test: filepath provided doesn't exist",
- filter: "'test' in File('non_existing_data.txt')",
- result: false,
- err: nil,
- },
- }
- for _, test := range tests {
- compiledFilter, err := expr.Compile(test.filter, expr.Env(GetExprEnv(map[string]interface{}{})))
- if err != nil {
- log.Fatalf(err.Error())
- }
- result, err := expr.Run(compiledFilter, GetExprEnv(map[string]interface{}{}))
- if err != nil {
- log.Fatalf(err.Error())
- }
- if isOk := assert.Equal(t, test.result, result); !isOk {
- t.Fatalf("test '%s' : NOK", test.name)
- }
- log.Printf("test '%s' : OK", test.name)
- }
- }
- func TestIpInRange(t *testing.T) {
- tests := []struct {
- name string
- env map[string]interface{}
- code string
- result bool
- err string
- }{
- {
- name: "IpInRange() test: basic test",
- env: map[string]interface{}{
- "ip": "192.168.0.1",
- "ipRange": "192.168.0.0/24",
- "IpInRange": IpInRange,
- },
- code: "IpInRange(ip, ipRange)",
- result: true,
- err: "",
- },
- {
- name: "IpInRange() test: malformed IP",
- env: map[string]interface{}{
- "ip": "192.168.0",
- "ipRange": "192.168.0.0/24",
- "IpInRange": IpInRange,
- },
- code: "IpInRange(ip, ipRange)",
- result: false,
- err: "",
- },
- {
- name: "IpInRange() test: malformed IP range",
- env: map[string]interface{}{
- "ip": "192.168.0.0/255",
- "ipRange": "192.168.0.0/24",
- "IpInRange": IpInRange,
- },
- code: "IpInRange(ip, ipRange)",
- result: false,
- err: "",
- },
- }
- for _, test := range tests {
- program, err := expr.Compile(test.code, expr.Env(test.env))
- require.NoError(t, err)
- output, err := expr.Run(program, test.env)
- require.NoError(t, err)
- require.Equal(t, test.result, output)
- log.Printf("test '%s' : OK", test.name)
- }
- }
- func TestAtof(t *testing.T) {
- testFloat := "1.5"
- expectedFloat := 1.5
- if Atof(testFloat) != expectedFloat {
- t.Fatalf("Atof should returned 1.5 as a float")
- }
- log.Printf("test 'Atof()' : OK")
- //bad float
- testFloat = "1aaa.5"
- expectedFloat = 0.0
- if Atof(testFloat) != expectedFloat {
- t.Fatalf("Atof should returned a negative value (error) as a float got")
- }
- log.Printf("test 'Atof()' : OK")
- }
- func TestUpper(t *testing.T) {
- testStr := "test"
- expectedStr := "TEST"
- if Upper(testStr) != expectedStr {
- t.Fatalf("Upper() should returned test in upper case")
- }
- log.Printf("test 'Upper()' : OK")
- }
- func TestTimeNow(t *testing.T) {
- ti, err := time.Parse(time.RFC3339, TimeNow())
- if err != nil {
- t.Fatalf("Error parsing the return value of TimeNow: %s", err)
- }
- if -1*time.Until(ti) > time.Second {
- t.Fatalf("TimeNow func should return time.Now()")
- }
- log.Printf("test 'TimeNow()' : OK")
- }
- func TestParseUri(t *testing.T) {
- tests := []struct {
- name string
- env map[string]interface{}
- code string
- result map[string][]string
- err string
- }{
- {
- name: "ParseUri() test: basic test",
- env: map[string]interface{}{
- "uri": "/foo?a=1&b=2",
- "ParseUri": ParseUri,
- },
- code: "ParseUri(uri)",
- result: map[string][]string{"a": []string{"1"}, "b": []string{"2"}},
- err: "",
- },
- {
- name: "ParseUri() test: no param",
- env: map[string]interface{}{
- "uri": "/foo",
- "ParseUri": ParseUri,
- },
- code: "ParseUri(uri)",
- result: map[string][]string{},
- err: "",
- },
- {
- name: "ParseUri() test: extra question mark",
- env: map[string]interface{}{
- "uri": "/foo?a=1&b=2?",
- "ParseUri": ParseUri,
- },
- code: "ParseUri(uri)",
- result: map[string][]string{"a": []string{"1"}, "b": []string{"2?"}},
- err: "",
- },
- {
- name: "ParseUri() test: weird params",
- env: map[string]interface{}{
- "uri": "/foo?&?&&&&?=123",
- "ParseUri": ParseUri,
- },
- code: "ParseUri(uri)",
- result: map[string][]string{"?": []string{"", "123"}},
- err: "",
- },
- {
- name: "ParseUri() test: bad encoding",
- env: map[string]interface{}{
- "uri": "/foo?a=%%F",
- "ParseUri": ParseUri,
- },
- code: "ParseUri(uri)",
- result: map[string][]string{},
- err: "",
- },
- }
- for _, test := range tests {
- program, err := expr.Compile(test.code, expr.Env(test.env))
- require.NoError(t, err)
- output, err := expr.Run(program, test.env)
- require.NoError(t, err)
- require.Equal(t, test.result, output)
- log.Printf("test '%s' : OK", test.name)
- }
- }
|