1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033 |
- package exprhelpers
- import (
- "context"
- "fmt"
- "os"
- "time"
- "github.com/pkg/errors"
- "github.com/crowdsecurity/crowdsec/pkg/csconfig"
- "github.com/crowdsecurity/crowdsec/pkg/database"
- "github.com/crowdsecurity/crowdsec/pkg/models"
- "github.com/crowdsecurity/crowdsec/pkg/types"
- log "github.com/sirupsen/logrus"
- "testing"
- "github.com/antonmedv/expr"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- )
- var (
- TestFolder = "tests"
- )
- func getDBClient(t *testing.T) *database.Client {
- t.Helper()
- dbPath, err := os.CreateTemp("", "*sqlite")
- if err != nil {
- t.Fatal(err)
- }
- testDbClient, err := database.NewClient(&csconfig.DatabaseCfg{
- Type: "sqlite",
- DbName: "crowdsec",
- DbPath: dbPath.Name(),
- })
- if err != nil {
- t.Fatal(err)
- }
- return testDbClient
- }
- func TestVisitor(t *testing.T) {
- if err := Init(nil); err != nil {
- log.Fatal(err)
- }
- 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)
- }
- debugFilter, err := NewDebugger(test.filter, expr.Env(GetExprEnv(test.env)))
- if err != nil && test.err == nil {
- log.Fatalf("debug: %s", err)
- }
- if compiledFilter != nil {
- result, err := expr.Run(compiledFilter, GetExprEnv(test.env))
- if err != nil && test.err == nil {
- log.Fatalf("run : %s", err)
- }
- 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(nil); err != nil {
- log.Fatal(err)
- }
- err := FileInit(TestFolder, "test_data_re.txt", "regex")
- if err != nil {
- log.Fatal(err)
- }
- 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.Fatal(err)
- }
- result, err := expr.Run(compiledFilter, GetExprEnv(map[string]interface{}{}))
- if err != nil {
- log.Fatal(err)
- }
- if isOk := assert.Equal(t, test.result, result); !isOk {
- t.Fatalf("test '%s' : NOK", test.name)
- }
- }
- }
- func TestFileInit(t *testing.T) {
- if err := Init(nil); err != nil {
- log.Fatal(err)
- }
- 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.Fatal(err)
- }
- 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(nil); err != nil {
- log.Fatal(err)
- }
- err := FileInit(TestFolder, "test_data.txt", "string")
- if err != nil {
- log.Fatal(err)
- }
- 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.Fatal(err)
- }
- result, err := expr.Run(compiledFilter, GetExprEnv(map[string]interface{}{}))
- if err != nil {
- log.Fatal(err)
- }
- 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 TestIpToRange(t *testing.T) {
- tests := []struct {
- name string
- env map[string]interface{}
- code string
- result string
- err string
- }{
- {
- name: "IpToRange() test: IPv4",
- env: map[string]interface{}{
- "ip": "192.168.1.1",
- "netmask": "16",
- "IpToRange": IpToRange,
- },
- code: "IpToRange(ip, netmask)",
- result: "192.168.0.0/16",
- err: "",
- },
- {
- name: "IpToRange() test: IPv6",
- env: map[string]interface{}{
- "ip": "2001:db8::1",
- "netmask": "/64",
- "IpToRange": IpToRange,
- },
- code: "IpToRange(ip, netmask)",
- result: "2001:db8::/64",
- err: "",
- },
- {
- name: "IpToRange() test: malformed netmask",
- env: map[string]interface{}{
- "ip": "192.168.0.1",
- "netmask": "test",
- "IpToRange": IpToRange,
- },
- code: "IpToRange(ip, netmask)",
- result: "",
- err: "",
- },
- {
- name: "IpToRange() test: malformed IP",
- env: map[string]interface{}{
- "ip": "a.b.c.d",
- "netmask": "24",
- "IpToRange": IpToRange,
- },
- code: "IpToRange(ip, netmask)",
- result: "",
- err: "",
- },
- {
- name: "IpToRange() test: too high netmask",
- env: map[string]interface{}{
- "ip": "192.168.1.1",
- "netmask": "35",
- "IpToRange": IpToRange,
- },
- code: "IpToRange(ip, netmask)",
- result: "",
- 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().UTC()")
- }
- 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)
- }
- }
- func TestQueryEscape(t *testing.T) {
- tests := []struct {
- name string
- env map[string]interface{}
- code string
- result string
- err string
- }{
- {
- name: "QueryEscape() test: basic test",
- env: map[string]interface{}{
- "uri": "/foo?a=1&b=2",
- "QueryEscape": QueryEscape,
- },
- code: "QueryEscape(uri)",
- result: "%2Ffoo%3Fa%3D1%26b%3D2",
- err: "",
- },
- {
- name: "QueryEscape() test: basic test",
- env: map[string]interface{}{
- "uri": "/foo?a=1&&b=<>'\"",
- "QueryEscape": QueryEscape,
- },
- code: "QueryEscape(uri)",
- result: "%2Ffoo%3Fa%3D1%26%26b%3D%3C%3E%27%22",
- 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 TestPathEscape(t *testing.T) {
- tests := []struct {
- name string
- env map[string]interface{}
- code string
- result string
- err string
- }{
- {
- name: "PathEscape() test: basic test",
- env: map[string]interface{}{
- "uri": "/foo?a=1&b=2",
- "PathEscape": PathEscape,
- },
- code: "PathEscape(uri)",
- result: "%2Ffoo%3Fa=1&b=2",
- err: "",
- },
- {
- name: "PathEscape() test: basic test with more special chars",
- env: map[string]interface{}{
- "uri": "/foo?a=1&&b=<>'\"",
- "PathEscape": PathEscape,
- },
- code: "PathEscape(uri)",
- result: "%2Ffoo%3Fa=1&&b=%3C%3E%27%22",
- 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 TestPathUnescape(t *testing.T) {
- tests := []struct {
- name string
- env map[string]interface{}
- code string
- result string
- err string
- }{
- {
- name: "PathUnescape() test: basic test",
- env: map[string]interface{}{
- "uri": "%2Ffoo%3Fa=1&b=%3C%3E%27%22",
- "PathUnescape": PathUnescape,
- },
- code: "PathUnescape(uri)",
- result: "/foo?a=1&b=<>'\"",
- err: "",
- },
- {
- name: "PathUnescape() test: basic test with more special chars",
- env: map[string]interface{}{
- "uri": "/$%7Bjndi",
- "PathUnescape": PathUnescape,
- },
- code: "PathUnescape(uri)",
- result: "/${jndi",
- 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 TestQueryUnescape(t *testing.T) {
- tests := []struct {
- name string
- env map[string]interface{}
- code string
- result string
- err string
- }{
- {
- name: "QueryUnescape() test: basic test",
- env: map[string]interface{}{
- "uri": "%2Ffoo%3Fa=1&b=%3C%3E%27%22",
- "QueryUnescape": QueryUnescape,
- },
- code: "QueryUnescape(uri)",
- result: "/foo?a=1&b=<>'\"",
- err: "",
- },
- {
- name: "QueryUnescape() test: basic test with more special chars",
- env: map[string]interface{}{
- "uri": "/$%7Bjndi",
- "QueryUnescape": QueryUnescape,
- },
- code: "QueryUnescape(uri)",
- result: "/${jndi",
- 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 TestLower(t *testing.T) {
- tests := []struct {
- name string
- env map[string]interface{}
- code string
- result string
- err string
- }{
- {
- name: "Lower() test: basic test",
- env: map[string]interface{}{
- "name": "ABCDEFG",
- "Lower": Lower,
- },
- code: "Lower(name)",
- result: "abcdefg",
- err: "",
- },
- {
- name: "Lower() test: basic test with more special chars",
- env: map[string]interface{}{
- "name": "AbcDefG!#",
- "Lower": Lower,
- },
- code: "Lower(name)",
- result: "abcdefg!#",
- 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 TestGetDecisionsCount(t *testing.T) {
- var err error
- var start_ip, start_sfx, end_ip, end_sfx int64
- var ip_sz int
- existingIP := "1.2.3.4"
- unknownIP := "1.2.3.5"
- ip_sz, start_ip, start_sfx, end_ip, end_sfx, err = types.Addr2Ints(existingIP)
- if err != nil {
- t.Errorf("unable to convert '%s' to int: %s", existingIP, err)
- }
- // Add sample data to DB
- dbClient = getDBClient(t)
- decision := dbClient.Ent.Decision.Create().
- SetUntil(time.Now().Add(time.Hour)).
- SetScenario("crowdsec/test").
- SetStartIP(start_ip).
- SetStartSuffix(start_sfx).
- SetEndIP(end_ip).
- SetEndSuffix(end_sfx).
- SetIPSize(int64(ip_sz)).
- SetType("ban").
- SetScope("IP").
- SetValue(existingIP).
- SetOrigin("CAPI").
- SaveX(context.Background())
- if decision == nil {
- assert.Error(t, errors.Errorf("Failed to create sample decision"))
- }
- tests := []struct {
- name string
- env map[string]interface{}
- code string
- result string
- err string
- }{
- {
- name: "GetDecisionsCount() test: existing IP count",
- env: map[string]interface{}{
- "Alert": &models.Alert{
- Source: &models.Source{
- Value: &existingIP,
- },
- Decisions: []*models.Decision{
- {
- Value: &existingIP,
- },
- },
- },
- "GetDecisionsCount": GetDecisionsCount,
- "sprintf": fmt.Sprintf,
- },
- code: "sprintf('%d', GetDecisionsCount(Alert.GetValue()))",
- result: "1",
- err: "",
- },
- {
- name: "GetDecisionsCount() test: unknown IP count",
- env: map[string]interface{}{
- "Alert": &models.Alert{
- Source: &models.Source{
- Value: &unknownIP,
- },
- Decisions: []*models.Decision{
- {
- Value: &unknownIP,
- },
- },
- },
- "GetDecisionsCount": GetDecisionsCount,
- "sprintf": fmt.Sprintf,
- },
- code: "sprintf('%d', GetDecisionsCount(Alert.GetValue()))",
- result: "0",
- err: "",
- },
- }
- for _, test := range tests {
- program, err := expr.Compile(test.code, expr.Env(GetExprEnv(test.env)))
- require.NoError(t, err)
- output, err := expr.Run(program, GetExprEnv(test.env))
- require.NoError(t, err)
- require.Equal(t, test.result, output)
- log.Printf("test '%s' : OK", test.name)
- }
- }
- func TestGetDecisionsSinceCount(t *testing.T) {
- var err error
- var start_ip, start_sfx, end_ip, end_sfx int64
- var ip_sz int
- existingIP := "1.2.3.4"
- unknownIP := "1.2.3.5"
- ip_sz, start_ip, start_sfx, end_ip, end_sfx, err = types.Addr2Ints(existingIP)
- if err != nil {
- t.Errorf("unable to convert '%s' to int: %s", existingIP, err)
- }
- // Add sample data to DB
- dbClient = getDBClient(t)
- decision := dbClient.Ent.Decision.Create().
- SetUntil(time.Now().Add(time.Hour)).
- SetScenario("crowdsec/test").
- SetStartIP(start_ip).
- SetStartSuffix(start_sfx).
- SetEndIP(end_ip).
- SetEndSuffix(end_sfx).
- SetIPSize(int64(ip_sz)).
- SetType("ban").
- SetScope("IP").
- SetValue(existingIP).
- SetOrigin("CAPI").
- SaveX(context.Background())
- if decision == nil {
- assert.Error(t, errors.Errorf("Failed to create sample decision"))
- }
- decision2 := dbClient.Ent.Decision.Create().
- SetCreatedAt(time.Now().AddDate(0, 0, -1)).
- SetUntil(time.Now().AddDate(0, 0, -1)).
- SetScenario("crowdsec/test").
- SetStartIP(start_ip).
- SetStartSuffix(start_sfx).
- SetEndIP(end_ip).
- SetEndSuffix(end_sfx).
- SetIPSize(int64(ip_sz)).
- SetType("ban").
- SetScope("IP").
- SetValue(existingIP).
- SetOrigin("CAPI").
- SaveX(context.Background())
- if decision2 == nil {
- assert.Error(t, errors.Errorf("Failed to create sample decision"))
- }
- tests := []struct {
- name string
- env map[string]interface{}
- code string
- result string
- err string
- }{
- {
- name: "GetDecisionsSinceCount() test: existing IP count since more than 1 day",
- env: map[string]interface{}{
- "Alert": &models.Alert{
- Source: &models.Source{
- Value: &existingIP,
- },
- Decisions: []*models.Decision{
- {
- Value: &existingIP,
- },
- },
- },
- "GetDecisionsSinceCount": GetDecisionsSinceCount,
- "sprintf": fmt.Sprintf,
- },
- code: "sprintf('%d', GetDecisionsSinceCount(Alert.GetValue(), '25h'))",
- result: "2",
- err: "",
- },
- {
- name: "GetDecisionsSinceCount() test: existing IP count since more than 1 hour",
- env: map[string]interface{}{
- "Alert": &models.Alert{
- Source: &models.Source{
- Value: &existingIP,
- },
- Decisions: []*models.Decision{
- {
- Value: &existingIP,
- },
- },
- },
- "GetDecisionsSinceCount": GetDecisionsSinceCount,
- "sprintf": fmt.Sprintf,
- },
- code: "sprintf('%d', GetDecisionsSinceCount(Alert.GetValue(), '1h'))",
- result: "1",
- err: "",
- },
- {
- name: "GetDecisionsSinceCount() test: unknown IP count",
- env: map[string]interface{}{
- "Alert": &models.Alert{
- Source: &models.Source{
- Value: &unknownIP,
- },
- Decisions: []*models.Decision{
- {
- Value: &unknownIP,
- },
- },
- },
- "GetDecisionsSinceCount": GetDecisionsSinceCount,
- "sprintf": fmt.Sprintf,
- },
- code: "sprintf('%d', GetDecisionsSinceCount(Alert.GetValue(), '1h'))",
- result: "0",
- err: "",
- },
- }
- for _, test := range tests {
- program, err := expr.Compile(test.code, expr.Env(GetExprEnv(test.env)))
- require.NoError(t, err)
- output, err := expr.Run(program, GetExprEnv(test.env))
- require.NoError(t, err)
- require.Equal(t, test.result, output)
- log.Printf("test '%s' : OK", test.name)
- }
- }
- func TestParseUnix(t *testing.T) {
- tests := []struct {
- name string
- env map[string]interface{}
- code string
- result string
- err string
- }{
- {
- name: "ParseUnix() test: valid value with milli",
- env: map[string]interface{}{
- "unix": "1672239773.3590894",
- "ParseUnix": ParseUnix,
- },
- code: "ParseUnix(unix)",
- result: "2022-12-28T15:02:53Z",
- err: "",
- },
- {
- name: "ParseUnix() test: valid value without milli",
- env: map[string]interface{}{
- "unix": "1672239773",
- "ParseUnix": ParseUnix,
- },
- code: "ParseUnix(unix)",
- result: "2022-12-28T15:02:53Z",
- err: "",
- },
- {
- name: "ParseUnix() test: invalid input",
- env: map[string]interface{}{
- "unix": "AbcDefG!#",
- "ParseUnix": ParseUnix,
- },
- code: "ParseUnix(unix)",
- result: "",
- err: "",
- },
- {
- name: "ParseUnix() test: negative value",
- env: map[string]interface{}{
- "unix": "-1000",
- "ParseUnix": ParseUnix,
- },
- code: "ParseUnix(unix)",
- result: "",
- 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)
- }
- }
|