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 }