github.com/crowdsecurity/crowdsec@v1.6.1/pkg/csprofiles/csprofiles_test.go (about) 1 package csprofiles 2 3 import ( 4 "fmt" 5 "reflect" 6 "testing" 7 8 "github.com/stretchr/testify/require" 9 10 "github.com/crowdsecurity/crowdsec/pkg/csconfig" 11 "github.com/crowdsecurity/crowdsec/pkg/exprhelpers" 12 "github.com/crowdsecurity/crowdsec/pkg/models" 13 ) 14 15 var ( 16 scope = "Country" 17 typ = "ban" 18 boolFalse = false 19 boolTrue = true 20 duration = "1h" 21 22 value = "CH" 23 scenario = "ssh-bf" 24 ) 25 26 func TestNewProfile(t *testing.T) { 27 tests := []struct { 28 name string 29 profileCfg *csconfig.ProfileCfg 30 expectedNbProfile int 31 }{ 32 { 33 name: "filter ok and duration_expr ok", 34 profileCfg: &csconfig.ProfileCfg{ 35 Filters: []string{ 36 "1==1", 37 }, 38 DurationExpr: "1==1", 39 Debug: &boolFalse, 40 Decisions: []models.Decision{ 41 {Type: &typ, Scope: &scope, Simulated: &boolTrue, Duration: &duration}, 42 }, 43 }, 44 expectedNbProfile: 1, 45 }, 46 { 47 name: "filter NOK and duration_expr ok", 48 profileCfg: &csconfig.ProfileCfg{ 49 Filters: []string{ 50 "1==1", 51 "unknownExprHelper() == 'foo'", 52 }, 53 DurationExpr: "1==1", 54 Debug: &boolFalse, 55 Decisions: []models.Decision{ 56 {Type: &typ, Scope: &scope, Simulated: &boolFalse, Duration: &duration}, 57 }, 58 }, 59 expectedNbProfile: 0, 60 }, 61 { 62 name: "filter ok and duration_expr NOK", 63 profileCfg: &csconfig.ProfileCfg{ 64 Filters: []string{ 65 "1==1", 66 }, 67 DurationExpr: "unknownExprHelper() == 'foo'", 68 Debug: &boolFalse, 69 Decisions: []models.Decision{ 70 {Type: &typ, Scope: &scope, Simulated: &boolFalse, Duration: &duration}, 71 }, 72 }, 73 expectedNbProfile: 0, 74 }, 75 { 76 name: "filter ok and duration_expr ok + DEBUG", 77 profileCfg: &csconfig.ProfileCfg{ 78 Filters: []string{ 79 "1==1", 80 }, 81 DurationExpr: "1==1", 82 Debug: &boolTrue, 83 Decisions: []models.Decision{ 84 {Type: &typ, Scope: &scope, Simulated: &boolFalse, Duration: &duration}, 85 }, 86 }, 87 expectedNbProfile: 1, 88 }, 89 { 90 name: "filter ok and no duration", 91 profileCfg: &csconfig.ProfileCfg{ 92 Filters: []string{ 93 "1==1", 94 }, 95 Debug: &boolTrue, 96 Decisions: []models.Decision{ 97 {Type: &typ, Scope: &scope, Simulated: &boolFalse}, 98 }, 99 }, 100 expectedNbProfile: 1, 101 }, 102 } 103 104 for _, test := range tests { 105 test := test 106 t.Run(test.name, func(t *testing.T) { 107 profilesCfg := []*csconfig.ProfileCfg{ 108 test.profileCfg, 109 } 110 profile, _ := NewProfile(profilesCfg) 111 fmt.Printf("expected : %+v | result : %+v", test.expectedNbProfile, len(profile)) 112 require.Len(t, profile, test.expectedNbProfile) 113 }) 114 } 115 } 116 117 func TestEvaluateProfile(t *testing.T) { 118 type args struct { 119 profileCfg *csconfig.ProfileCfg 120 Alert *models.Alert 121 } 122 123 exprhelpers.Init(nil) 124 125 tests := []struct { 126 name string 127 args args 128 expectedDecisionCount int // count of expected decisions 129 expectedDuration string 130 expectedMatchStatus bool 131 }{ 132 { 133 name: "simple pass single expr", 134 args: args{ 135 profileCfg: &csconfig.ProfileCfg{ 136 Filters: []string{fmt.Sprintf("Alert.GetScenario() == \"%s\"", scenario)}, 137 Debug: &boolFalse, 138 }, 139 Alert: &models.Alert{Remediation: true, Scenario: &scenario}, 140 }, 141 expectedDecisionCount: 0, 142 expectedMatchStatus: true, 143 }, 144 { 145 name: "simple fail single expr", 146 args: args{ 147 profileCfg: &csconfig.ProfileCfg{ 148 Filters: []string{"Alert.GetScenario() == \"Foo\""}, 149 }, 150 Alert: &models.Alert{Remediation: true}, 151 }, 152 expectedDecisionCount: 0, 153 expectedMatchStatus: false, 154 }, 155 { 156 name: "1 expr fail 1 expr pass should still eval to match", 157 args: args{ 158 profileCfg: &csconfig.ProfileCfg{ 159 Filters: []string{"1==1", "1!=1"}, 160 }, 161 Alert: &models.Alert{Remediation: true}, 162 }, 163 expectedDecisionCount: 0, 164 expectedMatchStatus: true, 165 }, 166 { 167 name: "simple filter with 2 decision", 168 args: args{ 169 profileCfg: &csconfig.ProfileCfg{ 170 Filters: []string{"1==1"}, 171 Decisions: []models.Decision{ 172 {Type: &typ, Scope: &scope, Simulated: &boolTrue, Duration: &duration}, 173 {Type: &typ, Scope: &scope, Simulated: &boolFalse, Duration: &duration}, 174 }, 175 }, 176 Alert: &models.Alert{Remediation: true, Scenario: &scenario, Source: &models.Source{Value: &value}}, 177 }, 178 expectedDecisionCount: 2, 179 expectedMatchStatus: true, 180 }, 181 { 182 name: "simple filter with decision_expr", 183 args: args{ 184 profileCfg: &csconfig.ProfileCfg{ 185 Filters: []string{"1==1"}, 186 Decisions: []models.Decision{ 187 {Type: &typ, Scope: &scope, Simulated: &boolFalse}, 188 }, 189 DurationExpr: "Sprintf('%dh', 4*4)", 190 }, 191 Alert: &models.Alert{Remediation: true, Scenario: &scenario, Source: &models.Source{Value: &value}}, 192 }, 193 expectedDecisionCount: 1, 194 expectedDuration: "16h", 195 expectedMatchStatus: true, 196 }, 197 } 198 for _, tt := range tests { 199 tt := tt 200 t.Run(tt.name, func(t *testing.T) { 201 profilesCfg := []*csconfig.ProfileCfg{ 202 tt.args.profileCfg, 203 } 204 profile, err := NewProfile(profilesCfg) 205 if err != nil { 206 t.Errorf("failed to get newProfile : %+v", err) 207 } 208 got, got1, _ := profile[0].EvaluateProfile(tt.args.Alert) 209 if !reflect.DeepEqual(len(got), tt.expectedDecisionCount) { 210 t.Errorf("EvaluateProfile() got = %+v, want %+v", got, tt.expectedDecisionCount) 211 } 212 if got1 != tt.expectedMatchStatus { 213 t.Errorf("EvaluateProfile() got1 = %v, want %v", got1, tt.expectedMatchStatus) 214 } 215 if tt.expectedDuration != "" { 216 require.Equal(t, tt.expectedDuration, *got[0].Duration, "The two durations should be the same") 217 } 218 }) 219 } 220 }