@@ -703,6 +703,147 @@ func NewTestParserConfig() ParserConfig {
703703 return expect
704704}
705705
706+ func TestProcessWithCallback_QuietMode (t * testing.T ) {
707+ // Quiet mode swallows processing errors, but send_quiet still surfaces
708+ // downstream write failures so the pipeline can react to delivery errors.
709+ // drop_quiet never calls write so its parse failure is fully suppressed.
710+ testCases := []struct {
711+ name string
712+ onError string
713+ expectWriteWrap bool
714+ }{
715+ {
716+ name : "SendOnErrorQuiet_WriteFailure_PropagatesWriteError" ,
717+ onError : SendOnErrorQuiet ,
718+ expectWriteWrap : true ,
719+ },
720+ {
721+ name : "DropOnErrorQuiet_ParseFailure_Suppressed" ,
722+ onError : DropOnErrorQuiet ,
723+ },
724+ }
725+
726+ for _ , tc := range testCases {
727+ t .Run (tc .name , func (t * testing.T ) {
728+ fakeOut := testutil .NewFakeOutputWithProcessError (t )
729+ set := componenttest .NewNopTelemetrySettings ()
730+ set .Logger = zaptest .NewLogger (t )
731+ writer := & WriterOperator {
732+ BasicOperator : BasicOperator {
733+ OperatorID : "test-id" ,
734+ OperatorType : "test-type" ,
735+ set : set ,
736+ },
737+ OutputIDs : []string {fakeOut .ID ()},
738+ }
739+ require .NoError (t , writer .SetOutputs ([]operator.Operator {fakeOut }))
740+
741+ parser := ParserOperator {
742+ TransformerOperator : TransformerOperator {
743+ WriterOperator : * writer ,
744+ OnError : tc .onError ,
745+ },
746+ ParseFrom : entry .NewBodyField (),
747+ ParseTo : entry .NewAttributeField (),
748+ }
749+
750+ parse := func (_ any ) (any , error ) {
751+ return nil , errors .New ("parse failure" )
752+ }
753+
754+ ctx := t .Context ()
755+ testEntry := entry .New ()
756+ err := parser .ProcessWithCallback (ctx , testEntry , parse , nil )
757+ if tc .expectWriteWrap {
758+ require .Error (t , err )
759+ require .Contains (t , err .Error (), "failed to send entry after error" )
760+ } else {
761+ require .NoError (t , err , "quiet mode must not propagate the processing error" )
762+ }
763+ })
764+ }
765+ }
766+
767+ // TestProcessWithCallback_QuietMode_SkipAndCallbackPaths exercises the four
768+ // code paths in helper/parser.go that previously did not honor quiet mode:
769+ // - ProcessWithCallback Skip error
770+ // - ProcessWithCallback callback error
771+ // - ProcessBatchWithCallback Skip error
772+ // - ProcessBatchWithCallback callback error
773+ //
774+ // All four must be suppressed when the operator is configured in quiet mode.
775+ func TestProcessWithCallback_QuietMode_SkipAndCallbackPaths (t * testing.T ) {
776+ parse := func (v any ) (any , error ) { return v , nil }
777+ okCb := func (_ * entry.Entry ) error { return nil }
778+ failingCb := func (_ * entry.Entry ) error { return errors .New ("callback failure" ) }
779+
780+ // An "if" expression that always errors during evaluation (because the
781+ // attribute is missing and types do not match), driving the Skip error
782+ // path.
783+ badIfExpr , err := ExprCompileBool (`attributes["missing"] + 1 == 2` )
784+ require .NoError (t , err )
785+
786+ for _ , onError := range []string {DropOnErrorQuiet , SendOnErrorQuiet } {
787+ t .Run ("ProcessWithCallback_Skip_" + onError , func (t * testing.T ) {
788+ writer , _ := writerWithFakeOut (t )
789+ parser := ParserOperator {
790+ TransformerOperator : TransformerOperator {
791+ WriterOperator : * writer ,
792+ OnError : onError ,
793+ IfExpr : badIfExpr ,
794+ },
795+ ParseFrom : entry .NewBodyField (),
796+ ParseTo : entry .NewAttributeField (),
797+ }
798+ require .NoError (t , parser .ProcessWithCallback (t .Context (), entry .New (), parse , okCb ),
799+ "Skip error must be suppressed in quiet mode" )
800+ })
801+
802+ t .Run ("ProcessWithCallback_Callback_" + onError , func (t * testing.T ) {
803+ writer , _ := writerWithFakeOut (t )
804+ parser := ParserOperator {
805+ TransformerOperator : TransformerOperator {
806+ WriterOperator : * writer ,
807+ OnError : onError ,
808+ },
809+ ParseFrom : entry .NewBodyField (),
810+ ParseTo : entry .NewAttributeField (),
811+ }
812+ require .NoError (t , parser .ProcessWithCallback (t .Context (), entry .New (), parse , failingCb ),
813+ "callback error must be suppressed in quiet mode" )
814+ })
815+
816+ t .Run ("ProcessBatchWithCallback_Skip_" + onError , func (t * testing.T ) {
817+ writer , _ := writerWithFakeOut (t )
818+ parser := ParserOperator {
819+ TransformerOperator : TransformerOperator {
820+ WriterOperator : * writer ,
821+ OnError : onError ,
822+ IfExpr : badIfExpr ,
823+ },
824+ ParseFrom : entry .NewBodyField (),
825+ ParseTo : entry .NewAttributeField (),
826+ }
827+ require .NoError (t , parser .ProcessBatchWithCallback (t .Context (), []* entry.Entry {entry .New ()}, parse , okCb ),
828+ "batch Skip error must be suppressed in quiet mode" )
829+ })
830+
831+ t .Run ("ProcessBatchWithCallback_Callback_" + onError , func (t * testing.T ) {
832+ writer , _ := writerWithFakeOut (t )
833+ parser := ParserOperator {
834+ TransformerOperator : TransformerOperator {
835+ WriterOperator : * writer ,
836+ OnError : onError ,
837+ },
838+ ParseFrom : entry .NewBodyField (),
839+ ParseTo : entry .NewAttributeField (),
840+ }
841+ require .NoError (t , parser .ProcessBatchWithCallback (t .Context (), []* entry.Entry {entry .New ()}, parse , failingCb ),
842+ "batch callback error must be suppressed in quiet mode" )
843+ })
844+ }
845+ }
846+
706847func writerWithFakeOut (t * testing.T ) (* WriterOperator , * testutil.FakeOutput ) {
707848 fakeOut := testutil .NewFakeOutput (t )
708849 set := componenttest .NewNopTelemetrySettings ()
0 commit comments