@@ -228,6 +228,97 @@ func TestProcess_Traces(t *testing.T) {
228228 require .Equal (t , "reportSnapshot" , mockOpamp .sentMessageType )
229229}
230230
231+ func TestProcess_Metrics_PreservesTemporalityWithFiltering (t * testing.T ) {
232+ factory := NewFactory ()
233+ sink := & consumertest.MetricsSink {}
234+
235+ pSet := processortest .NewNopSettings (componentType )
236+ p , err := factory .CreateMetrics (context .Background (), pSet , factory .CreateDefaultConfig (), sink )
237+ require .NoError (t , err )
238+
239+ mockOpamp := & mockOpAMPExtension {
240+ msgChan : make (chan * protobufs.CustomMessage , 1 ),
241+ }
242+
243+ mockHost := & mockHost {
244+ extensions : map [component.ID ]component.Component {
245+ component .MustNewID ("opamp" ): mockOpamp ,
246+ },
247+ }
248+
249+ require .NoError (t , p .Start (context .Background (), mockHost ))
250+ t .Cleanup (func () {
251+ require .NoError (t , p .Shutdown (context .Background ()))
252+ })
253+
254+ // Load test metrics with different aggregation temporalities
255+ m , err := golden .ReadMetrics (filepath .Join ("testdata" , "metrics" , "temporality-metrics.yaml" ))
256+ require .NoError (t , err )
257+
258+ require .NoError (t , p .ConsumeMetrics (context .Background (), m ))
259+
260+ // Request buffer with search query (this triggers the filtering code path where the bug occurred)
261+ reqPayload := fmt .Sprintf (`{"processor":%q,"pipeline_type":"metrics","session_id":"filtering-test","search_query":"transmit"}` , pSet .ID )
262+
263+ cm := & protobufs.CustomMessage {
264+ Capability : "com.bindplane.snapshot" ,
265+ Type : "requestSnapshot" ,
266+ Data : []byte (reqPayload ),
267+ }
268+
269+ mockOpamp .msgChan <- cm
270+
271+ // Wait for response
272+ require .Eventually (t , func () bool {
273+ return mockOpamp .GotMessage ()
274+ }, 5 * time .Second , 100 * time .Millisecond )
275+
276+ // Parse the actual response
277+ var actualMessageContents map [string ]any
278+ err = json .Unmarshal (gunzipBytes (t , mockOpamp .sentMessage ), & actualMessageContents )
279+ require .NoError (t , err )
280+
281+ // Verify filtering worked and only "transmit" metric is present
282+ telemetryPayload := actualMessageContents ["telemetry_payload" ].(map [string ]any )
283+ resourceMetrics := telemetryPayload ["resourceMetrics" ].([]any )
284+ require .Len (t , resourceMetrics , 1 , "Should have one resource metric after filtering" )
285+
286+ firstResource := resourceMetrics [0 ].(map [string ]any )
287+ scopeMetrics := firstResource ["scopeMetrics" ].([]any )
288+ require .Len (t , scopeMetrics , 1 , "Should have one scope metric" )
289+
290+ firstScope := scopeMetrics [0 ].(map [string ]any )
291+ metrics := firstScope ["metrics" ].([]any )
292+ require .Len (t , metrics , 1 , "Should have one metric matching 'transmit' filter" )
293+
294+ // Verify the filtered metric is the correct one and has preserved aggregation temporality
295+ filteredMetric := metrics [0 ].(map [string ]any )
296+ require .Equal (t , "system.network.io" , filteredMetric ["name" ])
297+
298+ sum := filteredMetric ["sum" ].(map [string ]any )
299+ require .Equal (t , float64 (2 ), sum ["aggregationTemporality" ], "Aggregation temporality should be preserved as Cumulative (2) even after filtering" )
300+ require .Equal (t , true , sum ["isMonotonic" ], "IsMonotonic should be preserved after filtering" )
301+
302+ // Verify the data point attributes contain "transmit"
303+ dataPoints := sum ["dataPoints" ].([]any )
304+ require .Len (t , dataPoints , 1 , "Should have one data point" )
305+
306+ dataPoint := dataPoints [0 ].(map [string ]any )
307+ attributes := dataPoint ["attributes" ].([]any )
308+ foundTransmit := false
309+ for _ , attrAny := range attributes {
310+ attr := attrAny .(map [string ]any )
311+ if attr ["key" ] == "direction" {
312+ value := attr ["value" ].(map [string ]any )
313+ if value ["stringValue" ] == "transmit" {
314+ foundTransmit = true
315+ break
316+ }
317+ }
318+ }
319+ require .True (t , foundTransmit , "Filtered metric should contain 'transmit' attribute" )
320+ }
321+
231322// mockHost for component.Host
232323type mockHost struct {
233324 extensions map [component.ID ]component.Component
0 commit comments