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

     1  package processor
     2  
     3  import (
     4  	"strconv"
     5  	"testing"
     6  
     7  	"github.com/Jeffail/benthos/v3/lib/log"
     8  	"github.com/Jeffail/benthos/v3/lib/message"
     9  	"github.com/Jeffail/benthos/v3/lib/metrics"
    10  	"github.com/Jeffail/gabs/v2"
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/require"
    13  )
    14  
    15  func TestJQAllParts(t *testing.T) {
    16  	conf := NewConfig()
    17  	conf.JQ.Query = ".foo.bar"
    18  
    19  	jSet, err := NewJQ(conf, nil, log.Noop(), metrics.Noop())
    20  	require.NoError(t, err)
    21  
    22  	msgIn := message.New([][]byte{
    23  		[]byte(`{"foo":{"bar":0}}`),
    24  		[]byte(`{"foo":{"bar":1}}`),
    25  		[]byte(`{"foo":{"bar":2}}`),
    26  	})
    27  	msgs, res := jSet.ProcessMessage(msgIn)
    28  	require.Nil(t, res)
    29  	require.Len(t, msgs, 1)
    30  	for i, part := range message.GetAllBytes(msgs[0]) {
    31  		assert.Equal(t, strconv.Itoa(i), string(part))
    32  	}
    33  }
    34  
    35  func TestJQValidation(t *testing.T) {
    36  	conf := NewConfig()
    37  	conf.JQ.Query = ".foo.bar"
    38  
    39  	jSet, err := NewJQ(conf, nil, log.Noop(), metrics.Noop())
    40  	require.NoError(t, err)
    41  
    42  	msgIn := message.New([][]byte{[]byte("this is bad json")})
    43  	msgs, res := jSet.ProcessMessage(msgIn)
    44  
    45  	require.Nil(t, res)
    46  	require.Len(t, msgs, 1)
    47  
    48  	assert.Equal(t, "this is bad json", string(message.GetAllBytes(msgs[0])[0]))
    49  }
    50  
    51  func TestJQMutation(t *testing.T) {
    52  	conf := NewConfig()
    53  	conf.JQ.Query = `{foo: .foo} | .foo.bar = "baz"`
    54  
    55  	jSet, err := NewJQ(conf, nil, log.Noop(), metrics.Noop())
    56  	require.NoError(t, err)
    57  
    58  	ogObj := gabs.New()
    59  	ogObj.Set("is this", "foo", "original", "content")
    60  	ogObj.Set("remove this", "bar")
    61  	ogExp := ogObj.String()
    62  
    63  	msgIn := message.New(make([][]byte, 1))
    64  	msgIn.Get(0).SetJSON(ogObj.Data())
    65  	msgs, res := jSet.ProcessMessage(msgIn)
    66  	require.Nil(t, res)
    67  	require.Len(t, msgs, 1)
    68  
    69  	assert.Equal(t, `{"foo":{"bar":"baz","original":{"content":"is this"}}}`, string(message.GetAllBytes(msgs[0])[0]))
    70  	assert.Equal(t, ogExp, ogObj.String())
    71  }
    72  
    73  func TestJQ(t *testing.T) {
    74  	type jTest struct {
    75  		name   string
    76  		path   string
    77  		input  string
    78  		output string
    79  	}
    80  
    81  	tests := []jTest{
    82  		{
    83  			name:   "select obj",
    84  			path:   ".foo.bar",
    85  			input:  `{"foo":{"bar":{"baz":1}}}`,
    86  			output: `{"baz":1}`,
    87  		},
    88  		{
    89  			name:   "select array",
    90  			path:   ".foo.bar",
    91  			input:  `{"foo":{"bar":["baz","qux"]}}`,
    92  			output: `["baz","qux"]`,
    93  		},
    94  		{
    95  			name:   "select obj as str",
    96  			path:   ".foo.bar",
    97  			input:  `{"foo":{"bar":"{\"baz\":1}"}}`,
    98  			output: `"{\"baz\":1}"`,
    99  		},
   100  		{
   101  			name:   "select str",
   102  			path:   ".foo.bar",
   103  			input:  `{"foo":{"bar":"hello world"}}`,
   104  			output: `"hello world"`,
   105  		},
   106  		{
   107  			name:   "select float",
   108  			path:   ".foo.bar",
   109  			input:  `{"foo":{"bar":0.123}}`,
   110  			output: `0.123`,
   111  		},
   112  		{
   113  			name:   "select int",
   114  			path:   ".foo.bar",
   115  			input:  `{"foo":{"bar":123}}`,
   116  			output: `123`,
   117  		},
   118  		{
   119  			name:   "select bool",
   120  			path:   ".foo.bar",
   121  			input:  `{"foo":{"bar":true}}`,
   122  			output: `true`,
   123  		},
   124  		{
   125  			name:   "null result",
   126  			path:   ".baz.qux",
   127  			input:  `{"foo":{"bar":true}}`,
   128  			output: `null`,
   129  		},
   130  		{
   131  			name:   "empty string",
   132  			path:   ".foo.bar",
   133  			input:  `{"foo":{"bar":""}}`,
   134  			output: `""`,
   135  		},
   136  		{
   137  			name:   "convert to csv",
   138  			path:   "[.ts,.id,.msg] | @csv",
   139  			input:  `{"id":"1054fe28","msg":"sample \"log\"","ts":1641393111}`,
   140  			output: `"1641393111,\"1054fe28\",\"sample \"\"log\"\"\""`,
   141  		},
   142  	}
   143  
   144  	for _, test := range tests {
   145  		t.Run(test.name, func(t *testing.T) {
   146  			conf := NewConfig()
   147  			conf.JQ.Query = test.path
   148  
   149  			jSet, err := NewJQ(conf, nil, log.Noop(), metrics.Noop())
   150  			require.NoError(t, err)
   151  
   152  			inMsg := message.New(
   153  				[][]byte{
   154  					[]byte(test.input),
   155  				},
   156  			)
   157  			msgs, _ := jSet.ProcessMessage(inMsg)
   158  			require.Len(t, msgs, 1)
   159  			assert.Equal(t, test.output, string(message.GetAllBytes(msgs[0])[0]))
   160  		})
   161  	}
   162  }
   163  
   164  func TestJQ_OutputRaw(t *testing.T) {
   165  	type jTest struct {
   166  		name   string
   167  		path   string
   168  		input  string
   169  		output string
   170  	}
   171  
   172  	tests := []jTest{
   173  		{
   174  			name:   "select obj",
   175  			path:   ".foo.bar",
   176  			input:  `{"foo":{"bar":{"baz":1}}}`,
   177  			output: `{"baz":1}`,
   178  		},
   179  		{
   180  			name:   "select array",
   181  			path:   ".foo.bar",
   182  			input:  `{"foo":{"bar":["baz","qux"]}}`,
   183  			output: `["baz","qux"]`,
   184  		},
   185  		{
   186  			name:   "select obj as str",
   187  			path:   ".foo.bar",
   188  			input:  `{"foo":{"bar":"{\"baz\":1}"}}`,
   189  			output: `{"baz":1}`,
   190  		},
   191  		{
   192  			name:   "select str",
   193  			path:   ".foo.bar",
   194  			input:  `{"foo":{"bar":"hello world"}}`,
   195  			output: `hello world`,
   196  		},
   197  		{
   198  			name:   "select float",
   199  			path:   ".foo.bar",
   200  			input:  `{"foo":{"bar":0.123}}`,
   201  			output: `0.123`,
   202  		},
   203  		{
   204  			name:   "select int",
   205  			path:   ".foo.bar",
   206  			input:  `{"foo":{"bar":123}}`,
   207  			output: `123`,
   208  		},
   209  		{
   210  			name:   "select bool",
   211  			path:   ".foo.bar",
   212  			input:  `{"foo":{"bar":true}}`,
   213  			output: `true`,
   214  		},
   215  		{
   216  			name:   "null result",
   217  			path:   ".baz.qux",
   218  			input:  `{"foo":{"bar":true}}`,
   219  			output: `null`,
   220  		},
   221  		{
   222  			name:   "empty string",
   223  			path:   ".foo.bar",
   224  			input:  `{"foo":{"bar":""}}`,
   225  			output: ``,
   226  		},
   227  		{
   228  			name:   "convert to csv",
   229  			path:   "[.ts,.id,.msg] | @csv",
   230  			input:  `{"id":"1054fe28","msg":"sample \"log\"","ts":1641393111}`,
   231  			output: `1641393111,"1054fe28","sample ""log"""`,
   232  		},
   233  	}
   234  
   235  	for _, test := range tests {
   236  		t.Run(test.name, func(t *testing.T) {
   237  			conf := NewConfig()
   238  			conf.JQ.Query = test.path
   239  			conf.JQ.OutputRaw = true
   240  
   241  			jSet, err := NewJQ(conf, nil, log.Noop(), metrics.Noop())
   242  			require.NoError(t, err)
   243  
   244  			inMsg := message.New(
   245  				[][]byte{
   246  					[]byte(test.input),
   247  				},
   248  			)
   249  			msgs, _ := jSet.ProcessMessage(inMsg)
   250  			require.Len(t, msgs, 1)
   251  			assert.Equal(t, test.output, string(message.GetAllBytes(msgs[0])[0]))
   252  		})
   253  	}
   254  }