github.com/crowdsecurity/crowdsec@v1.6.1/pkg/exprhelpers/jsonextract_test.go (about) 1 package exprhelpers 2 3 import ( 4 "testing" 5 6 log "github.com/sirupsen/logrus" 7 8 "github.com/antonmedv/expr" 9 "github.com/stretchr/testify/assert" 10 "github.com/stretchr/testify/require" 11 ) 12 13 func TestJsonExtract(t *testing.T) { 14 if err := Init(nil); err != nil { 15 log.Fatal(err) 16 } 17 18 err := FileInit(TestFolder, "test_data_re.txt", "regex") 19 if err != nil { 20 log.Fatal(err) 21 } 22 23 tests := []struct { 24 name string 25 jsonBlob string 26 targetField string 27 expectResult string 28 expr string 29 }{ 30 { 31 name: "basic json extract", 32 jsonBlob: `{"test" : "1234"}`, 33 targetField: "test", 34 expectResult: "1234", 35 expr: "JsonExtract(blob, target)", 36 }, 37 { 38 name: "basic json extract with non existing field", 39 jsonBlob: `{"test" : "1234"}`, 40 targetField: "non_existing_field", 41 expectResult: "", 42 expr: "JsonExtract(blob, target)", 43 }, 44 { 45 name: "extract subfield", 46 jsonBlob: `{"test" : {"a": "b"}}`, 47 targetField: "test.a", 48 expectResult: "b", 49 expr: "JsonExtract(blob, target)", 50 }, 51 } 52 53 for _, test := range tests { 54 t.Run(test.name, func(t *testing.T) { 55 env := map[string]interface{}{ 56 "blob": test.jsonBlob, 57 "target": test.targetField, 58 } 59 vm, err := expr.Compile(test.expr, GetExprOptions(env)...) 60 require.NoError(t, err) 61 out, err := expr.Run(vm, env) 62 require.NoError(t, err) 63 assert.Equal(t, test.expectResult, out) 64 }) 65 } 66 } 67 68 func TestJsonExtractUnescape(t *testing.T) { 69 if err := Init(nil); err != nil { 70 log.Fatal(err) 71 } 72 73 err := FileInit(TestFolder, "test_data_re.txt", "regex") 74 if err != nil { 75 log.Fatal(err) 76 } 77 78 tests := []struct { 79 name string 80 jsonBlob string 81 targetField string 82 expectResult string 83 expr string 84 }{ 85 { 86 name: "basic json extract", 87 jsonBlob: `{"log" : "\"GET /JBNwtQ6i.blt HTTP/1.1\" 200 13 \"-\" \"Craftbot\""}`, 88 targetField: "log", 89 expectResult: "\"GET /JBNwtQ6i.blt HTTP/1.1\" 200 13 \"-\" \"Craftbot\"", 90 expr: "JsonExtractUnescape(blob, target)", 91 }, 92 { 93 name: "basic json extract with non existing field", 94 jsonBlob: `{"test" : "1234"}`, 95 targetField: "non_existing_field", 96 expectResult: "", 97 expr: "JsonExtractUnescape(blob, target)", 98 }, 99 } 100 101 for _, test := range tests { 102 t.Run(test.name, func(t *testing.T) { 103 env := map[string]interface{}{ 104 "blob": test.jsonBlob, 105 "target": test.targetField, 106 } 107 vm, err := expr.Compile(test.expr, GetExprOptions(env)...) 108 require.NoError(t, err) 109 out, err := expr.Run(vm, env) 110 require.NoError(t, err) 111 assert.Equal(t, test.expectResult, out) 112 }) 113 } 114 } 115 116 func TestJsonExtractSlice(t *testing.T) { 117 if err := Init(nil); err != nil { 118 log.Fatal(err) 119 } 120 121 err := FileInit(TestFolder, "test_data_re.txt", "regex") 122 if err != nil { 123 log.Fatal(err) 124 } 125 126 tests := []struct { 127 name string 128 jsonBlob string 129 targetField string 130 expectResult []interface{} 131 expr string 132 }{ 133 { 134 name: "try to extract a string as a slice", 135 jsonBlob: `{"test" : "1234"}`, 136 targetField: "test", 137 expectResult: nil, 138 expr: "JsonExtractSlice(blob, target)", 139 }, 140 { 141 name: "basic json slice extract", 142 jsonBlob: `{"test" : ["1234"]}`, 143 targetField: "test", 144 expectResult: []interface{}{"1234"}, 145 expr: "JsonExtractSlice(blob, target)", 146 }, 147 { 148 name: "extract with complex expression", 149 jsonBlob: `{"test": {"foo": [{"a":"b"}]}}`, 150 targetField: "test.foo", 151 expectResult: []interface{}{map[string]interface{}{"a": "b"}}, 152 expr: "JsonExtractSlice(blob, target)", 153 }, 154 { 155 name: "extract non-existing key", 156 jsonBlob: `{"test: "11234"}`, 157 targetField: "foo", 158 expectResult: nil, 159 expr: "JsonExtractSlice(blob, target)", 160 }, 161 } 162 163 for _, test := range tests { 164 test := test 165 t.Run(test.name, func(t *testing.T) { 166 env := map[string]interface{}{ 167 "blob": test.jsonBlob, 168 "target": test.targetField, 169 } 170 vm, err := expr.Compile(test.expr, GetExprOptions(env)...) 171 require.NoError(t, err) 172 out, err := expr.Run(vm, env) 173 require.NoError(t, err) 174 assert.Equal(t, test.expectResult, out) 175 }) 176 } 177 } 178 179 func TestJsonExtractObject(t *testing.T) { 180 if err := Init(nil); err != nil { 181 log.Fatal(err) 182 } 183 184 err := FileInit(TestFolder, "test_data_re.txt", "regex") 185 if err != nil { 186 log.Fatal(err) 187 } 188 189 tests := []struct { 190 name string 191 jsonBlob string 192 targetField string 193 expectResult map[string]interface{} 194 expr string 195 }{ 196 { 197 name: "try to extract a string as an object", 198 jsonBlob: `{"test" : "1234"}`, 199 targetField: "test", 200 expectResult: nil, 201 expr: "JsonExtractObject(blob, target)", 202 }, 203 { 204 name: "basic json object extract", 205 jsonBlob: `{"test" : {"1234": {"foo": "bar"}}}`, 206 targetField: "test", 207 expectResult: map[string]interface{}{"1234": map[string]interface{}{"foo": "bar"}}, 208 expr: "JsonExtractObject(blob, target)", 209 }, 210 { 211 name: "extract with complex expression", 212 jsonBlob: `{"test": {"foo": [{"a":"b"}]}}`, 213 targetField: "test.foo[0]", 214 expectResult: map[string]interface{}{"a": "b"}, 215 expr: "JsonExtractObject(blob, target)", 216 }, 217 } 218 219 for _, test := range tests { 220 test := test 221 t.Run(test.name, func(t *testing.T) { 222 env := map[string]interface{}{ 223 "blob": test.jsonBlob, 224 "target": test.targetField, 225 } 226 vm, err := expr.Compile(test.expr, GetExprOptions(env)...) 227 require.NoError(t, err) 228 out, err := expr.Run(vm, env) 229 require.NoError(t, err) 230 assert.Equal(t, test.expectResult, out) 231 }) 232 } 233 } 234 235 func TestToJson(t *testing.T) { 236 err := Init(nil) 237 require.NoError(t, err) 238 239 tests := []struct { 240 name string 241 obj interface{} 242 expectResult string 243 expr string 244 }{ 245 { 246 name: "convert int", 247 obj: 42, 248 expectResult: "42", 249 expr: "ToJsonString(obj)", 250 }, 251 { 252 name: "convert slice", 253 obj: []string{"foo", "bar"}, 254 expectResult: `["foo","bar"]`, 255 expr: "ToJsonString(obj)", 256 }, 257 { 258 name: "convert map", 259 obj: map[string]string{"foo": "bar"}, 260 expectResult: `{"foo":"bar"}`, 261 expr: "ToJsonString(obj)", 262 }, 263 { 264 name: "convert struct", 265 obj: struct{ Foo string }{"bar"}, 266 expectResult: `{"Foo":"bar"}`, 267 expr: "ToJsonString(obj)", 268 }, 269 { 270 name: "convert complex struct", 271 obj: struct { 272 Foo string 273 Bar struct { 274 Baz string 275 } 276 Bla []string 277 }{ 278 Foo: "bar", 279 Bar: struct { 280 Baz string 281 }{ 282 Baz: "baz", 283 }, 284 Bla: []string{"foo", "bar"}, 285 }, 286 expectResult: `{"Foo":"bar","Bar":{"Baz":"baz"},"Bla":["foo","bar"]}`, 287 expr: "ToJsonString(obj)", 288 }, 289 { 290 name: "convert invalid type", 291 obj: func() {}, 292 expectResult: "", 293 expr: "ToJsonString(obj)", 294 }, 295 } 296 297 for _, test := range tests { 298 t.Run(test.name, func(t *testing.T) { 299 env := map[string]interface{}{ 300 "obj": test.obj, 301 } 302 vm, err := expr.Compile(test.expr, GetExprOptions(env)...) 303 require.NoError(t, err) 304 out, err := expr.Run(vm, env) 305 require.NoError(t, err) 306 assert.Equal(t, test.expectResult, out) 307 }) 308 } 309 } 310 311 func TestUnmarshalJSON(t *testing.T) { 312 err := Init(nil) 313 require.NoError(t, err) 314 315 tests := []struct { 316 name string 317 json string 318 expectResult interface{} 319 expr string 320 }{ 321 { 322 name: "convert int", 323 json: "42", 324 expectResult: float64(42), 325 expr: "UnmarshalJSON(json, out, 'a')", 326 }, 327 { 328 name: "convert slice", 329 json: `["foo","bar"]`, 330 expectResult: []interface{}{"foo", "bar"}, 331 expr: "UnmarshalJSON(json, out, 'a')", 332 }, 333 { 334 name: "convert map", 335 json: `{"foo":"bar"}`, 336 expectResult: map[string]interface{}{"foo": "bar"}, 337 expr: "UnmarshalJSON(json, out, 'a')", 338 }, 339 { 340 name: "convert struct", 341 json: `{"Foo":"bar"}`, 342 expectResult: map[string]interface{}{"Foo": "bar"}, 343 expr: "UnmarshalJSON(json, out, 'a')", 344 }, 345 { 346 name: "convert complex struct", 347 json: `{"Foo":"bar","Bar":{"Baz":"baz"},"Bla":["foo","bar"]}`, 348 expectResult: map[string]interface{}{ 349 "Foo": "bar", 350 "Bar": map[string]interface{}{ 351 "Baz": "baz", 352 }, 353 "Bla": []interface{}{"foo", "bar"}, 354 }, 355 expr: "UnmarshalJSON(json, out, 'a')", 356 }, 357 } 358 359 for _, test := range tests { 360 t.Run(test.name, func(t *testing.T) { 361 outMap := make(map[string]interface{}) 362 env := map[string]interface{}{ 363 "json": test.json, 364 "out": outMap, 365 } 366 vm, err := expr.Compile(test.expr, GetExprOptions(env)...) 367 require.NoError(t, err) 368 _, err = expr.Run(vm, env) 369 require.NoError(t, err) 370 assert.Equal(t, test.expectResult, outMap["a"]) 371 }) 372 } 373 }