github.com/Jeffail/benthos/v3@v3.65.0/public/service/processor_test.go (about) 1 package service 2 3 import ( 4 "context" 5 "errors" 6 "testing" 7 "time" 8 9 "github.com/Jeffail/benthos/v3/lib/message" 10 "github.com/Jeffail/benthos/v3/lib/metrics" 11 "github.com/Jeffail/benthos/v3/lib/processor" 12 "github.com/stretchr/testify/assert" 13 "github.com/stretchr/testify/require" 14 ) 15 16 type fnProcessor struct { 17 fn func(context.Context, *Message) (MessageBatch, error) 18 closed bool 19 } 20 21 func (p *fnProcessor) Process(ctx context.Context, msg *Message) (MessageBatch, error) { 22 return p.fn(ctx, msg) 23 } 24 25 func (p *fnProcessor) Close(ctx context.Context) error { 26 p.closed = true 27 return nil 28 } 29 30 func TestProcessorAirGapShutdown(t *testing.T) { 31 rp := &fnProcessor{} 32 agrp := newAirGapProcessor("foo", rp, metrics.Noop()) 33 34 err := agrp.WaitForClose(time.Millisecond * 5) 35 assert.EqualError(t, err, "action timed out") 36 assert.False(t, rp.closed) 37 38 agrp.CloseAsync() 39 err = agrp.WaitForClose(time.Millisecond * 5) 40 assert.NoError(t, err) 41 assert.True(t, rp.closed) 42 } 43 44 func TestProcessorAirGapOneToOne(t *testing.T) { 45 agrp := newAirGapProcessor("foo", &fnProcessor{ 46 fn: func(c context.Context, m *Message) (MessageBatch, error) { 47 if b, err := m.AsBytes(); err != nil || string(b) != "unchanged" { 48 return nil, errors.New("nope") 49 } 50 m.SetBytes([]byte("changed")) 51 return MessageBatch{m}, nil 52 }, 53 }, metrics.Noop()) 54 55 msg := message.New([][]byte{[]byte("unchanged")}) 56 msgs, res := agrp.ProcessMessage(msg) 57 require.Nil(t, res) 58 require.Len(t, msgs, 1) 59 assert.Equal(t, 1, msgs[0].Len()) 60 assert.Equal(t, "changed", string(msgs[0].Get(0).Get())) 61 assert.Equal(t, "unchanged", string(msg.Get(0).Get())) 62 } 63 64 func TestProcessorAirGapOneToError(t *testing.T) { 65 agrp := newAirGapProcessor("foo", &fnProcessor{ 66 fn: func(c context.Context, m *Message) (MessageBatch, error) { 67 _, err := m.AsStructured() 68 return nil, err 69 }, 70 }, metrics.Noop()) 71 72 msg := message.New([][]byte{[]byte("not a structured doc")}) 73 msgs, res := agrp.ProcessMessage(msg) 74 require.Nil(t, res) 75 require.Len(t, msgs, 1) 76 assert.Equal(t, 1, msgs[0].Len()) 77 assert.Equal(t, "not a structured doc", string(msgs[0].Get(0).Get())) 78 assert.Equal(t, "not a structured doc", string(msgs[0].Get(0).Get())) 79 assert.Equal(t, "invalid character 'o' in literal null (expecting 'u')", processor.GetFail(msgs[0].Get(0))) 80 } 81 82 func TestProcessorAirGapOneToMany(t *testing.T) { 83 agrp := newAirGapProcessor("foo", &fnProcessor{ 84 fn: func(c context.Context, m *Message) (MessageBatch, error) { 85 if b, err := m.AsBytes(); err != nil || string(b) != "unchanged" { 86 return nil, errors.New("nope") 87 } 88 second := m.Copy() 89 third := m.Copy() 90 m.SetBytes([]byte("changed 1")) 91 second.SetBytes([]byte("changed 2")) 92 third.SetBytes([]byte("changed 3")) 93 return MessageBatch{m, second, third}, nil 94 }, 95 }, metrics.Noop()) 96 97 msg := message.New([][]byte{[]byte("unchanged")}) 98 msgs, res := agrp.ProcessMessage(msg) 99 require.Nil(t, res) 100 require.Len(t, msgs, 1) 101 assert.Equal(t, 3, msgs[0].Len()) 102 assert.Equal(t, "changed 1", string(msgs[0].Get(0).Get())) 103 assert.Equal(t, "changed 2", string(msgs[0].Get(1).Get())) 104 assert.Equal(t, "changed 3", string(msgs[0].Get(2).Get())) 105 assert.Equal(t, "unchanged", string(msg.Get(0).Get())) 106 } 107 108 //------------------------------------------------------------------------------ 109 110 type fnBatchProcessor struct { 111 fn func(context.Context, MessageBatch) ([]MessageBatch, error) 112 closed bool 113 } 114 115 func (p *fnBatchProcessor) ProcessBatch(ctx context.Context, msg MessageBatch) ([]MessageBatch, error) { 116 return p.fn(ctx, msg) 117 } 118 119 func (p *fnBatchProcessor) Close(ctx context.Context) error { 120 p.closed = true 121 return nil 122 } 123 124 func TestBatchProcessorAirGapShutdown(t *testing.T) { 125 rp := &fnBatchProcessor{} 126 agrp := newAirGapBatchProcessor("foo", rp, metrics.Noop()) 127 128 err := agrp.WaitForClose(time.Millisecond * 5) 129 assert.EqualError(t, err, "action timed out") 130 assert.False(t, rp.closed) 131 132 agrp.CloseAsync() 133 err = agrp.WaitForClose(time.Millisecond * 5) 134 assert.NoError(t, err) 135 assert.True(t, rp.closed) 136 } 137 138 func TestBatchProcessorAirGapOneToOne(t *testing.T) { 139 agrp := newAirGapBatchProcessor("foo", &fnBatchProcessor{ 140 fn: func(c context.Context, msgs MessageBatch) ([]MessageBatch, error) { 141 if b, err := msgs[0].AsBytes(); err != nil || string(b) != "unchanged" { 142 return nil, errors.New("nope") 143 } 144 msgs[0].SetBytes([]byte("changed")) 145 return []MessageBatch{{msgs[0]}}, nil 146 }, 147 }, metrics.Noop()) 148 149 msg := message.New([][]byte{[]byte("unchanged")}) 150 msgs, res := agrp.ProcessMessage(msg) 151 require.Nil(t, res) 152 require.Len(t, msgs, 1) 153 assert.Equal(t, 1, msgs[0].Len()) 154 assert.Equal(t, "changed", string(msgs[0].Get(0).Get())) 155 assert.Equal(t, "unchanged", string(msg.Get(0).Get())) 156 } 157 158 func TestBatchProcessorAirGapOneToError(t *testing.T) { 159 agrp := newAirGapBatchProcessor("foo", &fnBatchProcessor{ 160 fn: func(c context.Context, msgs MessageBatch) ([]MessageBatch, error) { 161 _, err := msgs[0].AsStructured() 162 return nil, err 163 }, 164 }, metrics.Noop()) 165 166 msg := message.New([][]byte{[]byte("not a structured doc")}) 167 msgs, res := agrp.ProcessMessage(msg) 168 require.Nil(t, res) 169 require.Len(t, msgs, 1) 170 assert.Equal(t, 1, msgs[0].Len()) 171 assert.Equal(t, "not a structured doc", string(msgs[0].Get(0).Get())) 172 assert.Equal(t, "not a structured doc", string(msgs[0].Get(0).Get())) 173 assert.Equal(t, "invalid character 'o' in literal null (expecting 'u')", processor.GetFail(msgs[0].Get(0))) 174 } 175 176 func TestBatchProcessorAirGapOneToMany(t *testing.T) { 177 agrp := newAirGapBatchProcessor("foo", &fnBatchProcessor{ 178 fn: func(c context.Context, msgs MessageBatch) ([]MessageBatch, error) { 179 if b, err := msgs[0].AsBytes(); err != nil || string(b) != "unchanged" { 180 return nil, errors.New("nope") 181 } 182 second := msgs[0].Copy() 183 third := msgs[0].Copy() 184 msgs[0].SetBytes([]byte("changed 1")) 185 second.SetBytes([]byte("changed 2")) 186 third.SetBytes([]byte("changed 3")) 187 return []MessageBatch{{msgs[0], second}, {third}}, nil 188 }, 189 }, metrics.Noop()) 190 191 msg := message.New([][]byte{[]byte("unchanged")}) 192 msgs, res := agrp.ProcessMessage(msg) 193 require.Nil(t, res) 194 require.Len(t, msgs, 2) 195 assert.Equal(t, "unchanged", string(msg.Get(0).Get())) 196 197 assert.Equal(t, 2, msgs[0].Len()) 198 assert.Equal(t, "changed 1", string(msgs[0].Get(0).Get())) 199 assert.Equal(t, "changed 2", string(msgs[0].Get(1).Get())) 200 201 assert.Equal(t, 1, msgs[1].Len()) 202 assert.Equal(t, "changed 3", string(msgs[1].Get(0).Get())) 203 }