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

     1  // Copyright (c) 2017 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 policy
    22  
    23  import (
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/m3db/m3/src/metrics/aggregation"
    28  	"github.com/m3db/m3/src/metrics/generated/proto/aggregationpb"
    29  	"github.com/m3db/m3/src/metrics/generated/proto/policypb"
    30  	"github.com/m3db/m3/src/x/test/testmarshal"
    31  	xtime "github.com/m3db/m3/src/x/time"
    32  
    33  	"github.com/stretchr/testify/require"
    34  	yaml "gopkg.in/yaml.v2"
    35  )
    36  
    37  func TestPolicyString(t *testing.T) {
    38  	inputs := []struct {
    39  		p        Policy
    40  		expected string
    41  	}{
    42  		{p: NewPolicy(NewStoragePolicy(10*time.Second, xtime.Second, time.Hour), aggregation.DefaultID), expected: "10s:1h"},
    43  		{p: NewPolicy(NewStoragePolicy(time.Minute, xtime.Minute, 12*time.Hour), aggregation.MustCompressTypes(aggregation.Mean, aggregation.P999)), expected: "1m:12h|Mean,P999"},
    44  		{p: NewPolicy(NewStoragePolicy(time.Minute, xtime.Minute, 12*time.Hour), aggregation.MustCompressTypes(aggregation.Mean)), expected: "1m:12h|Mean"},
    45  	}
    46  	for _, input := range inputs {
    47  		require.Equal(t, input.expected, input.p.String())
    48  	}
    49  }
    50  
    51  func TestPolicyMarshalling(t *testing.T) {
    52  	inputs := []struct {
    53  		notCanonical bool
    54  		str          string
    55  		expected     Policy
    56  	}{
    57  		{
    58  			str:      "1s:1h",
    59  			expected: NewPolicy(NewStoragePolicy(time.Second, xtime.Second, time.Hour), aggregation.DefaultID),
    60  		},
    61  		{
    62  			str:      "10s:1d|Mean",
    63  			expected: NewPolicy(NewStoragePolicy(10*time.Second, xtime.Second, 24*time.Hour), aggregation.MustCompressTypes(aggregation.Mean)),
    64  		},
    65  		{
    66  			notCanonical: true,
    67  			str:          "60s:24h|Mean,Count",
    68  			expected:     NewPolicy(NewStoragePolicy(60*time.Second, xtime.Minute, 24*time.Hour), aggregation.MustCompressTypes(aggregation.Mean, aggregation.Count)),
    69  		},
    70  		{
    71  			notCanonical: true,
    72  			str:          "1m:1d|Count,Mean",
    73  			expected:     NewPolicy(NewStoragePolicy(time.Minute, xtime.Minute, 24*time.Hour), aggregation.MustCompressTypes(aggregation.Mean, aggregation.Count)),
    74  		},
    75  		{
    76  			str:      "1m:1d|Mean,Count",
    77  			expected: NewPolicy(NewStoragePolicy(time.Minute, xtime.Minute, 24*time.Hour), aggregation.MustCompressTypes(aggregation.Mean, aggregation.Count)),
    78  		},
    79  		{
    80  			notCanonical: true,
    81  			str:          "1s@1s:1h|P999,P9999",
    82  			expected:     NewPolicy(NewStoragePolicy(time.Second, xtime.Second, time.Hour), aggregation.MustCompressTypes(aggregation.P999, aggregation.P9999)),
    83  		},
    84  	}
    85  
    86  	t.Run("roundtrips", func(t *testing.T) {
    87  		examples := make([]Policy, 0, len(inputs))
    88  		for _, ex := range inputs {
    89  			examples = append(examples, ex.expected)
    90  		}
    91  
    92  		testmarshal.TestMarshalersRoundtrip(t, examples, []testmarshal.Marshaler{testmarshal.TextMarshaler, testmarshal.JSONMarshaler, testmarshal.YAMLMarshaler})
    93  	})
    94  
    95  	t.Run("marshals/text", func(t *testing.T) {
    96  		for _, input := range inputs {
    97  			if input.notCanonical {
    98  				continue
    99  			}
   100  			testmarshal.Require(t, testmarshal.AssertMarshals(t, testmarshal.TextMarshaler, input.expected, []byte(input.str)))
   101  		}
   102  	})
   103  
   104  	t.Run("unmarshals/text", func(t *testing.T) {
   105  		for _, input := range inputs {
   106  			testmarshal.Require(t, testmarshal.AssertUnmarshals(t, testmarshal.TextMarshaler, input.expected, []byte(input.str)))
   107  		}
   108  	})
   109  
   110  	t.Run("unmarshals/yaml", func(t *testing.T) {
   111  		for _, input := range inputs {
   112  			testmarshal.Require(t, testmarshal.AssertUnmarshals(t, testmarshal.YAMLMarshaler, input.expected, []byte(input.str)))
   113  		}
   114  	})
   115  }
   116  
   117  func TestPolicyUnmarshalYAMLErrors(t *testing.T) {
   118  	inputs := []string{
   119  		"|",
   120  		"|Mean",
   121  		"1s:1h|",
   122  		"1s:1h||",
   123  		"1s:1h|P99|",
   124  		"1s:1h|P",
   125  		"1s:1h|Meann",
   126  		"1s:1h|Mean,",
   127  	}
   128  	for _, input := range inputs {
   129  		var p Policy
   130  		require.Error(t, yaml.Unmarshal([]byte(input), &p))
   131  	}
   132  }
   133  
   134  func TestNewPoliciesFromProto(t *testing.T) {
   135  	input := []*policypb.Policy{
   136  		&policypb.Policy{
   137  			StoragePolicy: &policypb.StoragePolicy{
   138  				Resolution: policypb.Resolution{
   139  					WindowSize: int64(10 * time.Second),
   140  					Precision:  int64(time.Second),
   141  				},
   142  				Retention: policypb.Retention{
   143  					Period: int64(24 * time.Hour),
   144  				},
   145  			},
   146  			AggregationTypes: []aggregationpb.AggregationType{
   147  				aggregationpb.AggregationType_MEAN,
   148  				aggregationpb.AggregationType_P999,
   149  			},
   150  		},
   151  		&policypb.Policy{
   152  			StoragePolicy: &policypb.StoragePolicy{
   153  				Resolution: policypb.Resolution{
   154  					WindowSize: int64(time.Minute),
   155  					Precision:  int64(time.Minute),
   156  				},
   157  				Retention: policypb.Retention{
   158  					Period: int64(240 * time.Hour),
   159  				},
   160  			},
   161  			AggregationTypes: []aggregationpb.AggregationType{
   162  				aggregationpb.AggregationType_MEAN,
   163  				aggregationpb.AggregationType_P9999,
   164  			},
   165  		},
   166  	}
   167  
   168  	res, err := NewPoliciesFromProto(input)
   169  	require.NoError(t, err)
   170  	require.Equal(t, []Policy{
   171  		NewPolicy(NewStoragePolicy(10*time.Second, xtime.Second, 24*time.Hour), aggregation.MustCompressTypes(aggregation.Mean, aggregation.P999)),
   172  		NewPolicy(NewStoragePolicy(time.Minute, xtime.Minute, 240*time.Hour), aggregation.MustCompressTypes(aggregation.Mean, aggregation.P9999)),
   173  	}, res)
   174  }
   175  
   176  func TestParsePolicyIntoProto(t *testing.T) {
   177  	inputs := []struct {
   178  		str      string
   179  		expected *policypb.Policy
   180  	}{
   181  		{
   182  			str: "1s:1h",
   183  			expected: &policypb.Policy{
   184  				StoragePolicy: &policypb.StoragePolicy{
   185  					Resolution: policypb.Resolution{
   186  						WindowSize: time.Second.Nanoseconds(),
   187  						Precision:  time.Second.Nanoseconds(),
   188  					},
   189  					Retention: policypb.Retention{
   190  						Period: time.Hour.Nanoseconds(),
   191  					},
   192  				},
   193  			},
   194  		},
   195  		{
   196  			str: "1s:1h|Mean",
   197  			expected: &policypb.Policy{
   198  				StoragePolicy: &policypb.StoragePolicy{
   199  					Resolution: policypb.Resolution{
   200  						WindowSize: time.Second.Nanoseconds(),
   201  						Precision:  time.Second.Nanoseconds(),
   202  					},
   203  					Retention: policypb.Retention{
   204  						Period: time.Hour.Nanoseconds(),
   205  					},
   206  				},
   207  				AggregationTypes: []aggregationpb.AggregationType{aggregationpb.AggregationType_MEAN},
   208  			},
   209  		},
   210  		{
   211  			str: "60s:24h|Mean,Count",
   212  			expected: &policypb.Policy{
   213  				StoragePolicy: &policypb.StoragePolicy{
   214  					Resolution: policypb.Resolution{
   215  						WindowSize: time.Minute.Nanoseconds(),
   216  						Precision:  time.Minute.Nanoseconds(),
   217  					},
   218  					Retention: policypb.Retention{
   219  						Period: 24 * time.Hour.Nanoseconds(),
   220  					},
   221  				},
   222  				AggregationTypes: []aggregationpb.AggregationType{aggregationpb.AggregationType_MEAN, aggregationpb.AggregationType_COUNT},
   223  			},
   224  		},
   225  		{
   226  			str: "1m:1d|Count,Mean",
   227  			expected: &policypb.Policy{
   228  				StoragePolicy: &policypb.StoragePolicy{
   229  					Resolution: policypb.Resolution{
   230  						WindowSize: time.Minute.Nanoseconds(),
   231  						Precision:  time.Minute.Nanoseconds(),
   232  					},
   233  					Retention: policypb.Retention{
   234  						Period: 24 * time.Hour.Nanoseconds(),
   235  					},
   236  				},
   237  				AggregationTypes: []aggregationpb.AggregationType{aggregationpb.AggregationType_MEAN, aggregationpb.AggregationType_COUNT},
   238  			},
   239  		},
   240  		{
   241  			str: "1m@1s:1h|P999,P9999",
   242  			expected: &policypb.Policy{
   243  				StoragePolicy: &policypb.StoragePolicy{
   244  					Resolution: policypb.Resolution{
   245  						WindowSize: time.Minute.Nanoseconds(),
   246  						Precision:  time.Second.Nanoseconds(),
   247  					},
   248  					Retention: policypb.Retention{
   249  						Period: time.Hour.Nanoseconds(),
   250  					},
   251  				},
   252  				AggregationTypes: []aggregationpb.AggregationType{aggregationpb.AggregationType_P999, aggregationpb.AggregationType_P9999},
   253  			},
   254  		},
   255  	}
   256  
   257  	for _, input := range inputs {
   258  		p, err := ParsePolicy(input.str)
   259  		require.NoError(t, err)
   260  
   261  		sp, err := p.Proto()
   262  		require.NoError(t, err)
   263  		require.Equal(t, input.expected, sp, input.str)
   264  	}
   265  }