github.com/Jeffail/benthos/v3@v3.65.0/internal/bundle/tracing/bundle_test.go (about) 1 package tracing_test 2 3 import ( 4 "fmt" 5 "strconv" 6 "testing" 7 "time" 8 9 "github.com/Jeffail/benthos/v3/internal/bundle" 10 "github.com/Jeffail/benthos/v3/internal/bundle/tracing" 11 "github.com/Jeffail/benthos/v3/lib/input" 12 "github.com/Jeffail/benthos/v3/lib/log" 13 "github.com/Jeffail/benthos/v3/lib/manager" 14 "github.com/Jeffail/benthos/v3/lib/message" 15 "github.com/Jeffail/benthos/v3/lib/metrics" 16 "github.com/Jeffail/benthos/v3/lib/output" 17 "github.com/Jeffail/benthos/v3/lib/processor" 18 "github.com/Jeffail/benthos/v3/lib/response" 19 "github.com/Jeffail/benthos/v3/lib/types" 20 21 "github.com/stretchr/testify/assert" 22 "github.com/stretchr/testify/require" 23 24 _ "github.com/Jeffail/benthos/v3/public/components/all" 25 ) 26 27 func TestBundleInputTracing(t *testing.T) { 28 tenv, summary := tracing.TracedBundle(bundle.GlobalEnvironment) 29 30 inConfig := input.NewConfig() 31 inConfig.Label = "foo" 32 inConfig.Type = input.TypeGenerate 33 inConfig.Generate.Count = 10 34 inConfig.Generate.Interval = "1us" 35 inConfig.Generate.Mapping = `root.count = count("counting the number of input tracing messages")` 36 37 mgr, err := manager.NewV2( 38 manager.NewResourceConfig(), 39 types.NoopMgr(), 40 log.Noop(), 41 metrics.Noop(), 42 manager.OptSetEnvironment(tenv), 43 ) 44 require.NoError(t, err) 45 46 in, err := mgr.NewInput(inConfig, false) 47 require.NoError(t, err) 48 49 for i := 0; i < 10; i++ { 50 select { 51 case tran := <-in.TransactionChan(): 52 select { 53 case tran.ResponseChan <- response.NewAck(): 54 case <-time.After(time.Second): 55 t.Fatal("timed out") 56 } 57 case <-time.After(time.Second): 58 t.Fatal("timed out") 59 } 60 } 61 62 in.CloseAsync() 63 require.NoError(t, in.WaitForClose(time.Second)) 64 65 assert.Equal(t, uint64(10), summary.Input) 66 assert.Equal(t, uint64(0), summary.ProcessorErrors) 67 assert.Equal(t, uint64(0), summary.Output) 68 69 inEvents := summary.InputEvents() 70 require.Contains(t, inEvents, "foo") 71 72 events := inEvents["foo"] 73 require.Len(t, events, 10) 74 75 for i, e := range events { 76 assert.Equal(t, tracing.EventProduce, e.Type) 77 assert.Equal(t, fmt.Sprintf(`{"count":%v}`, i+1), e.Content) 78 } 79 } 80 81 func TestBundleOutputTracing(t *testing.T) { 82 tenv, summary := tracing.TracedBundle(bundle.GlobalEnvironment) 83 84 outConfig := output.NewConfig() 85 outConfig.Label = "foo" 86 outConfig.Type = output.TypeDrop 87 88 mgr, err := manager.NewV2( 89 manager.NewResourceConfig(), 90 types.NoopMgr(), 91 log.Noop(), 92 metrics.Noop(), 93 manager.OptSetEnvironment(tenv), 94 ) 95 require.NoError(t, err) 96 97 out, err := mgr.NewOutput(outConfig) 98 require.NoError(t, err) 99 100 tranChan := make(chan types.Transaction) 101 require.NoError(t, out.Consume(tranChan)) 102 103 for i := 0; i < 10; i++ { 104 resChan := make(chan types.Response) 105 tran := types.NewTransaction(message.New([][]byte{[]byte(strconv.Itoa(i))}), resChan) 106 select { 107 case tranChan <- tran: 108 select { 109 case <-resChan: 110 case <-time.After(time.Second): 111 t.Fatal("timed out") 112 } 113 case <-time.After(time.Second): 114 t.Fatal("timed out") 115 } 116 } 117 118 out.CloseAsync() 119 require.NoError(t, out.WaitForClose(time.Second)) 120 121 assert.Equal(t, uint64(0), summary.Input) 122 assert.Equal(t, uint64(0), summary.ProcessorErrors) 123 assert.Equal(t, uint64(10), summary.Output) 124 125 outEvents := summary.OutputEvents() 126 require.Contains(t, outEvents, "foo") 127 128 events := outEvents["foo"] 129 require.Len(t, events, 10) 130 131 for i, e := range events { 132 assert.Equal(t, tracing.EventConsume, e.Type) 133 assert.Equal(t, strconv.Itoa(i), e.Content) 134 } 135 } 136 137 func TestBundleOutputWithProcessorsTracing(t *testing.T) { 138 tenv, summary := tracing.TracedBundle(bundle.GlobalEnvironment) 139 140 outConfig := output.NewConfig() 141 outConfig.Label = "foo" 142 outConfig.Type = output.TypeDrop 143 144 blobConf := processor.NewConfig() 145 blobConf.Type = "bloblang" 146 blobConf.Bloblang = "root = content().uppercase()" 147 outConfig.Processors = append(outConfig.Processors, blobConf) 148 149 mgr, err := manager.NewV2( 150 manager.NewResourceConfig(), 151 types.NoopMgr(), 152 log.Noop(), 153 metrics.Noop(), 154 manager.OptSetEnvironment(tenv), 155 ) 156 require.NoError(t, err) 157 158 out, err := mgr.NewOutput(outConfig) 159 require.NoError(t, err) 160 161 tranChan := make(chan types.Transaction) 162 require.NoError(t, out.Consume(tranChan)) 163 164 for i := 0; i < 10; i++ { 165 resChan := make(chan types.Response) 166 tran := types.NewTransaction(message.New([][]byte{[]byte("hello world " + strconv.Itoa(i))}), resChan) 167 select { 168 case tranChan <- tran: 169 select { 170 case <-resChan: 171 case <-time.After(time.Second): 172 t.Fatal("timed out") 173 } 174 case <-time.After(time.Second): 175 t.Fatal("timed out") 176 } 177 } 178 179 out.CloseAsync() 180 require.NoError(t, out.WaitForClose(time.Second)) 181 182 assert.Equal(t, uint64(0), summary.Input) 183 assert.Equal(t, uint64(0), summary.ProcessorErrors) 184 assert.Equal(t, uint64(10), summary.Output) 185 186 outEvents := summary.OutputEvents() 187 require.Contains(t, outEvents, "foo") 188 189 outputEvents := outEvents["foo"] 190 require.Len(t, outputEvents, 10) 191 192 for i, e := range outputEvents { 193 assert.Equal(t, tracing.EventConsume, e.Type) 194 assert.Equal(t, "HELLO WORLD "+strconv.Itoa(i), e.Content) 195 } 196 197 procEvents := summary.ProcessorEvents() 198 require.Contains(t, procEvents, "foo.processor.0") 199 200 processorEvents := procEvents["foo.processor.0"] 201 require.Len(t, processorEvents, 20) 202 203 for i := 0; i < len(processorEvents); i += 2 { 204 consumeEvent := processorEvents[i] 205 produceEvent := processorEvents[i+1] 206 207 assert.Equal(t, tracing.EventConsume, consumeEvent.Type) 208 assert.Equal(t, tracing.EventProduce, produceEvent.Type) 209 210 assert.Equal(t, "hello world "+strconv.Itoa(i/2), consumeEvent.Content) 211 assert.Equal(t, "HELLO WORLD "+strconv.Itoa(i/2), produceEvent.Content) 212 } 213 } 214 215 func TestBundleProcessorTracing(t *testing.T) { 216 tenv, summary := tracing.TracedBundle(bundle.GlobalEnvironment) 217 218 procConfig := processor.NewConfig() 219 procConfig.Label = "foo" 220 procConfig.Type = processor.TypeBloblang 221 procConfig.Bloblang = ` 222 let ctr = content().number() 223 root.count = if $ctr % 2 == 0 { throw("nah %v".format($ctr)) } else { $ctr } 224 ` 225 226 mgr, err := manager.NewV2( 227 manager.NewResourceConfig(), 228 types.NoopMgr(), 229 log.Noop(), 230 metrics.Noop(), 231 manager.OptSetEnvironment(tenv), 232 ) 233 require.NoError(t, err) 234 235 proc, err := mgr.NewProcessor(procConfig) 236 require.NoError(t, err) 237 238 for i := 0; i < 10; i++ { 239 batch, res := proc.ProcessMessage(message.New([][]byte{[]byte(strconv.Itoa(i))})) 240 require.Nil(t, res) 241 require.Len(t, batch, 1) 242 assert.Equal(t, 1, batch[0].Len()) 243 } 244 245 proc.CloseAsync() 246 require.NoError(t, proc.WaitForClose(time.Second)) 247 248 assert.Equal(t, uint64(0), summary.Input) 249 assert.Equal(t, uint64(5), summary.ProcessorErrors) 250 assert.Equal(t, uint64(0), summary.Output) 251 252 procEvents := summary.ProcessorEvents() 253 require.Contains(t, procEvents, "foo") 254 255 events := procEvents["foo"] 256 require.Len(t, events, 25) 257 258 assert.Equal(t, []tracing.NodeEvent{ 259 {Type: "CONSUME", Content: "0"}, 260 {Type: "PRODUCE", Content: "0"}, 261 {Type: "ERROR", Content: "failed assignment (line 3): nah 0"}, 262 {Type: "CONSUME", Content: "1"}, 263 {Type: "PRODUCE", Content: "{\"count\":1}"}, 264 {Type: "CONSUME", Content: "2"}, 265 {Type: "PRODUCE", Content: "2"}, 266 {Type: "ERROR", Content: "failed assignment (line 3): nah 2"}, 267 {Type: "CONSUME", Content: "3"}, 268 {Type: "PRODUCE", Content: "{\"count\":3}"}, 269 {Type: "CONSUME", Content: "4"}, 270 {Type: "PRODUCE", Content: "4"}, 271 {Type: "ERROR", Content: "failed assignment (line 3): nah 4"}, 272 {Type: "CONSUME", Content: "5"}, 273 {Type: "PRODUCE", Content: "{\"count\":5}"}, 274 {Type: "CONSUME", Content: "6"}, 275 {Type: "PRODUCE", Content: "6"}, 276 {Type: "ERROR", Content: "failed assignment (line 3): nah 6"}, 277 {Type: "CONSUME", Content: "7"}, 278 {Type: "PRODUCE", Content: "{\"count\":7}"}, 279 {Type: "CONSUME", Content: "8"}, 280 {Type: "PRODUCE", Content: "8"}, 281 {Type: "ERROR", Content: "failed assignment (line 3): nah 8"}, 282 {Type: "CONSUME", Content: "9"}, 283 {Type: "PRODUCE", Content: "{\"count\":9}"}, 284 }, events) 285 }