@@ -760,7 +760,7 @@ func TestPlugin_Observation_PendingQueueEnabled_BroadcastsPendingQueueBlobsInPar
760760}
761761
762762func TestPlugin_Observation_PendingQueueEnabled_BroadcastBlobError (t * testing.T ) {
763- lggr := logger .TestLogger ( t )
763+ lggr , observed := logger .TestLoggerObserved ( t , zapcore . WarnLevel )
764764 store := requests .NewStore [* vaulttypes.Request ]()
765765 r := & ReportingPlugin {
766766 lggr : lggr ,
@@ -803,8 +803,15 @@ func TestPlugin_Observation_PendingQueueEnabled_BroadcastBlobError(t *testing.T)
803803 require .NoError (t , store .Add (& vaulttypes.Request {Payload : p , IDVal : "request-1" }))
804804 rdr := & kv {m : make (map [string ]response )}
805805
806- _ , err = r .Observation (t .Context (), 1 , types.AttributedQuery {}, rdr , & errorBlobBroadcastFetcher {err : errors .New ("boom" )})
807- require .ErrorContains (t , err , "could not broadcast pending queue item as blob: boom" )
806+ obs , err := r .Observation (t .Context (), 1 , types.AttributedQuery {}, rdr , & errorBlobBroadcastFetcher {err : errors .New ("boom" )})
807+ require .NoError (t , err )
808+ require .NotNil (t , obs )
809+
810+ warnLogs := observed .FilterMessage ("failed to broadcast pending queue item as blob, skipping" )
811+ assert .Equal (t , 1 , warnLogs .Len ())
812+ fields := warnLogs .All ()[0 ].ContextMap ()
813+ assert .Equal (t , "request-1" , fields ["requestID" ])
814+ assert .Contains (t , fmt .Sprint (fields ["err" ]), "boom" )
808815}
809816
810817func TestPlugin_Observation_GetSecretsRequest_SecretIdentifierInvalid (t * testing.T ) {
@@ -5166,6 +5173,21 @@ func mockMarshalBlob(ocr3_1types.BlobHandle) ([]byte, error) {
51665173 return []byte {}, nil
51675174}
51685175
5176+ type callbackBlobFetcher struct {
5177+ fn func (payload []byte ) error
5178+ }
5179+
5180+ func (f * callbackBlobFetcher ) BroadcastBlob (_ context.Context , payload []byte , _ ocr3_1types.BlobExpirationHint ) (ocr3_1types.BlobHandle , error ) {
5181+ if err := f .fn (payload ); err != nil {
5182+ return ocr3_1types.BlobHandle {}, err
5183+ }
5184+ return ocr3_1types.BlobHandle {}, nil
5185+ }
5186+
5187+ func (f * callbackBlobFetcher ) FetchBlob (context.Context , ocr3_1types.BlobHandle ) ([]byte , error ) {
5188+ panic ("FetchBlob should not be called in broadcastBlobPayloads tests" )
5189+ }
5190+
51695191func TestPlugin_StateTransition_StoresPendingQueue (t * testing.T ) {
51705192 lggr := logger .TestLogger (t )
51715193 store := requests .NewStore [* vaulttypes.Request ]()
@@ -7108,3 +7130,149 @@ func TestLogUserErrorAware(t *testing.T) {
71087130 assert .Contains (t , fmt .Sprint (fields ["error" ]), "internal error" )
71097131 })
71107132}
7133+
7134+ func TestPlugin_broadcastBlobPayloads (t * testing.T ) {
7135+ t .Run ("empty payloads returns empty slice" , func (t * testing.T ) {
7136+ lggr := logger .TestLogger (t )
7137+ r := & ReportingPlugin {
7138+ lggr : lggr ,
7139+ metrics : newTestMetrics (t ),
7140+ marshalBlob : func (ocr3_1types.BlobHandle ) ([]byte , error ) {
7141+ return []byte ("handle" ), nil
7142+ },
7143+ }
7144+
7145+ fetcher := & callbackBlobFetcher {fn : func ([]byte ) error { return nil }}
7146+ result := r .broadcastBlobPayloads (t .Context (), fetcher , 1 , nil , nil )
7147+ assert .Empty (t , result )
7148+ })
7149+
7150+ t .Run ("all payloads broadcast successfully" , func (t * testing.T ) {
7151+ lggr := logger .TestLogger (t )
7152+ r := & ReportingPlugin {
7153+ lggr : lggr ,
7154+ metrics : newTestMetrics (t ),
7155+ marshalBlob : func (ocr3_1types.BlobHandle ) ([]byte , error ) {
7156+ return []byte ("handle" ), nil
7157+ },
7158+ }
7159+
7160+ fetcher := & callbackBlobFetcher {fn : func ([]byte ) error { return nil }}
7161+ payloads := [][]byte {[]byte ("p1" ), []byte ("p2" ), []byte ("p3" )}
7162+ ids := []string {"req-1" , "req-2" , "req-3" }
7163+
7164+ result := r .broadcastBlobPayloads (t .Context (), fetcher , 1 , payloads , ids )
7165+ assert .Len (t , result , 3 )
7166+ for _ , item := range result {
7167+ assert .Equal (t , []byte ("handle" ), item )
7168+ }
7169+ })
7170+
7171+ t .Run ("failed broadcast is skipped and logged" , func (t * testing.T ) {
7172+ lggr , observed := logger .TestLoggerObserved (t , zapcore .WarnLevel )
7173+ r := & ReportingPlugin {
7174+ lggr : lggr ,
7175+ metrics : newTestMetrics (t ),
7176+ marshalBlob : func (ocr3_1types.BlobHandle ) ([]byte , error ) {
7177+ return []byte ("handle" ), nil
7178+ },
7179+ }
7180+
7181+ fetcher := & callbackBlobFetcher {fn : func (payload []byte ) error {
7182+ if string (payload ) == "p2" {
7183+ return errors .New ("broadcast error" )
7184+ }
7185+ return nil
7186+ }}
7187+
7188+ payloads := [][]byte {[]byte ("p1" ), []byte ("p2" ), []byte ("p3" )}
7189+ ids := []string {"req-1" , "req-2" , "req-3" }
7190+
7191+ result := r .broadcastBlobPayloads (t .Context (), fetcher , 5 , payloads , ids )
7192+ assert .Len (t , result , 2 )
7193+
7194+ warnLogs := observed .FilterMessage ("failed to broadcast pending queue item as blob, skipping" )
7195+ assert .Equal (t , 1 , warnLogs .Len ())
7196+ fields := warnLogs .All ()[0 ].ContextMap ()
7197+ assert .Equal (t , "req-2" , fields ["requestID" ])
7198+ assert .Equal (t , uint64 (5 ), fields ["seqNr" ])
7199+ assert .Contains (t , fmt .Sprint (fields ["err" ]), "broadcast error" )
7200+ })
7201+
7202+ t .Run ("all broadcasts fail returns empty slice" , func (t * testing.T ) {
7203+ lggr , observed := logger .TestLoggerObserved (t , zapcore .WarnLevel )
7204+ r := & ReportingPlugin {
7205+ lggr : lggr ,
7206+ metrics : newTestMetrics (t ),
7207+ marshalBlob : func (ocr3_1types.BlobHandle ) ([]byte , error ) {
7208+ return []byte ("handle" ), nil
7209+ },
7210+ }
7211+
7212+ fetcher := & errorBlobBroadcastFetcher {err : errors .New ("network down" )}
7213+ payloads := [][]byte {[]byte ("p1" ), []byte ("p2" )}
7214+ ids := []string {"req-1" , "req-2" }
7215+
7216+ result := r .broadcastBlobPayloads (t .Context (), fetcher , 1 , payloads , ids )
7217+ assert .Empty (t , result )
7218+
7219+ warnLogs := observed .FilterMessage ("failed to broadcast pending queue item as blob, skipping" )
7220+ assert .Equal (t , 2 , warnLogs .Len ())
7221+ })
7222+
7223+ t .Run ("marshal blob failure skips item and logs warning" , func (t * testing.T ) {
7224+ lggr , observed := logger .TestLoggerObserved (t , zapcore .WarnLevel )
7225+ r := & ReportingPlugin {
7226+ lggr : lggr ,
7227+ metrics : newTestMetrics (t ),
7228+ marshalBlob : func (ocr3_1types.BlobHandle ) ([]byte , error ) {
7229+ return nil , errors .New ("marshal error" )
7230+ },
7231+ }
7232+
7233+ fetcher := & callbackBlobFetcher {fn : func ([]byte ) error { return nil }}
7234+ payloads := [][]byte {[]byte ("p1" ), []byte ("p2" )}
7235+ ids := []string {"req-1" , "req-2" }
7236+
7237+ result := r .broadcastBlobPayloads (t .Context (), fetcher , 1 , payloads , ids )
7238+ assert .Empty (t , result )
7239+
7240+ warnLogs := observed .FilterMessage ("failed to marshal blob handle, skipping" )
7241+ assert .Equal (t , 2 , warnLogs .Len ())
7242+ })
7243+
7244+ t .Run ("mix of broadcast and marshal failures" , func (t * testing.T ) {
7245+ lggr , observed := logger .TestLoggerObserved (t , zapcore .WarnLevel )
7246+
7247+ marshalCallCount := atomic.Int32 {}
7248+ r := & ReportingPlugin {
7249+ lggr : lggr ,
7250+ metrics : newTestMetrics (t ),
7251+ marshalBlob : func (ocr3_1types.BlobHandle ) ([]byte , error ) {
7252+ n := marshalCallCount .Add (1 )
7253+ if n == 1 {
7254+ return nil , errors .New ("marshal error" )
7255+ }
7256+ return []byte ("handle" ), nil
7257+ },
7258+ }
7259+
7260+ fetcher := & callbackBlobFetcher {fn : func (payload []byte ) error {
7261+ if string (payload ) == "p1" {
7262+ return errors .New ("broadcast error" )
7263+ }
7264+ return nil
7265+ }}
7266+
7267+ payloads := [][]byte {[]byte ("p1" ), []byte ("p2" ), []byte ("p3" )}
7268+ ids := []string {"req-1" , "req-2" , "req-3" }
7269+
7270+ result := r .broadcastBlobPayloads (t .Context (), fetcher , 1 , payloads , ids )
7271+
7272+ broadcastWarns := observed .FilterMessage ("failed to broadcast pending queue item as blob, skipping" )
7273+ marshalWarns := observed .FilterMessage ("failed to marshal blob handle, skipping" )
7274+ assert .Equal (t , 1 , broadcastWarns .Len ())
7275+ assert .Equal (t , 1 , marshalWarns .Len ())
7276+ assert .Len (t , result , 1 )
7277+ })
7278+ }
0 commit comments