github.com/Jeffail/benthos/v3@v3.65.0/lib/processor/json_test.go (about)

     1  package processor
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/Jeffail/benthos/v3/lib/log"
     7  	"github.com/Jeffail/benthos/v3/lib/message"
     8  	"github.com/Jeffail/benthos/v3/lib/metrics"
     9  	"github.com/Jeffail/benthos/v3/lib/util/config"
    10  	yaml "gopkg.in/yaml.v3"
    11  )
    12  
    13  func TestJSONValidation(t *testing.T) {
    14  	conf := NewConfig()
    15  	conf.JSON.Operator = "dfjjkdsgjkdfhgjfh"
    16  	conf.JSON.Parts = []int{0}
    17  	conf.JSON.Path = "foo.bar"
    18  	conf.JSON.Value = []byte(`this isnt valid json`)
    19  
    20  	testLog := log.Noop()
    21  
    22  	if _, err := NewJSON(conf, nil, testLog, metrics.Noop()); err == nil {
    23  		t.Error("Expected error from bad operator")
    24  	}
    25  
    26  	conf = NewConfig()
    27  	conf.JSON.Operator = "move"
    28  	conf.JSON.Parts = []int{0}
    29  	conf.JSON.Path = "foo.bar"
    30  	conf.JSON.Value = []byte(`#%#@$his isnt valid json`)
    31  
    32  	if _, err := NewJSON(conf, nil, testLog, metrics.Noop()); err == nil {
    33  		t.Error("Expected error from bad value")
    34  	}
    35  
    36  	conf = NewConfig()
    37  	conf.JSON.Operator = "move"
    38  	conf.JSON.Parts = []int{0}
    39  	conf.JSON.Path = ""
    40  	conf.JSON.Value = []byte(`""`)
    41  
    42  	if _, err := NewJSON(conf, nil, testLog, metrics.Noop()); err == nil {
    43  		t.Error("Expected error from empty move paths")
    44  	}
    45  
    46  	conf = NewConfig()
    47  	conf.JSON.Operator = "copy"
    48  	conf.JSON.Parts = []int{0}
    49  	conf.JSON.Path = ""
    50  	conf.JSON.Value = []byte(`"foo.bar"`)
    51  
    52  	if _, err := NewJSON(conf, nil, testLog, metrics.Noop()); err == nil {
    53  		t.Error("Expected error from empty copy path")
    54  	}
    55  
    56  	conf = NewConfig()
    57  	conf.JSON.Operator = "copy"
    58  	conf.JSON.Parts = []int{0}
    59  	conf.JSON.Path = "foo.bar"
    60  	conf.JSON.Value = []byte(`""`)
    61  
    62  	if _, err := NewJSON(conf, nil, testLog, metrics.Noop()); err == nil {
    63  		t.Error("Expected error from empty copy destination")
    64  	}
    65  
    66  	conf = NewConfig()
    67  	conf.JSON.Operator = "set"
    68  	conf.JSON.Parts = []int{0}
    69  	conf.JSON.Path = "foo.bar"
    70  	conf.JSON.Value = []byte(`this isnt valid json`)
    71  
    72  	jSet, err := NewJSON(conf, nil, testLog, metrics.Noop())
    73  	if err != nil {
    74  		t.Fatal(err)
    75  	}
    76  
    77  	msgIn := message.New([][]byte{[]byte("this is bad json")})
    78  	msgs, res := jSet.ProcessMessage(msgIn)
    79  	if len(msgs) != 1 {
    80  		t.Fatal("No passthrough for bad input data")
    81  	}
    82  	if res != nil {
    83  		t.Fatal("Non-nil result")
    84  	}
    85  	if exp, act := "this is bad json", string(message.GetAllBytes(msgs[0])[0]); exp != act {
    86  		t.Errorf("Wrong output from bad json: %v != %v", act, exp)
    87  	}
    88  
    89  	conf.JSON.Parts = []int{5}
    90  
    91  	jSet, err = NewJSON(conf, nil, testLog, metrics.Noop())
    92  	if err != nil {
    93  		t.Fatal(err)
    94  	}
    95  
    96  	msgIn = message.New([][]byte{[]byte("{}")})
    97  	msgs, res = jSet.ProcessMessage(msgIn)
    98  	if len(msgs) != 1 {
    99  		t.Fatal("No passthrough for bad index")
   100  	}
   101  	if res != nil {
   102  		t.Fatal("Non-nil result")
   103  	}
   104  	if exp, act := "{}", string(message.GetAllBytes(msgs[0])[0]); exp != act {
   105  		t.Errorf("Wrong output from bad index: %v != %v", act, exp)
   106  	}
   107  }
   108  
   109  func TestJSONPartBounds(t *testing.T) {
   110  	tLog := log.Noop()
   111  	tStats := metrics.Noop()
   112  
   113  	conf := NewConfig()
   114  	conf.JSON.Operator = "set"
   115  	conf.JSON.Path = "foo.bar"
   116  	conf.JSON.Value = []byte(`{"baz":1}`)
   117  
   118  	exp := `{"foo":{"bar":{"baz":1}}}`
   119  
   120  	tests := map[int]int{
   121  		-3: 0,
   122  		-2: 1,
   123  		-1: 2,
   124  		0:  0,
   125  		1:  1,
   126  		2:  2,
   127  	}
   128  
   129  	for i, j := range tests {
   130  		input := [][]byte{
   131  			[]byte(`{"foo":{"bar":2}}`),
   132  			[]byte(`{"foo":{"bar":2}}`),
   133  			[]byte(`{"foo":{"bar":2}}`),
   134  		}
   135  
   136  		conf.JSON.Parts = []int{i}
   137  		proc, err := NewJSON(conf, nil, tLog, tStats)
   138  		if err != nil {
   139  			t.Fatal(err)
   140  		}
   141  
   142  		msgs, res := proc.ProcessMessage(message.New(input))
   143  		if len(msgs) != 1 {
   144  			t.Errorf("Select Parts failed on index: %v", i)
   145  		} else if res != nil {
   146  			t.Errorf("Expected nil response: %v", res)
   147  		}
   148  		if act := string(message.GetAllBytes(msgs[0])[j]); exp != act {
   149  			t.Errorf("Unexpected output for index %v: %v != %v", i, act, exp)
   150  		}
   151  		if act := string(message.GetAllBytes(msgs[0])[(j+1)%3]); exp == act {
   152  			t.Errorf("Processor was applied to wrong index %v: %v != %v", j+1%3, act, exp)
   153  		}
   154  	}
   155  }
   156  
   157  func TestJSONFlattenArray(t *testing.T) {
   158  	type jTest struct {
   159  		name   string
   160  		path   string
   161  		value  string
   162  		input  string
   163  		output string
   164  	}
   165  
   166  	tests := []jTest{
   167  		{
   168  			name:   "flatten ints 1",
   169  			path:   "foo.bar",
   170  			input:  `{"foo":{"bar":[0,[1,2],3,4]}}`,
   171  			output: `{"foo":{"bar":[0,1,2,3,4]}}`,
   172  		},
   173  		{
   174  			name:   "flatten numbers 1",
   175  			path:   "foo.bar",
   176  			input:  `{"foo":{"bar":[[0],[],1.5,[2,3,4]]}}`,
   177  			output: `{"foo":{"bar":[0,1.5,2,3,4]}}`,
   178  		},
   179  		{
   180  			name:   "flatten root numbers 1",
   181  			path:   ".",
   182  			input:  `[0,[1.5],2,[3],4]`,
   183  			output: `[0,1.5,2,3,4]`,
   184  		},
   185  		{
   186  			name:   "flatten strings 1",
   187  			path:   "foo.bar",
   188  			input:  `{"foo":{"bar":[["foo"],["bar","baz"]]}}`,
   189  			output: `{"foo":{"bar":["foo","bar","baz"]}}`,
   190  		},
   191  		{
   192  			name:   "flatten mixed 1",
   193  			path:   "foo.bar",
   194  			input:  `{"foo":{"bar":[["foo","bar"],[5],6,null]}}`,
   195  			output: `{"foo":{"bar":["foo","bar",5,6,null]}}`,
   196  		},
   197  		{
   198  			name:   "flatten empty",
   199  			path:   "foo.bar",
   200  			input:  `{"foo":{"bar":[]}}`,
   201  			output: `{"foo":{"bar":[]}}`,
   202  		},
   203  	}
   204  
   205  	for _, test := range tests {
   206  		conf := NewConfig()
   207  		conf.JSON.Operator = "flatten_array"
   208  		conf.JSON.Parts = []int{0}
   209  		conf.JSON.Path = test.path
   210  		conf.JSON.Value = []byte(test.value)
   211  
   212  		jSet, err := NewJSON(conf, nil, log.Noop(), metrics.Noop())
   213  		if err != nil {
   214  			t.Fatalf("Error for test '%v': %v", test.name, err)
   215  		}
   216  
   217  		inMsg := message.New(
   218  			[][]byte{
   219  				[]byte(test.input),
   220  			},
   221  		)
   222  		msgs, _ := jSet.ProcessMessage(inMsg)
   223  		if len(msgs) != 1 {
   224  			t.Fatalf("Test '%v' did not succeed", test.name)
   225  		}
   226  
   227  		if exp, act := test.output, string(message.GetAllBytes(msgs[0])[0]); exp != act {
   228  			t.Errorf("Wrong result '%v': %v != %v", test.name, act, exp)
   229  		}
   230  	}
   231  }
   232  
   233  func TestJSONFoldStringArray(t *testing.T) {
   234  	type jTest struct {
   235  		name   string
   236  		path   string
   237  		value  string
   238  		input  string
   239  		output string
   240  	}
   241  
   242  	tests := []jTest{
   243  		{
   244  			name:   "fold strings 1",
   245  			path:   "foo.bar",
   246  			input:  `{"foo":{"bar":["foo","bar","baz"]}}`,
   247  			output: `{"foo":{"bar":"foobarbaz"}}`,
   248  		},
   249  		{
   250  			name:   "fold strings 2",
   251  			path:   "foo.bar",
   252  			value:  `" "`,
   253  			input:  `{"foo":{"bar":["foo","bar","baz"]}}`,
   254  			output: `{"foo":{"bar":"foo bar baz"}}`,
   255  		},
   256  		{
   257  			name:   "fold empty",
   258  			path:   "foo.bar",
   259  			input:  `{"foo":{"bar":[]}}`,
   260  			output: `{"foo":{"bar":""}}`,
   261  		},
   262  	}
   263  
   264  	for _, test := range tests {
   265  		conf := NewConfig()
   266  		conf.JSON.Operator = "fold_string_array"
   267  		conf.JSON.Parts = []int{0}
   268  		conf.JSON.Path = test.path
   269  		conf.JSON.Value = []byte(test.value)
   270  
   271  		jSet, err := NewJSON(conf, nil, log.Noop(), metrics.Noop())
   272  		if err != nil {
   273  			t.Fatalf("Error for test '%v': %v", test.name, err)
   274  		}
   275  
   276  		inMsg := message.New(
   277  			[][]byte{
   278  				[]byte(test.input),
   279  			},
   280  		)
   281  		msgs, _ := jSet.ProcessMessage(inMsg)
   282  		if len(msgs) != 1 {
   283  			t.Fatalf("Test '%v' did not succeed", test.name)
   284  		}
   285  
   286  		if exp, act := test.output, string(message.GetAllBytes(msgs[0])[0]); exp != act {
   287  			t.Errorf("Wrong result '%v': %v != %v", test.name, act, exp)
   288  		}
   289  	}
   290  }
   291  
   292  func TestJSONNumberArray(t *testing.T) {
   293  	type jTest struct {
   294  		name   string
   295  		path   string
   296  		value  string
   297  		input  string
   298  		output string
   299  	}
   300  
   301  	tests := []jTest{
   302  		{
   303  			name:   "fold ints 1",
   304  			path:   "foo.bar",
   305  			input:  `{"foo":{"bar":[0,1,2,3,4]}}`,
   306  			output: `{"foo":{"bar":10}}`,
   307  		},
   308  		{
   309  			name:   "fold numbers 1",
   310  			path:   "foo.bar",
   311  			input:  `{"foo":{"bar":[0,1.5,2,3,4]}}`,
   312  			output: `{"foo":{"bar":10.5}}`,
   313  		},
   314  		{
   315  			name:   "fold root numbers 1",
   316  			path:   ".",
   317  			input:  `[0,1.5,2,3,4]`,
   318  			output: `10.5`,
   319  		},
   320  		{
   321  			name:   "fold numbers empty",
   322  			path:   "foo.bar",
   323  			input:  `{"foo":{"bar":[]}}`,
   324  			output: `{"foo":{"bar":0}}`,
   325  		},
   326  	}
   327  
   328  	for _, test := range tests {
   329  		conf := NewConfig()
   330  		conf.JSON.Operator = "fold_number_array"
   331  		conf.JSON.Parts = []int{0}
   332  		conf.JSON.Path = test.path
   333  		conf.JSON.Value = []byte(test.value)
   334  
   335  		jSet, err := NewJSON(conf, nil, log.Noop(), metrics.Noop())
   336  		if err != nil {
   337  			t.Fatalf("Error for test '%v': %v", test.name, err)
   338  		}
   339  
   340  		inMsg := message.New(
   341  			[][]byte{
   342  				[]byte(test.input),
   343  			},
   344  		)
   345  		msgs, _ := jSet.ProcessMessage(inMsg)
   346  		if len(msgs) != 1 {
   347  			t.Fatalf("Test '%v' did not succeed", test.name)
   348  		}
   349  
   350  		if exp, act := test.output, string(message.GetAllBytes(msgs[0])[0]); exp != act {
   351  			t.Errorf("Wrong result '%v': %v != %v", test.name, act, exp)
   352  		}
   353  	}
   354  }
   355  
   356  func TestJSONFlatten(t *testing.T) {
   357  	type jTest struct {
   358  		name   string
   359  		path   string
   360  		input  string
   361  		output string
   362  	}
   363  
   364  	tests := []jTest{
   365  		{
   366  			name:   "flatten 1",
   367  			path:   ".",
   368  			input:  `{"foo":{"bar":"baz"}}`,
   369  			output: `{"foo.bar":"baz"}`,
   370  		},
   371  		{
   372  			name:   "flatten 2",
   373  			path:   ".",
   374  			input:  `{"foo":[{"bar":"1"},{"bar":"2"}]}`,
   375  			output: `{"foo.0.bar":"1","foo.1.bar":"2"}`,
   376  		},
   377  		{
   378  			name:   "flatten 3",
   379  			path:   "",
   380  			input:  `[{"bar":"1"},{"bar":"2"}]`,
   381  			output: `{"0.bar":"1","1.bar":"2"}`,
   382  		},
   383  		{
   384  			name:   "flatten 4",
   385  			path:   "",
   386  			input:  `[["1"],["2","3"]]`,
   387  			output: `{"0.0":"1","1.0":"2","1.1":"3"}`,
   388  		},
   389  		{
   390  			name:   "flatten nested 1",
   391  			path:   "inner",
   392  			input:  `{"inner":{"foo":{"bar":"baz"}}}`,
   393  			output: `{"inner":{"foo.bar":"baz"}}`,
   394  		},
   395  		{
   396  			name:   "flatten nested 2",
   397  			path:   "inner",
   398  			input:  `{"also":"this","inner":{"foo":[{"bar":"1"},{"bar":"2"}]}}`,
   399  			output: `{"also":"this","inner":{"foo.0.bar":"1","foo.1.bar":"2"}}`,
   400  		},
   401  	}
   402  
   403  	for _, test := range tests {
   404  		conf := NewConfig()
   405  		conf.JSON.Operator = "flatten"
   406  		conf.JSON.Parts = []int{0}
   407  		conf.JSON.Path = test.path
   408  
   409  		jSet, err := NewJSON(conf, nil, log.Noop(), metrics.Noop())
   410  		if err != nil {
   411  			t.Fatalf("Error for test '%v': %v", test.name, err)
   412  		}
   413  
   414  		inMsg := message.New(
   415  			[][]byte{
   416  				[]byte(test.input),
   417  			},
   418  		)
   419  		msgs, _ := jSet.ProcessMessage(inMsg)
   420  		if len(msgs) != 1 {
   421  			t.Fatalf("Test '%v' did not succeed", test.name)
   422  		}
   423  
   424  		if exp, act := test.output, string(message.GetAllBytes(msgs[0])[0]); exp != act {
   425  			t.Errorf("Wrong result '%v': %v != %v", test.name, act, exp)
   426  		}
   427  	}
   428  }
   429  
   430  func TestJSONAppend(t *testing.T) {
   431  	tLog := log.Noop()
   432  	tStats := metrics.Noop()
   433  
   434  	type jTest struct {
   435  		name   string
   436  		path   string
   437  		value  string
   438  		input  string
   439  		output string
   440  	}
   441  
   442  	tests := []jTest{
   443  		{
   444  			name:   "append 1",
   445  			path:   "foo.bar",
   446  			value:  `{"baz":1}`,
   447  			input:  `{"foo":{"bar":5}}`,
   448  			output: `{"foo":{"bar":[5,{"baz":1}]}}`,
   449  		},
   450  		{
   451  			name:   "append in array 1",
   452  			path:   "foo.1.bar",
   453  			value:  `{"baz":1}`,
   454  			input:  `{"foo":[{"ignored":true},{"bar":5}]}`,
   455  			output: `{"foo":[{"ignored":true},{"bar":[5,{"baz":1}]}]}`,
   456  		},
   457  		{
   458  			name:   "append nil 1",
   459  			path:   "foo.bar",
   460  			value:  `{"baz":1}`,
   461  			input:  `{"foo":{"bar":null}}`,
   462  			output: `{"foo":{"bar":[null,{"baz":1}]}}`,
   463  		},
   464  		{
   465  			name:   "append nil 2",
   466  			path:   "foo.bar",
   467  			value:  `{"baz":1}`,
   468  			input:  `{"foo":{"bar":[null]}}`,
   469  			output: `{"foo":{"bar":[null,{"baz":1}]}}`,
   470  		},
   471  		{
   472  			name:   "append empty 1",
   473  			path:   "foo.bar",
   474  			value:  `{"baz":1}`,
   475  			input:  `{"foo":{}}`,
   476  			output: `{"foo":{"bar":[{"baz":1}]}}`,
   477  		},
   478  		{
   479  			name:   "append collision 1",
   480  			path:   "foo.bar",
   481  			value:  `{"baz":1}`,
   482  			input:  `{"foo":0}`,
   483  			output: `{"foo":0}`,
   484  		},
   485  		{
   486  			name:   "append array 1",
   487  			path:   "foo.bar",
   488  			value:  `[1,2,3]`,
   489  			input:  `{"foo":{"bar":[0]}}`,
   490  			output: `{"foo":{"bar":[0,1,2,3]}}`,
   491  		},
   492  		{
   493  			name:   "append array 2",
   494  			path:   "foo.bar",
   495  			value:  `[1,2,3]`,
   496  			input:  `{"foo":{"bar":0}}`,
   497  			output: `{"foo":{"bar":[0,1,2,3]}}`,
   498  		},
   499  	}
   500  
   501  	for _, test := range tests {
   502  		conf := NewConfig()
   503  		conf.JSON.Operator = "append"
   504  		conf.JSON.Parts = []int{0}
   505  		conf.JSON.Path = test.path
   506  		conf.JSON.Value = []byte(test.value)
   507  
   508  		jSet, err := NewJSON(conf, nil, tLog, tStats)
   509  		if err != nil {
   510  			t.Fatalf("Error for test '%v': %v", test.name, err)
   511  		}
   512  
   513  		inMsg := message.New(
   514  			[][]byte{
   515  				[]byte(test.input),
   516  			},
   517  		)
   518  		msgs, _ := jSet.ProcessMessage(inMsg)
   519  		if len(msgs) != 1 {
   520  			t.Fatalf("Test '%v' did not succeed", test.name)
   521  		}
   522  
   523  		if exp, act := test.output, string(message.GetAllBytes(msgs[0])[0]); exp != act {
   524  			t.Errorf("Wrong result '%v': %v != %v", test.name, act, exp)
   525  		}
   526  	}
   527  }
   528  
   529  func TestJSONSplit(t *testing.T) {
   530  	type jTest struct {
   531  		name   string
   532  		path   string
   533  		value  string
   534  		input  string
   535  		output string
   536  	}
   537  
   538  	tests := []jTest{
   539  		{
   540  			name:   "split 1",
   541  			path:   "foo.bar",
   542  			value:  `","`,
   543  			input:  `{"foo":{"bar":"1,2,3"}}`,
   544  			output: `{"foo":{"bar":["1","2","3"]}}`,
   545  		},
   546  		{
   547  			name:   "split 2",
   548  			path:   "foo.bar",
   549  			value:  `"-"`,
   550  			input:  `{"foo":{"bar":"1-2-3"}}`,
   551  			output: `{"foo":{"bar":["1","2","3"]}}`,
   552  		},
   553  		{
   554  			name:   "split 3",
   555  			path:   "foo.bar",
   556  			value:  `"-"`,
   557  			input:  `{"foo":{"bar":20}}`,
   558  			output: `{"foo":{"bar":20}}`,
   559  		},
   560  		{
   561  			name:   "split 4",
   562  			path:   "foo.bar",
   563  			value:  `","`,
   564  			input:  `{"foo":{"bar":"1"}}`,
   565  			output: `{"foo":{"bar":["1"]}}`,
   566  		},
   567  		{
   568  			name:   "split 5",
   569  			path:   "foo.bar",
   570  			value:  `","`,
   571  			input:  `{"foo":{"bar":","}}`,
   572  			output: `{"foo":{"bar":["",""]}}`,
   573  		},
   574  	}
   575  
   576  	for _, test := range tests {
   577  		conf := NewConfig()
   578  		conf.JSON.Operator = "split"
   579  		conf.JSON.Parts = []int{0}
   580  		conf.JSON.Path = test.path
   581  		conf.JSON.Value = []byte(test.value)
   582  
   583  		jSet, err := NewJSON(conf, nil, log.Noop(), metrics.Noop())
   584  		if err != nil {
   585  			t.Fatalf("Error for test '%v': %v", test.name, err)
   586  		}
   587  
   588  		inMsg := message.New(
   589  			[][]byte{
   590  				[]byte(test.input),
   591  			},
   592  		)
   593  		msgs, _ := jSet.ProcessMessage(inMsg)
   594  		if len(msgs) != 1 {
   595  			t.Fatalf("Test '%v' did not succeed", test.name)
   596  		}
   597  
   598  		if exp, act := test.output, string(message.GetAllBytes(msgs[0])[0]); exp != act {
   599  			t.Errorf("Wrong result '%v': %v != %v", test.name, act, exp)
   600  		}
   601  	}
   602  }
   603  
   604  func TestJSONMove(t *testing.T) {
   605  	type jTest struct {
   606  		name   string
   607  		path   string
   608  		value  string
   609  		input  string
   610  		output string
   611  	}
   612  
   613  	tests := []jTest{
   614  		{
   615  			name:   "move 1",
   616  			path:   "foo.bar",
   617  			value:  `"bar.baz"`,
   618  			input:  `{"foo":{"bar":5}}`,
   619  			output: `{"bar":{"baz":5},"foo":{}}`,
   620  		},
   621  		{
   622  			name:   "move 2",
   623  			path:   "foo.bar",
   624  			value:  `"bar.baz"`,
   625  			input:  `{"foo":{"bar":5},"bar":{"qux":6}}`,
   626  			output: `{"bar":{"baz":5,"qux":6},"foo":{}}`,
   627  		},
   628  		{
   629  			name:   "move to same path 1",
   630  			path:   "foo.bar",
   631  			value:  `"foo.bar"`,
   632  			input:  `{"foo":{"bar":5},"bar":{"qux":6}}`,
   633  			output: `{"bar":{"qux":6},"foo":{"bar":5}}`,
   634  		},
   635  		{
   636  			name:   "move from root 1",
   637  			path:   ".",
   638  			value:  `"bar.baz"`,
   639  			input:  `{"foo":{"bar":5}}`,
   640  			output: `{"bar":{"baz":{"foo":{"bar":5}}}}`,
   641  		},
   642  		{
   643  			name:   "move to root 1",
   644  			path:   "foo",
   645  			value:  `""`,
   646  			input:  `{"foo":{"bar":5}}`,
   647  			output: `{"bar":5}`,
   648  		},
   649  	}
   650  
   651  	for _, test := range tests {
   652  		conf := NewConfig()
   653  		conf.JSON.Operator = "move"
   654  		conf.JSON.Parts = []int{0}
   655  		conf.JSON.Path = test.path
   656  		conf.JSON.Value = []byte(test.value)
   657  
   658  		jSet, err := NewJSON(conf, nil, log.Noop(), metrics.Noop())
   659  		if err != nil {
   660  			t.Fatalf("Error for test '%v': %v", test.name, err)
   661  		}
   662  
   663  		inMsg := message.New(
   664  			[][]byte{
   665  				[]byte(test.input),
   666  			},
   667  		)
   668  		msgs, _ := jSet.ProcessMessage(inMsg)
   669  		if len(msgs) != 1 {
   670  			t.Fatalf("Test '%v' did not succeed", test.name)
   671  		}
   672  
   673  		if exp, act := test.output, string(message.GetAllBytes(msgs[0])[0]); exp != act {
   674  			t.Errorf("Wrong result '%v': %v != %v", test.name, act, exp)
   675  		}
   676  	}
   677  }
   678  
   679  func TestJSONExplode(t *testing.T) {
   680  	type jTest struct {
   681  		name   string
   682  		path   string
   683  		input  string
   684  		output string
   685  	}
   686  
   687  	tests := []jTest{
   688  		{
   689  			name:   "explode 1",
   690  			path:   "foo",
   691  			input:  `{"foo":[1,2,3],"id":"bar"}`,
   692  			output: `[{"foo":1,"id":"bar"},{"foo":2,"id":"bar"},{"foo":3,"id":"bar"}]`,
   693  		},
   694  		{
   695  			name:   "explode 2",
   696  			path:   "foo.bar",
   697  			input:  `{"foo":{"also":"this","bar":[{"key":"value1"},{"key":"value2"},{"key":"value3"}]},"id":"baz"}`,
   698  			output: `[{"foo":{"also":"this","bar":{"key":"value1"}},"id":"baz"},{"foo":{"also":"this","bar":{"key":"value2"}},"id":"baz"},{"foo":{"also":"this","bar":{"key":"value3"}},"id":"baz"}]`,
   699  		},
   700  		{
   701  			name:   "explode 3",
   702  			path:   "foo",
   703  			input:  `{"foo":{"a":1,"b":2,"c":3},"id":"bar"}`,
   704  			output: `{"a":{"foo":1,"id":"bar"},"b":{"foo":2,"id":"bar"},"c":{"foo":3,"id":"bar"}}`,
   705  		},
   706  		{
   707  			name:   "explode 4",
   708  			path:   "foo.bar",
   709  			input:  `{"foo":{"also":"this","bar":{"key1":["a","b"],"key2":{"c":3,"d":4}}},"id":"baz"}`,
   710  			output: `{"key1":{"foo":{"also":"this","bar":["a","b"]},"id":"baz"},"key2":{"foo":{"also":"this","bar":{"c":3,"d":4}},"id":"baz"}}`,
   711  		},
   712  	}
   713  
   714  	for _, test := range tests {
   715  		conf := NewConfig()
   716  		conf.JSON.Operator = "explode"
   717  		conf.JSON.Parts = []int{0}
   718  		conf.JSON.Path = test.path
   719  
   720  		jSet, err := NewJSON(conf, nil, log.Noop(), metrics.Noop())
   721  		if err != nil {
   722  			t.Fatalf("Error for test '%v': %v", test.name, err)
   723  		}
   724  
   725  		inMsg := message.New(
   726  			[][]byte{
   727  				[]byte(test.input),
   728  			},
   729  		)
   730  		msgs, _ := jSet.ProcessMessage(inMsg)
   731  		if len(msgs) != 1 {
   732  			t.Fatalf("Test '%v' did not succeed", test.name)
   733  		}
   734  
   735  		if exp, act := test.output, string(message.GetAllBytes(msgs[0])[0]); exp != act {
   736  			t.Errorf("Wrong result '%v': %v != %v", test.name, act, exp)
   737  		}
   738  	}
   739  }
   740  
   741  func TestJSONCopy(t *testing.T) {
   742  	tLog := log.Noop()
   743  	tStats := metrics.Noop()
   744  
   745  	type jTest struct {
   746  		name   string
   747  		path   string
   748  		value  string
   749  		input  string
   750  		output string
   751  	}
   752  
   753  	tests := []jTest{
   754  		{
   755  			name:   "copy 1",
   756  			path:   "foo.bar",
   757  			value:  `"bar.baz"`,
   758  			input:  `{"foo":{"bar":5}}`,
   759  			output: `{"bar":{"baz":5},"foo":{"bar":5}}`,
   760  		},
   761  		{
   762  			name:   "copy 2",
   763  			path:   "foo.bar",
   764  			value:  `"bar.baz"`,
   765  			input:  `{"foo":{"bar":5},"bar":{"qux":6}}`,
   766  			output: `{"bar":{"baz":5,"qux":6},"foo":{"bar":5}}`,
   767  		},
   768  	}
   769  
   770  	for _, test := range tests {
   771  		conf := NewConfig()
   772  		conf.JSON.Operator = "copy"
   773  		conf.JSON.Parts = []int{0}
   774  		conf.JSON.Path = test.path
   775  		conf.JSON.Value = []byte(test.value)
   776  
   777  		jSet, err := NewJSON(conf, nil, tLog, tStats)
   778  		if err != nil {
   779  			t.Fatalf("Error for test '%v': %v", test.name, err)
   780  		}
   781  
   782  		inMsg := message.New(
   783  			[][]byte{
   784  				[]byte(test.input),
   785  			},
   786  		)
   787  		msgs, _ := jSet.ProcessMessage(inMsg)
   788  		if len(msgs) != 1 {
   789  			t.Fatalf("Test '%v' did not succeed", test.name)
   790  		}
   791  
   792  		if exp, act := test.output, string(message.GetAllBytes(msgs[0])[0]); exp != act {
   793  			t.Errorf("Wrong result '%v': %v != %v", test.name, act, exp)
   794  		}
   795  	}
   796  }
   797  
   798  func TestJSONClean(t *testing.T) {
   799  	tLog := log.Noop()
   800  	tStats := metrics.Noop()
   801  
   802  	type jTest struct {
   803  		name   string
   804  		path   string
   805  		input  string
   806  		output string
   807  	}
   808  
   809  	tests := []jTest{
   810  		{
   811  			name:   "clean nothing",
   812  			path:   "foo.bar",
   813  			input:  `{"foo":{"bar":5}}`,
   814  			output: `{"foo":{"bar":5}}`,
   815  		},
   816  		{
   817  			name:   "clean array",
   818  			path:   "foo.bar",
   819  			input:  `{"foo":{"bar":[]}}`,
   820  			output: `{"foo":{}}`,
   821  		},
   822  		{
   823  			name:   "clean array 2",
   824  			path:   "foo.bar",
   825  			input:  `{"foo":{"b":[1],"bar":[]}}`,
   826  			output: `{"foo":{"b":[1]}}`,
   827  		},
   828  		{
   829  			name:   "clean array 3",
   830  			path:   "foo",
   831  			input:  `{"foo":{"b":[1],"bar":[]}}`,
   832  			output: `{"foo":{"b":[1]}}`,
   833  		},
   834  		{
   835  			name:   "clean object",
   836  			path:   "foo.bar",
   837  			input:  `{"foo":{"bar":{}}}`,
   838  			output: `{"foo":{}}`,
   839  		},
   840  		{
   841  			name:   "clean object 2",
   842  			path:   "foo.bar",
   843  			input:  `{"foo":{"b":{"1":1},"bar":{}}}`,
   844  			output: `{"foo":{"b":{"1":1}}}`,
   845  		},
   846  		{
   847  			name:   "clean object 3",
   848  			path:   "foo",
   849  			input:  `{"foo":{"b":{"1":1},"bar":{}}}`,
   850  			output: `{"foo":{"b":{"1":1}}}`,
   851  		},
   852  		{
   853  			name:   "clean array from root",
   854  			path:   "",
   855  			input:  `{"foo":{"b":"b","bar":[]}}`,
   856  			output: `{"foo":{"b":"b"}}`,
   857  		},
   858  		{
   859  			name:   "clean object from root",
   860  			path:   "",
   861  			input:  `{"foo":{"b":"b","bar":{}}}`,
   862  			output: `{"foo":{"b":"b"}}`,
   863  		},
   864  		{
   865  			name:   "clean everything object",
   866  			path:   "",
   867  			input:  `{"foo":{"bar":{}}}`,
   868  			output: `{}`,
   869  		},
   870  		{
   871  			name:   "clean everything array",
   872  			path:   "",
   873  			input:  `[{"foo":{"bar":{}}},[]]`,
   874  			output: `[]`,
   875  		},
   876  		{
   877  			name:   "clean everything string",
   878  			path:   "",
   879  			input:  `""`,
   880  			output: `null`,
   881  		},
   882  		{
   883  			name:   "clean arrays",
   884  			path:   "",
   885  			input:  `[[],1,"",2,{},"test",{"foo":{}}]`,
   886  			output: `[1,2,"test"]`,
   887  		},
   888  	}
   889  
   890  	for _, test := range tests {
   891  		conf := NewConfig()
   892  		conf.JSON.Operator = "clean"
   893  		conf.JSON.Parts = []int{0}
   894  		conf.JSON.Path = test.path
   895  
   896  		jSet, err := NewJSON(conf, nil, tLog, tStats)
   897  		if err != nil {
   898  			t.Fatalf("Error for test '%v': %v", test.name, err)
   899  		}
   900  
   901  		inMsg := message.New(
   902  			[][]byte{
   903  				[]byte(test.input),
   904  			},
   905  		)
   906  		msgs, _ := jSet.ProcessMessage(inMsg)
   907  		if len(msgs) != 1 {
   908  			t.Fatalf("Test '%v' did not succeed", test.name)
   909  		}
   910  
   911  		if exp, act := test.output, string(message.GetAllBytes(msgs[0])[0]); exp != act {
   912  			t.Errorf("Wrong result '%v': %v != %v", test.name, act, exp)
   913  		}
   914  	}
   915  }
   916  
   917  func TestJSONSet(t *testing.T) {
   918  	type jTest struct {
   919  		name   string
   920  		path   string
   921  		value  string
   922  		input  string
   923  		output string
   924  	}
   925  
   926  	tests := []jTest{
   927  		{
   928  			name:   "set 1",
   929  			path:   "foo.bar",
   930  			value:  `{"baz":1}`,
   931  			input:  `{"foo":{"bar":5}}`,
   932  			output: `{"foo":{"bar":{"baz":1}}}`,
   933  		},
   934  		{
   935  			name:   "set 2",
   936  			path:   "foo",
   937  			value:  `5`,
   938  			input:  `{"foo":{"bar":5}}`,
   939  			output: `{"foo":5}`,
   940  		},
   941  		{
   942  			name:   "set 3",
   943  			path:   "foo",
   944  			value:  `"5"`,
   945  			input:  `{"foo":{"bar":5}}`,
   946  			output: `{"foo":"5"}`,
   947  		},
   948  		{
   949  			name: "set 4",
   950  			path: "foo.bar",
   951  			value: `{
   952  					"baz": 1
   953  				}`,
   954  			input:  `{"foo":{"bar":5}}`,
   955  			output: `{"foo":{"bar":{"baz":1}}}`,
   956  		},
   957  		{
   958  			name:   "set 5",
   959  			path:   "foo.bar",
   960  			value:  `{"baz":"${!echo:foo}"}`,
   961  			input:  `{"foo":{"bar":5}}`,
   962  			output: `{"foo":{"bar":{"baz":"foo"}}}`,
   963  		},
   964  		{
   965  			name:   "set 6",
   966  			path:   "foo.bar",
   967  			value:  `${!echo:10}`,
   968  			input:  `{"foo":{"bar":5}}`,
   969  			output: `{"foo":{"bar":10}}`,
   970  		},
   971  		{
   972  			name:   "set root 1",
   973  			path:   "",
   974  			value:  `{"baz":1}`,
   975  			input:  `"hello world"`,
   976  			output: `{"baz":1}`,
   977  		},
   978  		{
   979  			name:   "set root 2",
   980  			path:   ".",
   981  			value:  `{"baz":1}`,
   982  			input:  `{"foo":2}`,
   983  			output: `{"baz":1}`,
   984  		},
   985  		{
   986  			name:   "set interpolate 1",
   987  			path:   "foo",
   988  			value:  `{"baz":"${!json("bar")}"}`,
   989  			input:  `{"foo":2,"bar":"hello world this is a string"}`,
   990  			output: `{"bar":"hello world this is a string","foo":{"baz":"hello world this is a string"}}`,
   991  		},
   992  		{
   993  			name:   "set interpolate 2",
   994  			path:   ".",
   995  			value:  `{"${!json("key")}":{"value":"${!json("value")}"}}`,
   996  			input:  `{"key":"dynamic","value":{"foo":"bar"}}`,
   997  			output: `{"dynamic":{"value":"{\"foo\":\"bar\"}"}}`,
   998  		},
   999  		{
  1000  			name:   "set null 1",
  1001  			path:   "foo.bar",
  1002  			value:  `null`,
  1003  			input:  `{"foo":{"bar":5}}`,
  1004  			output: `{"foo":{"bar":null}}`,
  1005  		},
  1006  		{
  1007  			name:   "set null 2",
  1008  			path:   "foo.bar",
  1009  			value:  `null`,
  1010  			input:  `{"foo":{"bar":{"baz":"yelp"}}}`,
  1011  			output: `{"foo":{"bar":null}}`,
  1012  		},
  1013  		{
  1014  			name:   "set unicode 1",
  1015  			path:   "foo.bar",
  1016  			value:  `"contains 🦄 emoji"`,
  1017  			input:  `{"foo":{"bar":{"baz":"yelp"}}}`,
  1018  			output: `{"foo":{"bar":"contains 🦄 emoji"}}`,
  1019  		},
  1020  		{
  1021  			name:   "set unicode 2",
  1022  			path:   "foo.bar",
  1023  			value:  `{"value":{"unicode":"contains 🦄 emoji"}}`,
  1024  			input:  `{"foo":{"bar":{"baz":"yelp"}}}`,
  1025  			output: `{"foo":{"bar":{"value":{"unicode":"contains 🦄 emoji"}}}}`,
  1026  		},
  1027  		{
  1028  			name:   "set unicode 3",
  1029  			path:   "foo.bar",
  1030  			value:  `{"value":"${!json("foo.bar.baz")}"}`,
  1031  			input:  `{"foo":{"bar":{"baz":"foo 🦄 bar"}}}`,
  1032  			output: `{"foo":{"bar":{"value":"foo 🦄 bar"}}}`,
  1033  		},
  1034  	}
  1035  
  1036  	for _, test := range tests {
  1037  		conf := NewConfig()
  1038  		conf.JSON.Operator = "set"
  1039  		conf.JSON.Parts = []int{0}
  1040  		conf.JSON.Path = test.path
  1041  		conf.JSON.Value = []byte(test.value)
  1042  
  1043  		jSet, err := NewJSON(conf, nil, log.Noop(), metrics.Noop())
  1044  		if err != nil {
  1045  			t.Fatalf("Error for test '%v': %v", test.name, err)
  1046  		}
  1047  
  1048  		inMsg := message.New(
  1049  			[][]byte{
  1050  				[]byte(test.input),
  1051  			},
  1052  		)
  1053  		msgs, _ := jSet.ProcessMessage(inMsg)
  1054  		if len(msgs) != 1 {
  1055  			t.Fatalf("Test '%v' did not succeed", test.name)
  1056  		}
  1057  
  1058  		if exp, act := test.output, string(message.GetAllBytes(msgs[0])[0]); exp != act {
  1059  			t.Errorf("Wrong result '%v': %v != %v", test.name, act, exp)
  1060  		}
  1061  	}
  1062  }
  1063  
  1064  func TestJSONSetEdge(t *testing.T) {
  1065  	conf := NewConfig()
  1066  	conf.JSON.Operator = "set"
  1067  	conf.JSON.Path = "foo"
  1068  	conf.JSON.Value = []byte(`"bar"`)
  1069  
  1070  	jSet, err := NewJSON(conf, nil, log.Noop(), metrics.Noop())
  1071  	if err != nil {
  1072  		t.Fatal(err)
  1073  	}
  1074  
  1075  	inMsg := message.New([][]byte{[]byte(`{}`)})
  1076  	msgs, _ := jSet.ProcessMessage(inMsg)
  1077  	if len(msgs) != 1 {
  1078  		t.Fatalf("Wrong count of result messages: %v", len(msgs))
  1079  	}
  1080  	if exp, act := `{"foo":"bar"}`, string(msgs[0].Get(0).Get()); exp != act {
  1081  		t.Errorf("Wrong result: %v != %v", act, exp)
  1082  	}
  1083  
  1084  	msgs, _ = jSet.ProcessMessage(msgs[0])
  1085  	if len(msgs) != 1 {
  1086  		t.Fatalf("Wrong count of result messages: %v", len(msgs))
  1087  	}
  1088  	if exp, act := `{"foo":"bar"}`, string(msgs[0].Get(0).Get()); exp != act {
  1089  		t.Errorf("Wrong result: %v != %v", act, exp)
  1090  	}
  1091  }
  1092  
  1093  func TestJSONConfigYAML(t *testing.T) {
  1094  	tLog := log.Noop()
  1095  	tStats := metrics.Noop()
  1096  
  1097  	input := `{"foo":{"bar":5}}`
  1098  
  1099  	tests := map[string]string{
  1100  		`value: 10`:            `{"foo":{"bar":10}}`,
  1101  		`value: "hello world"`: `{"foo":{"bar":"hello world"}}`,
  1102  		`value: hello world`:   `{"foo":{"bar":"hello world"}}`,
  1103  		`
  1104  value:
  1105    baz: 10`: `{"foo":{"bar":{"baz":10}}}`,
  1106  		`
  1107  value:
  1108    baz:
  1109      - first
  1110      - 2
  1111      - third`: `{"foo":{"bar":{"baz":["first",2,"third"]}}}`,
  1112  		`
  1113  value:
  1114    baz:
  1115      deeper: look at me
  1116    here: 11`: `{"foo":{"bar":{"baz":{"deeper":"look at me"},"here":11}}}`,
  1117  	}
  1118  
  1119  	for config, exp := range tests {
  1120  		conf := NewConfig()
  1121  		conf.JSON.Operator = "set"
  1122  		conf.JSON.Parts = []int{}
  1123  		conf.JSON.Path = "foo.bar"
  1124  
  1125  		if err := yaml.Unmarshal([]byte(config), &conf.JSON); err != nil {
  1126  			t.Fatal(err)
  1127  		}
  1128  
  1129  		jSet, err := NewJSON(conf, nil, tLog, tStats)
  1130  		if err != nil {
  1131  			t.Fatalf("Error creating proc '%v': %v", config, err)
  1132  		}
  1133  
  1134  		inMsg := message.New(
  1135  			[][]byte{
  1136  				[]byte(input),
  1137  			},
  1138  		)
  1139  		msgs, _ := jSet.ProcessMessage(inMsg)
  1140  		if len(msgs) != 1 {
  1141  			t.Fatalf("Test did not succeed with config: %v", config)
  1142  		}
  1143  
  1144  		if act := string(message.GetAllBytes(msgs[0])[0]); exp != act {
  1145  			t.Errorf("Wrong result '%v': %v != %v", config, act, exp)
  1146  		}
  1147  	}
  1148  }
  1149  
  1150  func TestJSONConfigYAMLMarshal(t *testing.T) {
  1151  	tLog := log.Noop()
  1152  	tStats := metrics.Noop()
  1153  
  1154  	tests := []string{
  1155  		`parts:
  1156    - 0
  1157  operator: set
  1158  path: foo.bar
  1159  value:
  1160    baz:
  1161      deeper: look at me
  1162    here: 11
  1163  `,
  1164  		`parts:
  1165    - 0
  1166  operator: set
  1167  path: foo.bar
  1168  value: null
  1169  `,
  1170  		`parts:
  1171    - 0
  1172  operator: set
  1173  path: foo.bar
  1174  value:
  1175    foo: null
  1176  `,
  1177  		`parts:
  1178    - 0
  1179  operator: set
  1180  path: foo.bar
  1181  value:
  1182    baz:
  1183      deeper:
  1184        - first
  1185        - second
  1186        - third
  1187    here: 11
  1188  `,
  1189  		`parts:
  1190    - 5
  1191  operator: set
  1192  path: foo.bar.baz
  1193  value: 5
  1194  `,
  1195  		`parts:
  1196    - 0
  1197  operator: set
  1198  path: foo.bar
  1199  value: hello world
  1200  `,
  1201  		`parts:
  1202    - 0
  1203  operator: set
  1204  path: foo.bar
  1205  value:
  1206    root:
  1207      - values:
  1208          - nested: true
  1209        with: array
  1210  `,
  1211  		`parts:
  1212    - 0
  1213  operator: set
  1214  path: foo.bar
  1215  value:
  1216    foo:
  1217      bar:
  1218        baz:
  1219          value: true
  1220  `,
  1221  	}
  1222  
  1223  	for _, testconfig := range tests {
  1224  		conf := NewConfig()
  1225  		if err := yaml.Unmarshal([]byte(testconfig), &conf.JSON); err != nil {
  1226  			t.Error(err)
  1227  			continue
  1228  		}
  1229  
  1230  		if act, err := config.MarshalYAML(conf.JSON); err != nil {
  1231  			t.Error(err)
  1232  		} else if string(act) != testconfig {
  1233  			t.Errorf("Marshalled config does not match: %v != %v", string(act), testconfig)
  1234  		}
  1235  
  1236  		if _, err := NewJSON(conf, nil, tLog, tStats); err != nil {
  1237  			t.Errorf("Error creating proc '%v': %v", testconfig, err)
  1238  		}
  1239  	}
  1240  }
  1241  
  1242  func TestJSONSelect(t *testing.T) {
  1243  	tLog := log.Noop()
  1244  	tStats := metrics.Noop()
  1245  
  1246  	type jTest struct {
  1247  		name   string
  1248  		path   string
  1249  		input  string
  1250  		output string
  1251  	}
  1252  
  1253  	tests := []jTest{
  1254  		{
  1255  			name:   "select obj",
  1256  			path:   "foo.bar",
  1257  			input:  `{"foo":{"bar":{"baz":1}}}`,
  1258  			output: `{"baz":1}`,
  1259  		},
  1260  		{
  1261  			name:   "select array",
  1262  			path:   "foo.bar",
  1263  			input:  `{"foo":{"bar":["baz","qux"]}}`,
  1264  			output: `["baz","qux"]`,
  1265  		},
  1266  		{
  1267  			name:   "select obj as str",
  1268  			path:   "foo.bar",
  1269  			input:  `{"foo":{"bar":"{\"baz\":1}"}}`,
  1270  			output: `{"baz":1}`,
  1271  		},
  1272  		{
  1273  			name:   "select str",
  1274  			path:   "foo.bar",
  1275  			input:  `{"foo":{"bar":"hello world"}}`,
  1276  			output: `hello world`,
  1277  		},
  1278  		{
  1279  			name:   "select float",
  1280  			path:   "foo.bar",
  1281  			input:  `{"foo":{"bar":0.123}}`,
  1282  			output: `0.123`,
  1283  		},
  1284  		{
  1285  			name:   "select int",
  1286  			path:   "foo.bar",
  1287  			input:  `{"foo":{"bar":123}}`,
  1288  			output: `123`,
  1289  		},
  1290  		{
  1291  			name:   "select bool",
  1292  			path:   "foo.bar",
  1293  			input:  `{"foo":{"bar":true}}`,
  1294  			output: `true`,
  1295  		},
  1296  	}
  1297  
  1298  	for _, test := range tests {
  1299  		conf := NewConfig()
  1300  		conf.JSON.Operator = "select"
  1301  		conf.JSON.Parts = []int{0}
  1302  		conf.JSON.Path = test.path
  1303  
  1304  		jSet, err := NewJSON(conf, nil, tLog, tStats)
  1305  		if err != nil {
  1306  			t.Fatalf("Error for test '%v': %v", test.name, err)
  1307  		}
  1308  
  1309  		inMsg := message.New(
  1310  			[][]byte{
  1311  				[]byte(test.input),
  1312  			},
  1313  		)
  1314  		msgs, _ := jSet.ProcessMessage(inMsg)
  1315  		if len(msgs) != 1 {
  1316  			t.Fatalf("Test '%v' did not succeed", test.name)
  1317  		}
  1318  
  1319  		if exp, act := test.output, string(message.GetAllBytes(msgs[0])[0]); exp != act {
  1320  			t.Errorf("Wrong result '%v': %v != %v", test.name, act, exp)
  1321  		}
  1322  	}
  1323  }
  1324  
  1325  func TestJSONDeletePartBounds(t *testing.T) {
  1326  	tLog := log.Noop()
  1327  	tStats := metrics.Noop()
  1328  
  1329  	conf := NewConfig()
  1330  	conf.JSON.Path = "foo.bar"
  1331  	conf.JSON.Operator = "delete"
  1332  
  1333  	exp := `{"foo":{}}`
  1334  
  1335  	tests := map[int]int{
  1336  		-3: 0,
  1337  		-2: 1,
  1338  		-1: 2,
  1339  		0:  0,
  1340  		1:  1,
  1341  		2:  2,
  1342  	}
  1343  
  1344  	for i, j := range tests {
  1345  		input := [][]byte{
  1346  			[]byte(`{"foo":{"bar":2}}`),
  1347  			[]byte(`{"foo":{"bar":2}}`),
  1348  			[]byte(`{"foo":{"bar":2}}`),
  1349  		}
  1350  
  1351  		conf.JSON.Parts = []int{i}
  1352  		proc, err := NewJSON(conf, nil, tLog, tStats)
  1353  		if err != nil {
  1354  			t.Fatal(err)
  1355  		}
  1356  
  1357  		msgs, res := proc.ProcessMessage(message.New(input))
  1358  		if len(msgs) != 1 {
  1359  			t.Errorf("Select Parts failed on index: %v", i)
  1360  		} else if res != nil {
  1361  			t.Errorf("Expected nil response: %v", res)
  1362  		}
  1363  		if act := string(message.GetAllBytes(msgs[0])[j]); exp != act {
  1364  			t.Errorf("Unexpected output for index %v: %v != %v", i, act, exp)
  1365  		}
  1366  	}
  1367  }
  1368  
  1369  func TestJSONDelete(t *testing.T) {
  1370  	tLog := log.Noop()
  1371  	tStats := metrics.Noop()
  1372  
  1373  	type jTest struct {
  1374  		name   string
  1375  		path   string
  1376  		input  string
  1377  		output string
  1378  	}
  1379  
  1380  	tests := []jTest{
  1381  		{
  1382  			name:   "del field 1",
  1383  			path:   "foo.bar",
  1384  			input:  `{"foo":{"bar":5}}`,
  1385  			output: `{"foo":{}}`,
  1386  		},
  1387  		{
  1388  			name:   "del obj field 1",
  1389  			path:   "foo.bar",
  1390  			input:  `{"foo":{"bar":{"baz":5}}}`,
  1391  			output: `{"foo":{}}`,
  1392  		},
  1393  		{
  1394  			name:   "del array field 1",
  1395  			path:   "foo.bar",
  1396  			input:  `{"foo":{"bar":[5]}}`,
  1397  			output: `{"foo":{}}`,
  1398  		},
  1399  	}
  1400  
  1401  	for _, test := range tests {
  1402  		conf := NewConfig()
  1403  		conf.JSON.Parts = []int{0}
  1404  		conf.JSON.Operator = "delete"
  1405  		conf.JSON.Path = test.path
  1406  
  1407  		jSet, err := NewJSON(conf, nil, tLog, tStats)
  1408  		if err != nil {
  1409  			t.Fatalf("Error for test '%v': %v", test.name, err)
  1410  		}
  1411  
  1412  		inMsg := message.New(
  1413  			[][]byte{
  1414  				[]byte(test.input),
  1415  			},
  1416  		)
  1417  		msgs, _ := jSet.ProcessMessage(inMsg)
  1418  		if len(msgs) != 1 {
  1419  			t.Fatalf("Test '%v' did not succeed", test.name)
  1420  		}
  1421  
  1422  		if exp, act := test.output, string(message.GetAllBytes(msgs[0])[0]); exp != act {
  1423  			t.Errorf("Wrong result '%v': %v != %v", test.name, act, exp)
  1424  		}
  1425  	}
  1426  }