github.com/livekit/protocol@v1.39.3/utils/metrics_batch_builder_test.go (about)

     1  // Copyright 2023 LiveKit, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package utils
    16  
    17  import (
    18  	"testing"
    19  	"time"
    20  
    21  	"github.com/stretchr/testify/require"
    22  	"google.golang.org/protobuf/proto"
    23  	"google.golang.org/protobuf/types/known/timestamppb"
    24  
    25  	"github.com/livekit/protocol/livekit"
    26  	"github.com/livekit/protocol/utils/mono"
    27  )
    28  
    29  func TestMetricsBatchBuilder(t *testing.T) {
    30  	t.Run("basic", func(t *testing.T) {
    31  		at := mono.Now()
    32  		normalizedAt := mono.Now().Add(10 * time.Millisecond)
    33  		expected := &livekit.MetricsBatch{
    34  			TimestampMs:         at.UnixMilli(),
    35  			NormalizedTimestamp: timestamppb.New(normalizedAt),
    36  		}
    37  
    38  		mbb := NewMetricsBatchBuilder()
    39  		require.True(t, mbb.IsEmpty())
    40  		mbb.SetTime(
    41  			time.Unix(0, expected.TimestampMs*int64(time.Millisecond)),
    42  			expected.NormalizedTimestamp.AsTime(),
    43  		)
    44  		mb := mbb.ToProto()
    45  		require.True(t, proto.Equal(expected, mb))
    46  	})
    47  
    48  	t.Run("time series metric", func(t *testing.T) {
    49  		at := mono.Now()
    50  		normalizedAt := mono.Now().Add(10 * time.Millisecond)
    51  
    52  		expected := &livekit.MetricsBatch{
    53  			TimestampMs:         at.UnixMilli(),
    54  			NormalizedTimestamp: timestamppb.New(normalizedAt),
    55  			StrData: []string{
    56  				"PA_1",
    57  				"TR_VC1",
    58  				"f",
    59  				"CustomMetric",
    60  				"TR_VC2",
    61  				"q",
    62  				"PA_2",
    63  			},
    64  			TimeSeries: []*livekit.TimeSeriesMetric{
    65  				{
    66  					Label:               uint32(livekit.MetricLabel_PUBLISHER_RTT),
    67  					ParticipantIdentity: uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE),
    68  					TrackSid:            uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 1,
    69  					Samples: []*livekit.MetricSample{
    70  						{
    71  							TimestampMs:         at.UnixMilli(),
    72  							NormalizedTimestamp: timestamppb.New(normalizedAt),
    73  							Value:               42.4,
    74  						},
    75  						{
    76  							TimestampMs:         at.UnixMilli(),
    77  							NormalizedTimestamp: timestamppb.New(normalizedAt),
    78  							Value:               52.4,
    79  						},
    80  						{
    81  							TimestampMs:         at.UnixMilli(),
    82  							NormalizedTimestamp: timestamppb.New(normalizedAt),
    83  							Value:               62.4,
    84  						},
    85  					},
    86  					Rid: uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 2,
    87  				},
    88  				{
    89  					Label:               uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 3,
    90  					ParticipantIdentity: uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE),
    91  					TrackSid:            uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 4,
    92  					Samples: []*livekit.MetricSample{
    93  						{
    94  							TimestampMs:         at.UnixMilli(),
    95  							NormalizedTimestamp: timestamppb.New(normalizedAt),
    96  							Value:               72.4,
    97  						},
    98  						{
    99  							TimestampMs:         at.UnixMilli(),
   100  							NormalizedTimestamp: timestamppb.New(normalizedAt),
   101  							Value:               82.4,
   102  						},
   103  						{
   104  							TimestampMs:         at.UnixMilli(),
   105  							NormalizedTimestamp: timestamppb.New(normalizedAt),
   106  							Value:               92.4,
   107  						},
   108  					},
   109  					Rid: uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 5,
   110  				},
   111  				{
   112  					Label:               uint32(livekit.MetricLabel_SUBSCRIBER_RTT),
   113  					ParticipantIdentity: uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 6,
   114  					Samples: []*livekit.MetricSample{
   115  						{
   116  							TimestampMs:         at.UnixMilli(),
   117  							NormalizedTimestamp: timestamppb.New(normalizedAt),
   118  							Value:               102.4,
   119  						},
   120  					},
   121  				},
   122  				{
   123  					Label:               uint32(livekit.MetricLabel_CLIENT_VIDEO_SUBSCRIBER_FREEZE_COUNT),
   124  					ParticipantIdentity: uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE),
   125  					Samples: []*livekit.MetricSample{
   126  						{
   127  							TimestampMs:         at.UnixMilli(),
   128  							NormalizedTimestamp: timestamppb.New(normalizedAt),
   129  							Value:               102.4,
   130  						},
   131  					},
   132  				},
   133  			},
   134  		}
   135  
   136  		mbb := NewMetricsBatchBuilder()
   137  		mbb.SetTime(at, normalizedAt)
   138  		mbb.SetRestrictedLabels(MetricRestrictedLabels{
   139  			LabelRanges: []MetricLabelRange{
   140  				{
   141  					StartInclusive: livekit.MetricLabel_CLIENT_VIDEO_SUBSCRIBER_FREEZE_COUNT,
   142  					EndInclusive:   livekit.MetricLabel_CLIENT_VIDEO_PUBLISHER_QUALITY_LIMITATION_DURATION_OTHER,
   143  				},
   144  			},
   145  			ParticipantIdentity: "PA_1",
   146  		})
   147  
   148  		// should not be able to add invalid metric label index
   149  		_, err := mbb.AddTimeSeriesMetric(TimeSeriesMetric{
   150  			MetricLabel: livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE,
   151  		})
   152  		require.ErrorIs(t, err, ErrInvalidMetricLabel)
   153  
   154  		// add a time series metric
   155  		ts1Idx, err := mbb.AddTimeSeriesMetric(TimeSeriesMetric{
   156  			MetricLabel:         livekit.MetricLabel_PUBLISHER_RTT,
   157  			ParticipantIdentity: "PA_1",
   158  			TrackID:             "TR_VC1",
   159  			Samples: []MetricSample{
   160  				{
   161  					At:           at,
   162  					NormalizedAt: normalizedAt,
   163  					Value:        42.4,
   164  				},
   165  			},
   166  			Rid: "f",
   167  		})
   168  		require.NoError(t, err)
   169  		require.False(t, mbb.IsEmpty())
   170  
   171  		// should not be able to add sample to invalid index
   172  		err = mbb.AddMetricSamplesToTimeSeriesMetric(-1, nil)
   173  		require.ErrorIs(t, err, ErrInvalidTimeSeriesMetricIndex)
   174  		err = mbb.AddMetricSamplesToTimeSeriesMetric(ts1Idx+1, nil)
   175  		require.ErrorIs(t, err, ErrInvalidTimeSeriesMetricIndex)
   176  
   177  		// add a second one
   178  		ts2Idx, err := mbb.AddTimeSeriesMetric(TimeSeriesMetric{
   179  			CustomMetricLabel:   "CustomMetric",
   180  			ParticipantIdentity: "PA_1",
   181  			TrackID:             "TR_VC2",
   182  			Samples: []MetricSample{
   183  				{
   184  					At:           at,
   185  					NormalizedAt: normalizedAt,
   186  					Value:        72.4,
   187  				},
   188  			},
   189  			Rid: "q",
   190  		})
   191  		require.NoError(t, err)
   192  
   193  		// add extra samples to first metric to ensure it gets added to the right metric
   194  		err = mbb.AddMetricSamplesToTimeSeriesMetric(ts1Idx, []MetricSample{
   195  			{
   196  				At:           at,
   197  				NormalizedAt: normalizedAt,
   198  				Value:        52.4,
   199  			},
   200  			{
   201  				At:           at,
   202  				NormalizedAt: normalizedAt,
   203  				Value:        62.4,
   204  			},
   205  		})
   206  		require.NoError(t, err)
   207  
   208  		// add extra samples to second metric to ensure it gets added to the right metric
   209  		err = mbb.AddMetricSamplesToTimeSeriesMetric(ts2Idx, []MetricSample{
   210  			{
   211  				At:           at,
   212  				NormalizedAt: normalizedAt,
   213  				Value:        82.4,
   214  			},
   215  			{
   216  				At:           at,
   217  				NormalizedAt: normalizedAt,
   218  				Value:        92.4,
   219  			},
   220  		})
   221  		require.NoError(t, err)
   222  
   223  		// add a third metric with some fields not populated to ensure that those indices default to 0
   224  		_, err = mbb.AddTimeSeriesMetric(TimeSeriesMetric{
   225  			MetricLabel:         livekit.MetricLabel_SUBSCRIBER_RTT,
   226  			ParticipantIdentity: "PA_2",
   227  			Samples: []MetricSample{
   228  				{
   229  					At:           at,
   230  					NormalizedAt: normalizedAt,
   231  					Value:        102.4,
   232  				},
   233  			},
   234  		})
   235  		require.NoError(t, err)
   236  
   237  		// should accept restricted labels from that participant
   238  		_, err = mbb.AddTimeSeriesMetric(TimeSeriesMetric{
   239  			MetricLabel:         livekit.MetricLabel_CLIENT_VIDEO_SUBSCRIBER_FREEZE_COUNT,
   240  			ParticipantIdentity: "PA_1",
   241  			Samples: []MetricSample{
   242  				{
   243  					At:           at,
   244  					NormalizedAt: normalizedAt,
   245  					Value:        102.4,
   246  				},
   247  			},
   248  		})
   249  		require.NoError(t, err)
   250  
   251  		// should not accept restricted labels from any other participant
   252  		_, err = mbb.AddTimeSeriesMetric(TimeSeriesMetric{
   253  			MetricLabel:         livekit.MetricLabel_CLIENT_VIDEO_PUBLISHER_QUALITY_LIMITATION_DURATION_OTHER,
   254  			ParticipantIdentity: "PA_2",
   255  			Samples: []MetricSample{
   256  				{
   257  					At:           at,
   258  					NormalizedAt: normalizedAt,
   259  					Value:        102.4,
   260  				},
   261  			},
   262  		})
   263  		require.ErrorIs(t, err, ErrFilteredMetricLabel)
   264  
   265  		mb := mbb.ToProto()
   266  		require.True(t, proto.Equal(expected, mb))
   267  	})
   268  
   269  	t.Run("event metric", func(t *testing.T) {
   270  		at := mono.Now()
   271  		atMilli := at.UnixMilli()
   272  		normalizedAt := mono.Now().Add(10 * time.Millisecond)
   273  
   274  		expected := &livekit.MetricsBatch{
   275  			TimestampMs:         at.UnixMilli(),
   276  			NormalizedTimestamp: timestamppb.New(normalizedAt),
   277  			StrData: []string{
   278  				"PA_1",
   279  				"TR_VC1",
   280  				"f",
   281  				"CustomMetric",
   282  				"TR_VC2",
   283  				"PA_2",
   284  			},
   285  			Events: []*livekit.EventMetric{
   286  				{
   287  					Label:                    uint32(livekit.MetricLabel_PUBLISHER_RTT),
   288  					ParticipantIdentity:      uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE),
   289  					TrackSid:                 uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 1,
   290  					StartTimestampMs:         at.UnixMilli(),
   291  					EndTimestampMs:           &atMilli,
   292  					NormalizedStartTimestamp: timestamppb.New(normalizedAt),
   293  					NormalizedEndTimestamp:   timestamppb.New(normalizedAt),
   294  					Metadata:                 "md1",
   295  					Rid:                      uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 2,
   296  				},
   297  				{
   298  					Label:                    uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 3,
   299  					ParticipantIdentity:      uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE),
   300  					TrackSid:                 uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 4,
   301  					StartTimestampMs:         at.UnixMilli(),
   302  					NormalizedStartTimestamp: timestamppb.New(normalizedAt),
   303  					Metadata:                 "md2",
   304  				},
   305  				{
   306  					Label:                    uint32(livekit.MetricLabel_CLIENT_VIDEO_PUBLISHER_QUALITY_LIMITATION_DURATION_OTHER),
   307  					ParticipantIdentity:      uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE),
   308  					TrackSid:                 uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 1,
   309  					StartTimestampMs:         at.UnixMilli(),
   310  					EndTimestampMs:           &atMilli,
   311  					NormalizedStartTimestamp: timestamppb.New(normalizedAt),
   312  					NormalizedEndTimestamp:   timestamppb.New(normalizedAt),
   313  					Metadata:                 "md1",
   314  					Rid:                      uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 2,
   315  				},
   316  			},
   317  			TimeSeries: []*livekit.TimeSeriesMetric{
   318  				{
   319  					Label:               uint32(livekit.MetricLabel_SUBSCRIBER_RTT),
   320  					ParticipantIdentity: uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 5,
   321  					Samples: []*livekit.MetricSample{
   322  						{
   323  							TimestampMs:         at.UnixMilli(),
   324  							NormalizedTimestamp: timestamppb.New(normalizedAt),
   325  							Value:               102.4,
   326  						},
   327  					},
   328  				},
   329  			},
   330  		}
   331  
   332  		mbb := NewMetricsBatchBuilder()
   333  		mbb.SetTime(at, normalizedAt)
   334  		mbb.SetRestrictedLabels(MetricRestrictedLabels{
   335  			LabelRanges: []MetricLabelRange{
   336  				{
   337  					StartInclusive: livekit.MetricLabel_CLIENT_VIDEO_SUBSCRIBER_FREEZE_COUNT,
   338  					EndInclusive:   livekit.MetricLabel_CLIENT_VIDEO_PUBLISHER_QUALITY_LIMITATION_DURATION_OTHER,
   339  				},
   340  			},
   341  			ParticipantIdentity: "PA_1",
   342  		})
   343  
   344  		// should not be able to add invalid metric label index
   345  		err := mbb.AddEventMetric(EventMetric{
   346  			MetricLabel: livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE,
   347  		})
   348  		require.ErrorIs(t, err, ErrInvalidMetricLabel)
   349  
   350  		// add an event metric
   351  		err = mbb.AddEventMetric(EventMetric{
   352  			MetricLabel:         livekit.MetricLabel_PUBLISHER_RTT,
   353  			ParticipantIdentity: "PA_1",
   354  			TrackID:             "TR_VC1",
   355  			StartedAt:           at,
   356  			EndedAt:             at,
   357  			NormalizedStartedAt: normalizedAt,
   358  			NormalizedEndedAt:   normalizedAt,
   359  			Metadata:            "md1",
   360  			Rid:                 "f",
   361  		})
   362  		require.NoError(t, err)
   363  
   364  		// add a second one with some optional fields not included
   365  		err = mbb.AddEventMetric(EventMetric{
   366  			CustomMetricLabel:   "CustomMetric",
   367  			ParticipantIdentity: "PA_1",
   368  			TrackID:             "TR_VC2",
   369  			StartedAt:           at,
   370  			NormalizedStartedAt: normalizedAt,
   371  			Metadata:            "md2",
   372  		})
   373  
   374  		// should accept restricted label from PA_1
   375  		err = mbb.AddEventMetric(EventMetric{
   376  			MetricLabel:         livekit.MetricLabel_CLIENT_VIDEO_PUBLISHER_QUALITY_LIMITATION_DURATION_OTHER,
   377  			ParticipantIdentity: "PA_1",
   378  			TrackID:             "TR_VC1",
   379  			StartedAt:           at,
   380  			EndedAt:             at,
   381  			NormalizedStartedAt: normalizedAt,
   382  			NormalizedEndedAt:   normalizedAt,
   383  			Metadata:            "md1",
   384  			Rid:                 "f",
   385  		})
   386  		require.NoError(t, err)
   387  
   388  		// should not accept restricted label from !PA_1
   389  		err = mbb.AddEventMetric(EventMetric{
   390  			MetricLabel:         livekit.MetricLabel_CLIENT_VIDEO_PUBLISHER_QUALITY_LIMITATION_DURATION_OTHER,
   391  			ParticipantIdentity: "PA_2",
   392  			TrackID:             "TR_VC1",
   393  			StartedAt:           at,
   394  			EndedAt:             at,
   395  			NormalizedStartedAt: normalizedAt,
   396  			NormalizedEndedAt:   normalizedAt,
   397  			Metadata:            "md1",
   398  			Rid:                 "f",
   399  		})
   400  		require.ErrorIs(t, err, ErrFilteredMetricLabel)
   401  
   402  		// add a time series metric to ensure both time series metric and event metric can be in same batch
   403  		_, err = mbb.AddTimeSeriesMetric(TimeSeriesMetric{
   404  			MetricLabel:         livekit.MetricLabel_SUBSCRIBER_RTT,
   405  			ParticipantIdentity: "PA_2",
   406  			Samples: []MetricSample{
   407  				{
   408  					At:           at,
   409  					NormalizedAt: normalizedAt,
   410  					Value:        102.4,
   411  				},
   412  			},
   413  		})
   414  		require.NoError(t, err)
   415  
   416  		mb := mbb.ToProto()
   417  		require.True(t, proto.Equal(expected, mb))
   418  	})
   419  
   420  	t.Run("merge", func(t *testing.T) {
   421  		at := mono.Now()
   422  		atMilli := at.UnixMilli()
   423  		normalizedAt := mono.Now().Add(10 * time.Millisecond)
   424  
   425  		expected := &livekit.MetricsBatch{
   426  			TimestampMs:         at.UnixMilli(),
   427  			NormalizedTimestamp: timestamppb.New(normalizedAt),
   428  			StrData: []string{
   429  				"PA_1",
   430  				"TR_VC1",
   431  				"f",
   432  				"CustomMetric",
   433  				"TR_VC2",
   434  				"q",
   435  				"PA_2",
   436  			},
   437  			Events: []*livekit.EventMetric{
   438  				{
   439  					Label:                    uint32(livekit.MetricLabel_PUBLISHER_RTT),
   440  					ParticipantIdentity:      uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE),
   441  					TrackSid:                 uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 1,
   442  					StartTimestampMs:         at.UnixMilli(),
   443  					EndTimestampMs:           &atMilli,
   444  					NormalizedStartTimestamp: timestamppb.New(normalizedAt),
   445  					NormalizedEndTimestamp:   timestamppb.New(normalizedAt),
   446  					Metadata:                 "md1",
   447  					Rid:                      uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 2,
   448  				},
   449  				{
   450  					Label:                    uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 3,
   451  					ParticipantIdentity:      uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE),
   452  					TrackSid:                 uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 4,
   453  					StartTimestampMs:         at.UnixMilli(),
   454  					NormalizedStartTimestamp: timestamppb.New(normalizedAt),
   455  					Metadata:                 "md2",
   456  					Rid:                      uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 5,
   457  				},
   458  				{
   459  					Label:                    uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 3,
   460  					ParticipantIdentity:      uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE),
   461  					TrackSid:                 uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 4,
   462  					StartTimestampMs:         at.UnixMilli(),
   463  					NormalizedStartTimestamp: timestamppb.New(normalizedAt),
   464  					Metadata:                 "md2",
   465  					Rid:                      uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 5,
   466  				},
   467  				{
   468  					Label:                    uint32(livekit.MetricLabel_CLIENT_VIDEO_PUBLISHER_QUALITY_LIMITATION_DURATION_BANDWIDTH),
   469  					ParticipantIdentity:      uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE),
   470  					TrackSid:                 uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 4,
   471  					StartTimestampMs:         at.UnixMilli(),
   472  					NormalizedStartTimestamp: timestamppb.New(normalizedAt),
   473  					Metadata:                 "md2",
   474  					Rid:                      uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 5,
   475  				},
   476  			},
   477  			TimeSeries: []*livekit.TimeSeriesMetric{
   478  				{
   479  					Label:               uint32(livekit.MetricLabel_SUBSCRIBER_RTT),
   480  					ParticipantIdentity: uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 6,
   481  					Samples: []*livekit.MetricSample{
   482  						{
   483  							TimestampMs:         at.UnixMilli(),
   484  							NormalizedTimestamp: timestamppb.New(normalizedAt),
   485  							Value:               102.4,
   486  						},
   487  					},
   488  				},
   489  			},
   490  		}
   491  
   492  		mbb := NewMetricsBatchBuilder()
   493  		mbb.SetTime(at, normalizedAt)
   494  		mbb.SetRestrictedLabels(MetricRestrictedLabels{
   495  			LabelRanges: []MetricLabelRange{
   496  				{
   497  					StartInclusive: livekit.MetricLabel_CLIENT_VIDEO_SUBSCRIBER_FREEZE_COUNT,
   498  					EndInclusive:   livekit.MetricLabel_CLIENT_VIDEO_PUBLISHER_QUALITY_LIMITATION_DURATION_OTHER,
   499  				},
   500  			},
   501  			ParticipantIdentity: "PA_1",
   502  		})
   503  
   504  		// should not be able to add invalid metric label index
   505  		err := mbb.AddEventMetric(EventMetric{
   506  			MetricLabel: livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE,
   507  		})
   508  		require.ErrorIs(t, err, ErrInvalidMetricLabel)
   509  
   510  		// add an event metric
   511  		err = mbb.AddEventMetric(EventMetric{
   512  			MetricLabel:         livekit.MetricLabel_PUBLISHER_RTT,
   513  			ParticipantIdentity: "PA_1",
   514  			TrackID:             "TR_VC1",
   515  			StartedAt:           at,
   516  			EndedAt:             at,
   517  			NormalizedStartedAt: normalizedAt,
   518  			NormalizedEndedAt:   normalizedAt,
   519  			Metadata:            "md1",
   520  			Rid:                 "f",
   521  		})
   522  		require.NoError(t, err)
   523  
   524  		// add a second one with some optional fields not included
   525  		// including this here and in the one to merge to test index translation
   526  		err = mbb.AddEventMetric(EventMetric{
   527  			CustomMetricLabel:   "CustomMetric",
   528  			ParticipantIdentity: "PA_1",
   529  			TrackID:             "TR_VC2",
   530  			StartedAt:           at,
   531  			NormalizedStartedAt: normalizedAt,
   532  			Metadata:            "md2",
   533  			Rid:                 "q",
   534  		})
   535  		require.NoError(t, err)
   536  
   537  		toMerge := &livekit.MetricsBatch{
   538  			TimestampMs:         at.UnixMilli(),
   539  			NormalizedTimestamp: timestamppb.New(normalizedAt),
   540  			StrData: []string{
   541  				"CustomMetric",
   542  				"PA_1",
   543  				"TR_VC2",
   544  				"q",
   545  				"PA_2",
   546  			},
   547  			Events: []*livekit.EventMetric{
   548  				{
   549  					Label:                    uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE),
   550  					ParticipantIdentity:      uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 1,
   551  					TrackSid:                 uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 2,
   552  					StartTimestampMs:         at.UnixMilli(),
   553  					NormalizedStartTimestamp: timestamppb.New(normalizedAt),
   554  					Metadata:                 "md2",
   555  					Rid:                      uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 3,
   556  				},
   557  				{
   558  					Label:                    uint32(livekit.MetricLabel_CLIENT_VIDEO_PUBLISHER_QUALITY_LIMITATION_DURATION_BANDWIDTH),
   559  					ParticipantIdentity:      uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 1,
   560  					TrackSid:                 uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 2,
   561  					StartTimestampMs:         at.UnixMilli(),
   562  					NormalizedStartTimestamp: timestamppb.New(normalizedAt),
   563  					Metadata:                 "md2",
   564  					Rid:                      uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 3,
   565  				},
   566  			},
   567  			TimeSeries: []*livekit.TimeSeriesMetric{
   568  				{
   569  					Label:               uint32(livekit.MetricLabel_SUBSCRIBER_RTT),
   570  					ParticipantIdentity: uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 4,
   571  					Samples: []*livekit.MetricSample{
   572  						{
   573  							TimestampMs:         at.UnixMilli(),
   574  							NormalizedTimestamp: timestamppb.New(normalizedAt),
   575  							Value:               102.4,
   576  						},
   577  					},
   578  				},
   579  				{
   580  					// should be filtered
   581  					Label:               uint32(livekit.MetricLabel_CLIENT_VIDEO_PUBLISHER_QUALITY_LIMITATION_DURATION_CPU),
   582  					ParticipantIdentity: uint32(livekit.MetricLabel_METRIC_LABEL_PREDEFINED_MAX_VALUE) + 4,
   583  					Samples: []*livekit.MetricSample{
   584  						{
   585  							TimestampMs:         at.UnixMilli(),
   586  							NormalizedTimestamp: timestamppb.New(normalizedAt),
   587  							Value:               102.4,
   588  						},
   589  					},
   590  				},
   591  			},
   592  		}
   593  		mbb.Merge(toMerge)
   594  
   595  		mb := mbb.ToProto()
   596  		require.True(t, proto.Equal(expected, mb))
   597  	})
   598  }