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  }