github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/metrics/metadata/metadata_test.go (about)

     1  // Copyright (c) 2018 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package metadata
    22  
    23  import (
    24  	"encoding/json"
    25  	"fmt"
    26  	"testing"
    27  	"time"
    28  
    29  	"github.com/m3db/m3/src/metrics/aggregation"
    30  	"github.com/m3db/m3/src/metrics/generated/proto/aggregationpb"
    31  	"github.com/m3db/m3/src/metrics/generated/proto/metricpb"
    32  	"github.com/m3db/m3/src/metrics/generated/proto/pipelinepb"
    33  	"github.com/m3db/m3/src/metrics/generated/proto/policypb"
    34  	"github.com/m3db/m3/src/metrics/generated/proto/transformationpb"
    35  	"github.com/m3db/m3/src/metrics/pipeline"
    36  	"github.com/m3db/m3/src/metrics/pipeline/applied"
    37  	"github.com/m3db/m3/src/metrics/policy"
    38  	"github.com/m3db/m3/src/metrics/transformation"
    39  	xtime "github.com/m3db/m3/src/x/time"
    40  
    41  	"github.com/stretchr/testify/require"
    42  )
    43  
    44  var (
    45  	testSmallForwardMetadata = ForwardMetadata{
    46  		AggregationID: aggregation.DefaultID,
    47  		StoragePolicy: policy.NewStoragePolicy(time.Minute, xtime.Minute, 12*time.Hour),
    48  		Pipeline: applied.NewPipeline([]applied.OpUnion{
    49  			{
    50  				Type: pipeline.RollupOpType,
    51  				Rollup: applied.RollupOp{
    52  					ID:            []byte("foo"),
    53  					AggregationID: aggregation.MustCompressTypes(aggregation.Count),
    54  				},
    55  			},
    56  		}),
    57  		SourceID:          1234,
    58  		NumForwardedTimes: 3,
    59  	}
    60  	testLargeForwardMetadata = ForwardMetadata{
    61  		AggregationID: aggregation.MustCompressTypes(aggregation.Sum),
    62  		StoragePolicy: policy.NewStoragePolicy(10*time.Second, xtime.Second, 6*time.Hour),
    63  		Pipeline: applied.NewPipeline([]applied.OpUnion{
    64  			{
    65  				Type: pipeline.TransformationOpType,
    66  				Transformation: pipeline.TransformationOp{
    67  					Type: transformation.Absolute,
    68  				},
    69  			},
    70  			{
    71  				Type: pipeline.RollupOpType,
    72  				Rollup: applied.RollupOp{
    73  					ID:            []byte("bar"),
    74  					AggregationID: aggregation.MustCompressTypes(aggregation.Last, aggregation.Sum),
    75  				},
    76  			},
    77  		}),
    78  		SourceID:          897,
    79  		NumForwardedTimes: 2,
    80  	}
    81  	testSmallPipelineMetadata = PipelineMetadata{
    82  		AggregationID: aggregation.DefaultID,
    83  		StoragePolicies: []policy.StoragePolicy{
    84  			policy.NewStoragePolicy(time.Minute, xtime.Minute, 6*time.Hour),
    85  		},
    86  		Pipeline: applied.NewPipeline([]applied.OpUnion{
    87  			{
    88  				Type: pipeline.TransformationOpType,
    89  				Transformation: pipeline.TransformationOp{
    90  					Type: transformation.PerSecond,
    91  				},
    92  			},
    93  		}),
    94  	}
    95  	testLargePipelineMetadata = PipelineMetadata{
    96  		AggregationID: aggregation.DefaultID,
    97  		StoragePolicies: []policy.StoragePolicy{
    98  			policy.NewStoragePolicy(time.Minute, xtime.Minute, 12*time.Hour),
    99  			policy.NewStoragePolicy(time.Hour, xtime.Hour, 30*24*time.Hour),
   100  		},
   101  		Pipeline: applied.NewPipeline([]applied.OpUnion{
   102  			{
   103  				Type: pipeline.TransformationOpType,
   104  				Transformation: pipeline.TransformationOp{
   105  					Type: transformation.Absolute,
   106  				},
   107  			},
   108  			{
   109  				Type: pipeline.RollupOpType,
   110  				Rollup: applied.RollupOp{
   111  					ID:            []byte("foo"),
   112  					AggregationID: aggregation.MustCompressTypes(aggregation.Last, aggregation.Sum),
   113  				},
   114  			},
   115  		}),
   116  	}
   117  	testBadForwardMetadata = ForwardMetadata{
   118  		StoragePolicy: policy.NewStoragePolicy(10*time.Second, xtime.Unit(101), 6*time.Hour),
   119  	}
   120  	testBadPipelineMetadata = PipelineMetadata{
   121  		AggregationID: aggregation.DefaultID,
   122  		StoragePolicies: []policy.StoragePolicy{
   123  			policy.NewStoragePolicy(time.Minute, xtime.Unit(100), 6*time.Hour),
   124  		},
   125  	}
   126  	testSmallStagedMetadatas = StagedMetadatas{
   127  		{
   128  			CutoverNanos: 4567,
   129  			Tombstoned:   true,
   130  			Metadata: Metadata{
   131  				Pipelines: []PipelineMetadata{
   132  					{
   133  						AggregationID: aggregation.MustCompressTypes(aggregation.Sum),
   134  						StoragePolicies: []policy.StoragePolicy{
   135  							policy.NewStoragePolicy(time.Second, xtime.Second, time.Hour),
   136  						},
   137  					},
   138  					{
   139  						AggregationID: aggregation.DefaultID,
   140  						StoragePolicies: []policy.StoragePolicy{
   141  							policy.NewStoragePolicy(10*time.Second, xtime.Second, time.Hour),
   142  						},
   143  						Pipeline: applied.NewPipeline([]applied.OpUnion{
   144  							{
   145  								Type: pipeline.RollupOpType,
   146  								Rollup: applied.RollupOp{
   147  									ID:            []byte("baz"),
   148  									AggregationID: aggregation.MustCompressTypes(aggregation.Mean),
   149  								},
   150  							},
   151  						}),
   152  					},
   153  				},
   154  			},
   155  		},
   156  	}
   157  	testLargeStagedMetadatas = StagedMetadatas{
   158  		{
   159  			CutoverNanos: 1234,
   160  			Tombstoned:   false,
   161  		},
   162  		{
   163  			CutoverNanos: 4567,
   164  			Tombstoned:   true,
   165  			Metadata: Metadata{
   166  				Pipelines: []PipelineMetadata{
   167  					{
   168  						AggregationID: aggregation.MustCompressTypes(aggregation.Count),
   169  						StoragePolicies: []policy.StoragePolicy{
   170  							policy.NewStoragePolicy(time.Second, xtime.Second, time.Hour),
   171  						},
   172  					},
   173  					{
   174  						AggregationID: aggregation.DefaultID,
   175  						StoragePolicies: []policy.StoragePolicy{
   176  							policy.NewStoragePolicy(time.Minute, xtime.Minute, 6*time.Hour),
   177  							policy.NewStoragePolicy(time.Hour, xtime.Hour, 30*24*time.Hour),
   178  						},
   179  						Pipeline: applied.NewPipeline([]applied.OpUnion{
   180  							{
   181  								Type: pipeline.TransformationOpType,
   182  								Transformation: pipeline.TransformationOp{
   183  									Type: transformation.Absolute,
   184  								},
   185  							},
   186  							{
   187  								Type: pipeline.RollupOpType,
   188  								Rollup: applied.RollupOp{
   189  									ID:            []byte("foo"),
   190  									AggregationID: aggregation.MustCompressTypes(aggregation.Last, aggregation.Sum),
   191  								},
   192  							},
   193  						}),
   194  					},
   195  				},
   196  			},
   197  		},
   198  		{
   199  			CutoverNanos: 32768,
   200  			Tombstoned:   false,
   201  			Metadata: Metadata{
   202  				Pipelines: []PipelineMetadata{
   203  					{
   204  						AggregationID: aggregation.DefaultID,
   205  						Pipeline: applied.NewPipeline([]applied.OpUnion{
   206  							{
   207  								Type: pipeline.TransformationOpType,
   208  								Transformation: pipeline.TransformationOp{
   209  									Type: transformation.PerSecond,
   210  								},
   211  							},
   212  							{
   213  								Type: pipeline.RollupOpType,
   214  								Rollup: applied.RollupOp{
   215  									ID:            []byte("bar"),
   216  									AggregationID: aggregation.MustCompressTypes(aggregation.P99),
   217  								},
   218  							},
   219  						}),
   220  					},
   221  				},
   222  			},
   223  		},
   224  	}
   225  	testBadStagedMetadatas = StagedMetadatas{
   226  		{
   227  			Metadata: Metadata{
   228  				Pipelines: []PipelineMetadata{
   229  					{
   230  						AggregationID: aggregation.DefaultID,
   231  						StoragePolicies: []policy.StoragePolicy{
   232  							policy.NewStoragePolicy(time.Minute, xtime.Unit(100), 6*time.Hour),
   233  						},
   234  					},
   235  				},
   236  			},
   237  		},
   238  	}
   239  	testSmallForwardMetadataProto = metricpb.ForwardMetadata{
   240  		AggregationId: aggregationpb.AggregationID{Id: 0},
   241  		StoragePolicy: policypb.StoragePolicy{
   242  			Resolution: policypb.Resolution{
   243  				WindowSize: time.Minute.Nanoseconds(),
   244  				Precision:  time.Minute.Nanoseconds(),
   245  			},
   246  			Retention: policypb.Retention{
   247  				Period: (12 * time.Hour).Nanoseconds(),
   248  			},
   249  		},
   250  		Pipeline: pipelinepb.AppliedPipeline{
   251  			Ops: []pipelinepb.AppliedPipelineOp{
   252  				{
   253  					Type: pipelinepb.AppliedPipelineOp_ROLLUP,
   254  					Rollup: pipelinepb.AppliedRollupOp{
   255  						Id:            []byte("foo"),
   256  						AggregationId: aggregationpb.AggregationID{Id: aggregation.MustCompressTypes(aggregation.Count)[0]},
   257  					},
   258  				},
   259  			},
   260  		},
   261  		SourceId:          1234,
   262  		NumForwardedTimes: 3,
   263  	}
   264  	testLargeForwardMetadataProto = metricpb.ForwardMetadata{
   265  		AggregationId: aggregationpb.AggregationID{Id: aggregation.MustCompressTypes(aggregation.Sum)[0]},
   266  		StoragePolicy: policypb.StoragePolicy{
   267  			Resolution: policypb.Resolution{
   268  				WindowSize: 10 * time.Second.Nanoseconds(),
   269  				Precision:  time.Second.Nanoseconds(),
   270  			},
   271  			Retention: policypb.Retention{
   272  				Period: (6 * time.Hour).Nanoseconds(),
   273  			},
   274  		},
   275  		Pipeline: pipelinepb.AppliedPipeline{
   276  			Ops: []pipelinepb.AppliedPipelineOp{
   277  				{
   278  					Type: pipelinepb.AppliedPipelineOp_TRANSFORMATION,
   279  					Transformation: pipelinepb.TransformationOp{
   280  						Type: transformationpb.TransformationType_ABSOLUTE,
   281  					},
   282  				},
   283  				{
   284  					Type: pipelinepb.AppliedPipelineOp_ROLLUP,
   285  					Rollup: pipelinepb.AppliedRollupOp{
   286  						Id:            []byte("bar"),
   287  						AggregationId: aggregationpb.AggregationID{Id: aggregation.MustCompressTypes(aggregation.Last, aggregation.Sum)[0]},
   288  					},
   289  				},
   290  			},
   291  		},
   292  		SourceId:          897,
   293  		NumForwardedTimes: 2,
   294  	}
   295  	testBadForwardMetadataProto    = metricpb.ForwardMetadata{}
   296  	testSmallPipelineMetadataProto = metricpb.PipelineMetadata{
   297  		AggregationId: aggregationpb.AggregationID{Id: 0},
   298  		StoragePolicies: []policypb.StoragePolicy{
   299  			{
   300  				Resolution: policypb.Resolution{
   301  					WindowSize: time.Minute.Nanoseconds(),
   302  					Precision:  time.Minute.Nanoseconds(),
   303  				},
   304  				Retention: policypb.Retention{
   305  					Period: (6 * time.Hour).Nanoseconds(),
   306  				},
   307  			},
   308  		},
   309  		Pipeline: pipelinepb.AppliedPipeline{
   310  			Ops: []pipelinepb.AppliedPipelineOp{
   311  				{
   312  					Type: pipelinepb.AppliedPipelineOp_TRANSFORMATION,
   313  					Transformation: pipelinepb.TransformationOp{
   314  						Type: transformationpb.TransformationType_PERSECOND,
   315  					},
   316  				},
   317  			},
   318  		},
   319  	}
   320  	testLargePipelineMetadataProto = metricpb.PipelineMetadata{
   321  		AggregationId: aggregationpb.AggregationID{Id: 0},
   322  		StoragePolicies: []policypb.StoragePolicy{
   323  			{
   324  				Resolution: policypb.Resolution{
   325  					WindowSize: time.Minute.Nanoseconds(),
   326  					Precision:  time.Minute.Nanoseconds(),
   327  				},
   328  				Retention: policypb.Retention{
   329  					Period: (12 * time.Hour).Nanoseconds(),
   330  				},
   331  			},
   332  			{
   333  				Resolution: policypb.Resolution{
   334  					WindowSize: time.Hour.Nanoseconds(),
   335  					Precision:  time.Hour.Nanoseconds(),
   336  				},
   337  				Retention: policypb.Retention{
   338  					Period: (30 * 24 * time.Hour).Nanoseconds(),
   339  				},
   340  			},
   341  		},
   342  		Pipeline: pipelinepb.AppliedPipeline{
   343  			Ops: []pipelinepb.AppliedPipelineOp{
   344  				{
   345  					Type: pipelinepb.AppliedPipelineOp_TRANSFORMATION,
   346  					Transformation: pipelinepb.TransformationOp{
   347  						Type: transformationpb.TransformationType_ABSOLUTE,
   348  					},
   349  				},
   350  				{
   351  					Type: pipelinepb.AppliedPipelineOp_ROLLUP,
   352  					Rollup: pipelinepb.AppliedRollupOp{
   353  						Id:            []byte("foo"),
   354  						AggregationId: aggregationpb.AggregationID{Id: aggregation.MustCompressTypes(aggregation.Last, aggregation.Sum)[0]},
   355  					},
   356  				},
   357  			},
   358  		},
   359  	}
   360  	testBadPipelineMetadataProto = metricpb.PipelineMetadata{
   361  		StoragePolicies: []policypb.StoragePolicy{
   362  			{},
   363  		},
   364  	}
   365  	testSmallStagedMetadatasProto = metricpb.StagedMetadatas{
   366  		Metadatas: []metricpb.StagedMetadata{
   367  			{
   368  				CutoverNanos: 4567,
   369  				Tombstoned:   true,
   370  				Metadata: metricpb.Metadata{
   371  					Pipelines: []metricpb.PipelineMetadata{
   372  						{
   373  							AggregationId: aggregationpb.AggregationID{Id: aggregation.MustCompressTypes(aggregation.Sum)[0]},
   374  							StoragePolicies: []policypb.StoragePolicy{
   375  								{
   376  									Resolution: policypb.Resolution{
   377  										WindowSize: time.Second.Nanoseconds(),
   378  										Precision:  time.Second.Nanoseconds(),
   379  									},
   380  									Retention: policypb.Retention{
   381  										Period: time.Hour.Nanoseconds(),
   382  									},
   383  								},
   384  							},
   385  						},
   386  						{
   387  							AggregationId: aggregationpb.AggregationID{Id: 0},
   388  							StoragePolicies: []policypb.StoragePolicy{
   389  								{
   390  									Resolution: policypb.Resolution{
   391  										WindowSize: 10 * time.Second.Nanoseconds(),
   392  										Precision:  time.Second.Nanoseconds(),
   393  									},
   394  									Retention: policypb.Retention{
   395  										Period: time.Hour.Nanoseconds(),
   396  									},
   397  								},
   398  							},
   399  							Pipeline: pipelinepb.AppliedPipeline{
   400  								Ops: []pipelinepb.AppliedPipelineOp{
   401  									{
   402  										Type: pipelinepb.AppliedPipelineOp_ROLLUP,
   403  										Rollup: pipelinepb.AppliedRollupOp{
   404  											Id:            []byte("baz"),
   405  											AggregationId: aggregationpb.AggregationID{Id: aggregation.MustCompressTypes(aggregation.Mean)[0]},
   406  										},
   407  									},
   408  								},
   409  							},
   410  						},
   411  					},
   412  				},
   413  			},
   414  		},
   415  	}
   416  	testSmallStagedMetadatasWithLargeStoragePoliciesProto = metricpb.StagedMetadatas{
   417  		Metadatas: []metricpb.StagedMetadata{
   418  			{
   419  				CutoverNanos: 4567,
   420  				Tombstoned:   true,
   421  				Metadata: metricpb.Metadata{
   422  					Pipelines: []metricpb.PipelineMetadata{
   423  						{
   424  							AggregationId: aggregationpb.AggregationID{Id: aggregation.MustCompressTypes(aggregation.Sum)[0]},
   425  							StoragePolicies: []policypb.StoragePolicy{
   426  								{
   427  									Resolution: policypb.Resolution{
   428  										WindowSize: time.Second.Nanoseconds(),
   429  										Precision:  time.Second.Nanoseconds(),
   430  									},
   431  									Retention: policypb.Retention{
   432  										Period: 10 * time.Second.Nanoseconds(),
   433  									},
   434  								},
   435  								{
   436  									Resolution: policypb.Resolution{
   437  										WindowSize: 10 * time.Second.Nanoseconds(),
   438  										Precision:  time.Second.Nanoseconds(),
   439  									},
   440  									Retention: policypb.Retention{
   441  										Period: time.Hour.Nanoseconds(),
   442  									},
   443  								},
   444  								{
   445  									Resolution: policypb.Resolution{
   446  										WindowSize: 10 * time.Minute.Nanoseconds(),
   447  										Precision:  time.Second.Nanoseconds(),
   448  									},
   449  									Retention: policypb.Retention{
   450  										Period: time.Minute.Nanoseconds(),
   451  									},
   452  								},
   453  								{
   454  									Resolution: policypb.Resolution{
   455  										WindowSize: 10 * time.Minute.Nanoseconds(),
   456  										Precision:  time.Second.Nanoseconds(),
   457  									},
   458  									Retention: policypb.Retention{
   459  										Period: time.Second.Nanoseconds(),
   460  									},
   461  								},
   462  								{
   463  									Resolution: policypb.Resolution{
   464  										WindowSize: 10 * time.Hour.Nanoseconds(),
   465  										Precision:  time.Second.Nanoseconds(),
   466  									},
   467  									Retention: policypb.Retention{
   468  										Period: time.Second.Nanoseconds(),
   469  									},
   470  								},
   471  							},
   472  						},
   473  					},
   474  				},
   475  			},
   476  		},
   477  	}
   478  	testLargeStagedMetadatasProto = metricpb.StagedMetadatas{
   479  		Metadatas: []metricpb.StagedMetadata{
   480  			{
   481  				CutoverNanos: 1234,
   482  				Tombstoned:   false,
   483  			},
   484  			{
   485  				CutoverNanos: 4567,
   486  				Tombstoned:   true,
   487  				Metadata: metricpb.Metadata{
   488  					Pipelines: []metricpb.PipelineMetadata{
   489  						{
   490  							AggregationId: aggregationpb.AggregationID{Id: aggregation.MustCompressTypes(aggregation.Count)[0]},
   491  							StoragePolicies: []policypb.StoragePolicy{
   492  								{
   493  									Resolution: policypb.Resolution{
   494  										WindowSize: time.Second.Nanoseconds(),
   495  										Precision:  time.Second.Nanoseconds(),
   496  									},
   497  									Retention: policypb.Retention{
   498  										Period: time.Hour.Nanoseconds(),
   499  									},
   500  								},
   501  							},
   502  						},
   503  						{
   504  							AggregationId: aggregationpb.AggregationID{Id: 0},
   505  							StoragePolicies: []policypb.StoragePolicy{
   506  								{
   507  									Resolution: policypb.Resolution{
   508  										WindowSize: time.Minute.Nanoseconds(),
   509  										Precision:  time.Minute.Nanoseconds(),
   510  									},
   511  									Retention: policypb.Retention{
   512  										Period: (6 * time.Hour).Nanoseconds(),
   513  									},
   514  								},
   515  								{
   516  									Resolution: policypb.Resolution{
   517  										WindowSize: time.Hour.Nanoseconds(),
   518  										Precision:  time.Hour.Nanoseconds(),
   519  									},
   520  									Retention: policypb.Retention{
   521  										Period: (30 * 24 * time.Hour).Nanoseconds(),
   522  									},
   523  								},
   524  							},
   525  							Pipeline: pipelinepb.AppliedPipeline{
   526  								Ops: []pipelinepb.AppliedPipelineOp{
   527  									{
   528  										Type: pipelinepb.AppliedPipelineOp_TRANSFORMATION,
   529  										Transformation: pipelinepb.TransformationOp{
   530  											Type: transformationpb.TransformationType_ABSOLUTE,
   531  										},
   532  									},
   533  									{
   534  										Type: pipelinepb.AppliedPipelineOp_ROLLUP,
   535  										Rollup: pipelinepb.AppliedRollupOp{
   536  											Id:            []byte("foo"),
   537  											AggregationId: aggregationpb.AggregationID{Id: aggregation.MustCompressTypes(aggregation.Last, aggregation.Sum)[0]},
   538  										},
   539  									},
   540  								},
   541  							},
   542  						},
   543  					},
   544  				},
   545  			},
   546  			{
   547  				CutoverNanos: 32768,
   548  				Tombstoned:   false,
   549  				Metadata: metricpb.Metadata{
   550  					Pipelines: []metricpb.PipelineMetadata{
   551  						{
   552  							AggregationId: aggregationpb.AggregationID{Id: 0},
   553  							Pipeline: pipelinepb.AppliedPipeline{
   554  								Ops: []pipelinepb.AppliedPipelineOp{
   555  									{
   556  										Type: pipelinepb.AppliedPipelineOp_TRANSFORMATION,
   557  										Transformation: pipelinepb.TransformationOp{
   558  											Type: transformationpb.TransformationType_PERSECOND,
   559  										},
   560  									},
   561  									{
   562  										Type: pipelinepb.AppliedPipelineOp_ROLLUP,
   563  										Rollup: pipelinepb.AppliedRollupOp{
   564  											Id:            []byte("bar"),
   565  											AggregationId: aggregationpb.AggregationID{Id: aggregation.MustCompressTypes(aggregation.P99)[0]},
   566  										},
   567  									},
   568  								},
   569  							},
   570  						},
   571  					},
   572  				},
   573  			},
   574  		},
   575  	}
   576  	testBadStagedMetadatasProto = metricpb.StagedMetadatas{
   577  		Metadatas: []metricpb.StagedMetadata{
   578  			{
   579  				Metadata: metricpb.Metadata{
   580  					Pipelines: []metricpb.PipelineMetadata{
   581  						{
   582  							StoragePolicies: []policypb.StoragePolicy{
   583  								{},
   584  							},
   585  						},
   586  					},
   587  				},
   588  			},
   589  		},
   590  	}
   591  	testDropMustDropPolicyPipelineMetadata = PipelineMetadata{
   592  		AggregationID:   aggregation.DefaultID,
   593  		StoragePolicies: []policy.StoragePolicy{},
   594  		Pipeline:        applied.DefaultPipeline,
   595  		DropPolicy:      policy.DropMust,
   596  	}
   597  	testDropExceptIfMatchOtherDropPolicyPipelineMetadata = PipelineMetadata{
   598  		AggregationID:   aggregation.DefaultID,
   599  		StoragePolicies: []policy.StoragePolicy{},
   600  		Pipeline:        applied.DefaultPipeline,
   601  		DropPolicy:      policy.DropMust,
   602  	}
   603  )
   604  
   605  func TestStagedMetadatasIsDefault(t *testing.T) {
   606  	inputs := []struct {
   607  		metadatas StagedMetadatas
   608  		expected  bool
   609  	}{
   610  		{
   611  			metadatas: StagedMetadatas{
   612  				{
   613  					Metadata: Metadata{
   614  						Pipelines: []PipelineMetadata{
   615  							{},
   616  						},
   617  					},
   618  				},
   619  			},
   620  			expected: true,
   621  		},
   622  		{
   623  			metadatas: DefaultStagedMetadatas,
   624  			expected:  true,
   625  		},
   626  		{
   627  			metadatas: StagedMetadatas{},
   628  			expected:  false,
   629  		},
   630  		{
   631  			metadatas: StagedMetadatas{
   632  				{
   633  					CutoverNanos: 1234,
   634  					Metadata: Metadata{
   635  						Pipelines: []PipelineMetadata{
   636  							{},
   637  						},
   638  					},
   639  				},
   640  			},
   641  			expected: false,
   642  		},
   643  		{
   644  			metadatas: StagedMetadatas{
   645  				{
   646  					Tombstoned: true,
   647  					Metadata: Metadata{
   648  						Pipelines: []PipelineMetadata{
   649  							{},
   650  						},
   651  					},
   652  				},
   653  			},
   654  			expected: false,
   655  		},
   656  		{
   657  			metadatas: StagedMetadatas{
   658  				{
   659  					Metadata: Metadata{
   660  						Pipelines: []PipelineMetadata{
   661  							{
   662  								AggregationID: aggregation.MustCompressTypes(aggregation.Sum),
   663  							},
   664  						},
   665  					},
   666  				},
   667  			},
   668  			expected: false,
   669  		},
   670  		{
   671  			metadatas: StagedMetadatas{
   672  				{
   673  					Metadata: Metadata{
   674  						Pipelines: []PipelineMetadata{
   675  							{
   676  								StoragePolicies: []policy.StoragePolicy{
   677  									policy.NewStoragePolicy(time.Second, xtime.Second, time.Hour),
   678  								},
   679  							},
   680  						},
   681  					},
   682  				},
   683  			},
   684  			expected: false,
   685  		},
   686  		{
   687  			metadatas: StagedMetadatas{
   688  				{
   689  					Metadata: Metadata{
   690  						Pipelines: []PipelineMetadata{
   691  							{
   692  								Pipeline: applied.NewPipeline([]applied.OpUnion{
   693  									{
   694  										Type:           pipeline.TransformationOpType,
   695  										Transformation: pipeline.TransformationOp{Type: transformation.Absolute},
   696  									},
   697  								}),
   698  							},
   699  						},
   700  					},
   701  				},
   702  			},
   703  			expected: false,
   704  		},
   705  		{
   706  			metadatas: StagedMetadatas{
   707  				{
   708  					Metadata: Metadata{
   709  						Pipelines: []PipelineMetadata{
   710  							{
   711  								Pipeline: applied.NewPipeline([]applied.OpUnion{
   712  									{
   713  										Type:   pipeline.RollupOpType,
   714  										Rollup: applied.RollupOp{ID: []byte("foo")},
   715  									},
   716  								}),
   717  							},
   718  						},
   719  					},
   720  				},
   721  			},
   722  			expected: false,
   723  		},
   724  		{
   725  			metadatas: StagedMetadatas{
   726  				{
   727  					Metadata: Metadata{
   728  						Pipelines: []PipelineMetadata{
   729  							{
   730  								Pipeline: applied.NewPipeline([]applied.OpUnion{
   731  									{
   732  										Type:   pipeline.RollupOpType,
   733  										Rollup: applied.RollupOp{AggregationID: aggregation.MustCompressTypes(aggregation.Sum)},
   734  									},
   735  								}),
   736  							},
   737  						},
   738  					},
   739  				},
   740  			},
   741  			expected: false,
   742  		},
   743  		{
   744  			metadatas: StagedMetadatas{
   745  				{
   746  					Metadata: Metadata{
   747  						Pipelines: []PipelineMetadata{
   748  							{},
   749  						},
   750  					},
   751  				},
   752  				{
   753  					Metadata: Metadata{
   754  						Pipelines: []PipelineMetadata{
   755  							{},
   756  						},
   757  					},
   758  				},
   759  			},
   760  			expected: false,
   761  		},
   762  	}
   763  
   764  	for _, input := range inputs {
   765  		input := input
   766  		t.Run(fmt.Sprintf("%v", input.metadatas), func(t *testing.T) {
   767  			require.Equal(t, input.expected, input.metadatas.IsDefault())
   768  		})
   769  	}
   770  }
   771  
   772  func TestForwardMetadataToProto(t *testing.T) {
   773  	inputs := []struct {
   774  		sequence []ForwardMetadata
   775  		expected []metricpb.ForwardMetadata
   776  	}{
   777  		{
   778  			sequence: []ForwardMetadata{
   779  				testSmallForwardMetadata,
   780  				testLargeForwardMetadata,
   781  			},
   782  			expected: []metricpb.ForwardMetadata{
   783  				testSmallForwardMetadataProto,
   784  				testLargeForwardMetadataProto,
   785  			},
   786  		},
   787  		{
   788  			sequence: []ForwardMetadata{
   789  				testLargeForwardMetadata,
   790  				testSmallForwardMetadata,
   791  			},
   792  			expected: []metricpb.ForwardMetadata{
   793  				testLargeForwardMetadataProto,
   794  				testSmallForwardMetadataProto,
   795  			},
   796  		},
   797  	}
   798  
   799  	for _, input := range inputs {
   800  		var pb metricpb.ForwardMetadata
   801  		for i, meta := range input.sequence {
   802  			require.NoError(t, meta.ToProto(&pb))
   803  			require.Equal(t, input.expected[i], pb)
   804  		}
   805  	}
   806  }
   807  
   808  func TestForwardMetadataFromProto(t *testing.T) {
   809  	inputs := []struct {
   810  		sequence []metricpb.ForwardMetadata
   811  		expected []ForwardMetadata
   812  	}{
   813  		{
   814  			sequence: []metricpb.ForwardMetadata{
   815  				testSmallForwardMetadataProto,
   816  				testLargeForwardMetadataProto,
   817  			},
   818  			expected: []ForwardMetadata{
   819  				testSmallForwardMetadata,
   820  				testLargeForwardMetadata,
   821  			},
   822  		},
   823  		{
   824  			sequence: []metricpb.ForwardMetadata{
   825  				testLargeForwardMetadataProto,
   826  				testSmallForwardMetadataProto,
   827  			},
   828  			expected: []ForwardMetadata{
   829  				testLargeForwardMetadata,
   830  				testSmallForwardMetadata,
   831  			},
   832  		},
   833  	}
   834  
   835  	for _, input := range inputs {
   836  		var res ForwardMetadata
   837  		for i, pb := range input.sequence {
   838  			require.NoError(t, res.FromProto(pb))
   839  			require.Equal(t, input.expected[i], res)
   840  		}
   841  	}
   842  }
   843  
   844  func TestForwardMetadataRoundtrip(t *testing.T) {
   845  	inputs := [][]ForwardMetadata{
   846  		{
   847  			testSmallForwardMetadata,
   848  			testLargeForwardMetadata,
   849  		},
   850  		{
   851  			testLargeForwardMetadata,
   852  			testSmallForwardMetadata,
   853  		},
   854  	}
   855  
   856  	for _, input := range inputs {
   857  		var (
   858  			pb  metricpb.ForwardMetadata
   859  			res ForwardMetadata
   860  		)
   861  		for _, metadata := range input {
   862  			require.NoError(t, metadata.ToProto(&pb))
   863  			require.NoError(t, res.FromProto(pb))
   864  			require.Equal(t, metadata, res)
   865  		}
   866  	}
   867  }
   868  
   869  func TestForwardMetadataToProtoBadMetadata(t *testing.T) {
   870  	var pb metricpb.ForwardMetadata
   871  	require.Error(t, testBadForwardMetadata.ToProto(&pb))
   872  }
   873  
   874  func TestForwardMetadataFromProtoBadMetadataProto(t *testing.T) {
   875  	var res ForwardMetadata
   876  	require.Error(t, res.FromProto(testBadForwardMetadataProto))
   877  }
   878  
   879  func TestPipelineMetadataClone(t *testing.T) {
   880  	cloned1 := testLargePipelineMetadata.Clone()
   881  	cloned2 := testLargePipelineMetadata.Clone()
   882  	require.True(t, cloned1.Equal(testLargePipelineMetadata))
   883  	require.True(t, cloned2.Equal(testLargePipelineMetadata))
   884  
   885  	// Assert that modifying the clone does not mutate the original pipeline metadata.
   886  	cloned1.StoragePolicies[0] = policy.MustParseStoragePolicy("1h:1h")
   887  	require.False(t, cloned1.Equal(testLargePipelineMetadata))
   888  	require.True(t, cloned2.Equal(testLargePipelineMetadata))
   889  }
   890  
   891  func TestPipelineMetadataToProto(t *testing.T) {
   892  	inputs := []struct {
   893  		sequence []PipelineMetadata
   894  		expected []metricpb.PipelineMetadata
   895  	}{
   896  		{
   897  			sequence: []PipelineMetadata{
   898  				testSmallPipelineMetadata,
   899  				testLargePipelineMetadata,
   900  			},
   901  			expected: []metricpb.PipelineMetadata{
   902  				testSmallPipelineMetadataProto,
   903  				testLargePipelineMetadataProto,
   904  			},
   905  		},
   906  		{
   907  			sequence: []PipelineMetadata{
   908  				testLargePipelineMetadata,
   909  				testSmallPipelineMetadata,
   910  			},
   911  			expected: []metricpb.PipelineMetadata{
   912  				testLargePipelineMetadataProto,
   913  				testSmallPipelineMetadataProto,
   914  			},
   915  		},
   916  	}
   917  
   918  	for _, input := range inputs {
   919  		var pb metricpb.PipelineMetadata
   920  		for i, meta := range input.sequence {
   921  			require.NoError(t, meta.ToProto(&pb))
   922  			require.Equal(t, input.expected[i], pb)
   923  		}
   924  	}
   925  }
   926  
   927  func TestPipelineMetadataFromProto(t *testing.T) {
   928  	inputs := []struct {
   929  		sequence []metricpb.PipelineMetadata
   930  		expected []PipelineMetadata
   931  	}{
   932  		{
   933  			sequence: []metricpb.PipelineMetadata{
   934  				testSmallPipelineMetadataProto,
   935  				testLargePipelineMetadataProto,
   936  			},
   937  			expected: []PipelineMetadata{
   938  				testSmallPipelineMetadata,
   939  				testLargePipelineMetadata,
   940  			},
   941  		},
   942  		{
   943  			sequence: []metricpb.PipelineMetadata{
   944  				testLargePipelineMetadataProto,
   945  				testSmallPipelineMetadataProto,
   946  			},
   947  			expected: []PipelineMetadata{
   948  				testLargePipelineMetadata,
   949  				testSmallPipelineMetadata,
   950  			},
   951  		},
   952  	}
   953  
   954  	for _, input := range inputs {
   955  		var res PipelineMetadata
   956  		for i, pb := range input.sequence {
   957  			require.NoError(t, res.FromProto(pb))
   958  			require.Equal(t, input.expected[i], res)
   959  		}
   960  	}
   961  }
   962  
   963  func TestPipelineMetadataRoundTrip(t *testing.T) {
   964  	inputs := [][]PipelineMetadata{
   965  		{
   966  			testSmallPipelineMetadata,
   967  			testLargePipelineMetadata,
   968  		},
   969  		{
   970  			testLargePipelineMetadata,
   971  			testSmallPipelineMetadata,
   972  		},
   973  	}
   974  
   975  	for _, input := range inputs {
   976  		var (
   977  			pb  metricpb.PipelineMetadata
   978  			res PipelineMetadata
   979  		)
   980  		for _, metadata := range input {
   981  			require.NoError(t, metadata.ToProto(&pb))
   982  			require.NoError(t, res.FromProto(pb))
   983  			require.Equal(t, metadata, res)
   984  		}
   985  	}
   986  }
   987  
   988  func TestPipelineMetadataToProtoBadMetadata(t *testing.T) {
   989  	var pb metricpb.PipelineMetadata
   990  	require.Error(t, testBadPipelineMetadata.ToProto(&pb))
   991  }
   992  
   993  func TestPipelineMetadataFromProtoBadMetadataProto(t *testing.T) {
   994  	var res PipelineMetadata
   995  	require.Error(t, res.FromProto(testBadPipelineMetadataProto))
   996  }
   997  
   998  func TestPipelineMetadatasClone(t *testing.T) {
   999  	input := PipelineMetadatas{
  1000  		testSmallPipelineMetadata,
  1001  		testLargePipelineMetadata,
  1002  	}
  1003  	cloned1 := input.Clone()
  1004  	cloned2 := input.Clone()
  1005  	require.True(t, cloned1.Equal(input))
  1006  	require.True(t, cloned2.Equal(input))
  1007  
  1008  	// Assert that modifying the clone does not mutate the original pipeline metadata.
  1009  	cloned1[0].StoragePolicies[0] = policy.MustParseStoragePolicy("1h:1h")
  1010  	require.False(t, cloned1.Equal(input))
  1011  	require.True(t, cloned2.Equal(input))
  1012  }
  1013  
  1014  func TestStagedMetadatasToProto(t *testing.T) {
  1015  	inputs := []struct {
  1016  		sequence []StagedMetadatas
  1017  		expected []metricpb.StagedMetadatas
  1018  	}{
  1019  		{
  1020  			sequence: []StagedMetadatas{
  1021  				testSmallStagedMetadatas,
  1022  				testLargeStagedMetadatas,
  1023  			},
  1024  			expected: []metricpb.StagedMetadatas{
  1025  				testSmallStagedMetadatasProto,
  1026  				testLargeStagedMetadatasProto,
  1027  			},
  1028  		},
  1029  		{
  1030  			sequence: []StagedMetadatas{
  1031  				testLargeStagedMetadatas,
  1032  				testSmallStagedMetadatas,
  1033  			},
  1034  			expected: []metricpb.StagedMetadatas{
  1035  				testLargeStagedMetadatasProto,
  1036  				testSmallStagedMetadatasProto,
  1037  			},
  1038  		},
  1039  	}
  1040  
  1041  	for _, input := range inputs {
  1042  		var pb metricpb.StagedMetadatas
  1043  		for i, meta := range input.sequence {
  1044  			require.NoError(t, meta.ToProto(&pb))
  1045  			require.Equal(t, input.expected[i], pb)
  1046  		}
  1047  	}
  1048  }
  1049  
  1050  func TestStagedMetadatasFromProto(t *testing.T) {
  1051  	inputs := []struct {
  1052  		sequence []metricpb.StagedMetadatas
  1053  		expected []StagedMetadatas
  1054  	}{
  1055  		{
  1056  			sequence: []metricpb.StagedMetadatas{
  1057  				testSmallStagedMetadatasProto,
  1058  				testLargeStagedMetadatasProto,
  1059  			},
  1060  			expected: []StagedMetadatas{
  1061  				testSmallStagedMetadatas,
  1062  				testLargeStagedMetadatas,
  1063  			},
  1064  		},
  1065  		{
  1066  			sequence: []metricpb.StagedMetadatas{
  1067  				testLargeStagedMetadatasProto,
  1068  				testSmallStagedMetadatasProto,
  1069  			},
  1070  			expected: []StagedMetadatas{
  1071  				testLargeStagedMetadatas,
  1072  				testSmallStagedMetadatas,
  1073  			},
  1074  		},
  1075  	}
  1076  
  1077  	for _, input := range inputs {
  1078  		var resOpt, resReference StagedMetadatas
  1079  		for i, pb := range input.sequence {
  1080  			require.NoError(t, resReference.fromProto(pb))
  1081  			require.NoError(t, resOpt.FromProto(pb))
  1082  			require.Equal(t, input.expected[i], resOpt)
  1083  			require.Equal(t, input.expected[i], resReference)
  1084  			require.Equal(t, resOpt, resReference)
  1085  		}
  1086  	}
  1087  }
  1088  
  1089  func TestStagedMetadatasRoundTrip(t *testing.T) {
  1090  	inputs := [][]StagedMetadatas{
  1091  		{
  1092  			testSmallStagedMetadatas,
  1093  			testLargeStagedMetadatas,
  1094  		},
  1095  		{
  1096  			testLargeStagedMetadatas,
  1097  			testSmallStagedMetadatas,
  1098  		},
  1099  	}
  1100  
  1101  	for _, input := range inputs {
  1102  		var (
  1103  			pb  metricpb.StagedMetadatas
  1104  			res StagedMetadatas
  1105  		)
  1106  		for _, metadata := range input {
  1107  			require.NoError(t, metadata.ToProto(&pb))
  1108  			require.NoError(t, res.FromProto(pb))
  1109  			require.Equal(t, metadata, res)
  1110  		}
  1111  	}
  1112  }
  1113  
  1114  func TestStagedMetadatasToProtoBadMetadatas(t *testing.T) {
  1115  	var pb metricpb.StagedMetadatas
  1116  	require.Error(t, testBadStagedMetadatas.ToProto(&pb))
  1117  }
  1118  
  1119  func TestStagedMetadatasFromProtoBadMetadatasProto(t *testing.T) {
  1120  	var res StagedMetadatas
  1121  	require.Error(t, res.FromProto(testBadStagedMetadatasProto))
  1122  }
  1123  
  1124  func TestVersionedStagedMetadatasMarshalJSON(t *testing.T) {
  1125  	vs := VersionedStagedMetadatas{
  1126  		Version: 12,
  1127  		StagedMetadatas: StagedMetadatas{
  1128  			{
  1129  				CutoverNanos: 4567,
  1130  				Tombstoned:   true,
  1131  				Metadata: Metadata{
  1132  					Pipelines: []PipelineMetadata{
  1133  						{
  1134  							ResendEnabled: true,
  1135  							AggregationID: aggregation.MustCompressTypes(aggregation.Sum),
  1136  							StoragePolicies: []policy.StoragePolicy{
  1137  								policy.NewStoragePolicy(time.Second, xtime.Second, time.Hour),
  1138  								policy.NewStoragePolicy(time.Minute, xtime.Minute, 12*time.Hour),
  1139  							},
  1140  						},
  1141  						{
  1142  							AggregationID: aggregation.DefaultID,
  1143  							StoragePolicies: []policy.StoragePolicy{
  1144  								policy.NewStoragePolicy(10*time.Second, xtime.Second, time.Hour),
  1145  							},
  1146  						},
  1147  					},
  1148  				},
  1149  			},
  1150  		},
  1151  	}
  1152  	res, err := json.Marshal(vs)
  1153  	require.NoError(t, err)
  1154  
  1155  	expected := `{` +
  1156  		`"stagedMetadatas":` +
  1157  		`[{"metadata":{"pipelines":[` +
  1158  		`{"storagePolicies":["1s:1h","1m:12h"],"aggregation":["Sum"],"resendEnabled":true},` +
  1159  		`{"storagePolicies":["10s:1h"],"aggregation":null}]},` +
  1160  		`"cutoverNanos":4567,` +
  1161  		`"tombstoned":true}],` +
  1162  		`"version":12` +
  1163  		`}`
  1164  	require.Equal(t, expected, string(res))
  1165  }
  1166  
  1167  func TestVersionedStagedMetadatasMarshalJSONRoundtrip(t *testing.T) {
  1168  	vs := VersionedStagedMetadatas{
  1169  		Version: 12,
  1170  		StagedMetadatas: StagedMetadatas{
  1171  			{
  1172  				CutoverNanos: 4567,
  1173  				Tombstoned:   true,
  1174  				Metadata: Metadata{
  1175  					Pipelines: []PipelineMetadata{
  1176  						{
  1177  							AggregationID: aggregation.MustCompressTypes(aggregation.Sum),
  1178  							StoragePolicies: []policy.StoragePolicy{
  1179  								policy.NewStoragePolicy(time.Second, xtime.Second, time.Hour),
  1180  								policy.NewStoragePolicy(time.Minute, xtime.Minute, 12*time.Hour),
  1181  							},
  1182  							DropPolicy: policy.DropNone,
  1183  						},
  1184  						{
  1185  							AggregationID: aggregation.DefaultID,
  1186  							StoragePolicies: []policy.StoragePolicy{
  1187  								policy.NewStoragePolicy(10*time.Second, xtime.Second, time.Hour),
  1188  							},
  1189  							DropPolicy: policy.DropNone,
  1190  						},
  1191  					},
  1192  				},
  1193  			},
  1194  		},
  1195  	}
  1196  	b, err := json.Marshal(vs)
  1197  	require.NoError(t, err)
  1198  	var res VersionedStagedMetadatas
  1199  	require.NoError(t, json.Unmarshal(b, &res))
  1200  	require.Equal(t, vs, res)
  1201  }
  1202  
  1203  func TestDropMustDropPolicyPipelineMetadata(t *testing.T) {
  1204  	require.True(t, testDropMustDropPolicyPipelineMetadata.IsDropPolicyApplied())
  1205  }
  1206  
  1207  func TestDropExceptIfMatchOtherDropPolicyPipelineMetadata(t *testing.T) {
  1208  	require.True(t, testDropExceptIfMatchOtherDropPolicyPipelineMetadata.IsDropPolicyApplied())
  1209  }
  1210  
  1211  func TestApplyOrRemoveDropPoliciesDropMust(t *testing.T) {
  1212  	input := PipelineMetadatas{
  1213  		{
  1214  			AggregationID: aggregation.MustCompressTypes(aggregation.Sum),
  1215  			StoragePolicies: []policy.StoragePolicy{
  1216  				policy.NewStoragePolicy(time.Second, xtime.Second, time.Hour),
  1217  				policy.NewStoragePolicy(time.Minute, xtime.Minute, 12*time.Hour),
  1218  			},
  1219  			DropPolicy: policy.DropNone,
  1220  		},
  1221  		{
  1222  			AggregationID:   aggregation.DefaultID,
  1223  			StoragePolicies: nil,
  1224  			DropPolicy:      policy.DropMust,
  1225  		},
  1226  		{
  1227  			AggregationID: aggregation.MustCompressTypes(aggregation.Sum),
  1228  			StoragePolicies: []policy.StoragePolicy{
  1229  				policy.NewStoragePolicy(time.Minute, xtime.Minute, 12*time.Hour),
  1230  				policy.NewStoragePolicy(10*time.Minute, xtime.Minute, 24*time.Hour),
  1231  			},
  1232  			DropPolicy: policy.DropNone,
  1233  		},
  1234  	}
  1235  	output, result := input.ApplyOrRemoveDropPolicies()
  1236  	require.Equal(t, AppliedEffectiveDropPolicyResult, result)
  1237  	require.True(t, output.Equal(DropPipelineMetadatas))
  1238  }
  1239  
  1240  func TestApplyOrRemoveDropPoliciesDropIfOnlyMatchEffective(t *testing.T) {
  1241  	input := PipelineMetadatas{
  1242  		{
  1243  			AggregationID:   aggregation.DefaultID,
  1244  			StoragePolicies: nil,
  1245  			DropPolicy:      policy.DropIfOnlyMatch,
  1246  		},
  1247  	}
  1248  	output, result := input.ApplyOrRemoveDropPolicies()
  1249  	require.Equal(t, AppliedEffectiveDropPolicyResult, result)
  1250  	require.True(t, output.Equal(DropPipelineMetadatas))
  1251  
  1252  	// Ensure that modifying output does not affect DropPipelineMetadatas,
  1253  	// to prevent regressions where global variables are returned.
  1254  	output[0].AggregationID = aggregation.MustCompressTypes(aggregation.Count)
  1255  	require.False(t, output.Equal(DropPipelineMetadatas))
  1256  }
  1257  
  1258  func TestApplyOrRemoveDropPoliciesDropIfOnlyMatchMiddleIneffective(t *testing.T) {
  1259  	validRules := PipelineMetadatas{
  1260  		{
  1261  			AggregationID: aggregation.MustCompressTypes(aggregation.Sum),
  1262  			StoragePolicies: []policy.StoragePolicy{
  1263  				policy.NewStoragePolicy(time.Second, xtime.Second, time.Hour),
  1264  				policy.NewStoragePolicy(time.Minute, xtime.Minute, 12*time.Hour),
  1265  			},
  1266  			DropPolicy: policy.DropNone,
  1267  		},
  1268  		{
  1269  			AggregationID: aggregation.MustCompressTypes(aggregation.Sum),
  1270  			StoragePolicies: []policy.StoragePolicy{
  1271  				policy.NewStoragePolicy(time.Minute, xtime.Minute, 12*time.Hour),
  1272  				policy.NewStoragePolicy(10*time.Minute, xtime.Minute, 24*time.Hour),
  1273  			},
  1274  			DropPolicy: policy.DropNone,
  1275  		},
  1276  	}
  1277  
  1278  	// Run test for every single insertion point
  1279  	for i := 0; i < len(validRules)+1; i++ {
  1280  		t.Run(fmt.Sprintf("test insert drop if only rule at %d", i),
  1281  			func(t *testing.T) {
  1282  				var (
  1283  					copy  = append(PipelineMetadatas(nil), validRules...)
  1284  					input PipelineMetadatas
  1285  				)
  1286  				for j := 0; j < len(validRules)+1; j++ {
  1287  					if j == i {
  1288  						// Insert the drop if only match rule at this position
  1289  						input = append(input, PipelineMetadata{
  1290  							AggregationID:   aggregation.DefaultID,
  1291  							StoragePolicies: nil,
  1292  							DropPolicy:      policy.DropIfOnlyMatch,
  1293  						})
  1294  					} else {
  1295  						input = append(input, copy[0])
  1296  						copy = copy[1:]
  1297  					}
  1298  				}
  1299  
  1300  				output, result := input.ApplyOrRemoveDropPolicies()
  1301  				require.Equal(t, RemovedIneffectiveDropPoliciesResult, result)
  1302  				require.True(t, output.Equal(validRules))
  1303  			})
  1304  	}
  1305  }
  1306  
  1307  func TestApplyOrRemoveDropPoliciesDropIfOnlyMatchNone(t *testing.T) {
  1308  	input := PipelineMetadatas{
  1309  		{
  1310  			AggregationID: aggregation.MustCompressTypes(aggregation.Sum),
  1311  			StoragePolicies: []policy.StoragePolicy{
  1312  				policy.NewStoragePolicy(time.Second, xtime.Second, time.Hour),
  1313  				policy.NewStoragePolicy(time.Minute, xtime.Minute, 12*time.Hour),
  1314  			},
  1315  			DropPolicy: policy.DropNone,
  1316  		},
  1317  		{
  1318  			AggregationID: aggregation.MustCompressTypes(aggregation.Sum),
  1319  			StoragePolicies: []policy.StoragePolicy{
  1320  				policy.NewStoragePolicy(time.Minute, xtime.Minute, 12*time.Hour),
  1321  				policy.NewStoragePolicy(10*time.Minute, xtime.Minute, 24*time.Hour),
  1322  			},
  1323  			DropPolicy: policy.DropNone,
  1324  		},
  1325  	}
  1326  	output, result := input.ApplyOrRemoveDropPolicies()
  1327  	require.Equal(t, NoDropPolicyPresentResult, result)
  1328  	require.True(t, output.Equal(input))
  1329  }
  1330  
  1331  func TestStagedMetadatasDropReturnsIsDropPolicyAppliedTrue(t *testing.T) {
  1332  	require.True(t, StagedMetadatas{
  1333  		StagedMetadata{Metadata: DropMetadata, CutoverNanos: 123},
  1334  	}.IsDropPolicyApplied())
  1335  }