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

     1  // Copyright (c) 2016 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  	"encoding/json"
    25  	"sort"
    26  	"testing"
    27  	"time"
    28  
    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  var (
    38  	testStoragePolicy      = NewStoragePolicy(10*time.Second, xtime.Second, time.Hour)
    39  	testBadStoragePolicy   = NewStoragePolicy(10*time.Second, xtime.Unit(100), time.Hour)
    40  	testStoragePolicyProto = policypb.StoragePolicy{
    41  		Resolution: policypb.Resolution{
    42  			WindowSize: (10 * time.Second).Nanoseconds(),
    43  			Precision:  time.Second.Nanoseconds(),
    44  		},
    45  		Retention: policypb.Retention{
    46  			Period: time.Hour.Nanoseconds(),
    47  		},
    48  	}
    49  	testStoragePolicyProtoNoResolution = policypb.StoragePolicy{
    50  		Retention: policypb.Retention{
    51  			Period: time.Hour.Nanoseconds(),
    52  		},
    53  	}
    54  	testStoragePolicyProtoNoRetention = policypb.StoragePolicy{
    55  		Resolution: policypb.Resolution{
    56  			WindowSize: (10 * time.Second).Nanoseconds(),
    57  			Precision:  time.Second.Nanoseconds(),
    58  		},
    59  	}
    60  	testStoragePolicyProtoBadPrecision = policypb.StoragePolicy{
    61  		Resolution: policypb.Resolution{
    62  			WindowSize: (10 * time.Second).Nanoseconds(),
    63  			Precision:  2,
    64  		},
    65  		Retention: policypb.Retention{
    66  			Period: time.Hour.Nanoseconds(),
    67  		},
    68  	}
    69  )
    70  
    71  func TestStoragePolicyString(t *testing.T) {
    72  	inputs := []struct {
    73  		p        StoragePolicy
    74  		expected string
    75  	}{
    76  		{p: NewStoragePolicy(10*time.Second, xtime.Second, time.Hour), expected: "10s:1h"},
    77  		{p: NewStoragePolicy(time.Minute, xtime.Minute, 12*time.Hour), expected: "1m:12h"},
    78  		{p: NewStoragePolicy(time.Minute, xtime.Second, 12*time.Hour), expected: "1m@1s:12h"},
    79  	}
    80  	for _, input := range inputs {
    81  		require.Equal(t, input.expected, input.p.String())
    82  	}
    83  }
    84  
    85  func TestParseStoragePolicy(t *testing.T) {
    86  	inputs := []struct {
    87  		str      string
    88  		expected StoragePolicy
    89  	}{
    90  		{
    91  			str:      "1s:1h",
    92  			expected: NewStoragePolicy(time.Second, xtime.Second, time.Hour),
    93  		},
    94  		{
    95  			str:      "10s:1d",
    96  			expected: NewStoragePolicy(10*time.Second, xtime.Second, 24*time.Hour),
    97  		},
    98  		{
    99  			str:      "60s:24h",
   100  			expected: NewStoragePolicy(time.Minute, xtime.Minute, 24*time.Hour),
   101  		},
   102  		{
   103  			str:      "1m:1d",
   104  			expected: NewStoragePolicy(time.Minute, xtime.Minute, 24*time.Hour),
   105  		},
   106  		{
   107  			str:      "1s@1s:1h",
   108  			expected: NewStoragePolicy(time.Second, xtime.Second, time.Hour),
   109  		},
   110  		{
   111  			str:      "10s@1s:1d",
   112  			expected: NewStoragePolicy(10*time.Second, xtime.Second, 24*time.Hour),
   113  		},
   114  		{
   115  			str:      "60s@1s:24h",
   116  			expected: NewStoragePolicy(time.Minute, xtime.Second, 24*time.Hour),
   117  		},
   118  		{
   119  			str:      "1m@1m:1d",
   120  			expected: NewStoragePolicy(time.Minute, xtime.Minute, 24*time.Hour),
   121  		},
   122  		{
   123  			str:      "1h0m0s@1h0m0s:24h0m0s",
   124  			expected: NewStoragePolicy(time.Hour, xtime.Hour, 24*time.Hour),
   125  		},
   126  		{
   127  			str:      "1h:24h",
   128  			expected: NewStoragePolicy(time.Hour, xtime.Hour, 24*time.Hour),
   129  		},
   130  	}
   131  	for _, input := range inputs {
   132  		res, err := ParseStoragePolicy(input.str)
   133  		require.NoError(t, err)
   134  		require.Equal(t, input.expected, res)
   135  	}
   136  }
   137  
   138  func TestStoragePolicyParseRoundTrip(t *testing.T) {
   139  	inputs := []StoragePolicy{
   140  		NewStoragePolicy(time.Second, xtime.Second, time.Hour),
   141  		NewStoragePolicy(10*time.Second, xtime.Second, 24*time.Hour),
   142  		NewStoragePolicy(time.Minute, xtime.Minute, 24*time.Hour),
   143  		NewStoragePolicy(time.Minute, xtime.Minute, 24*time.Hour),
   144  		NewStoragePolicy(time.Second, xtime.Second, time.Hour),
   145  		NewStoragePolicy(10*time.Second, xtime.Second, 24*time.Hour),
   146  		NewStoragePolicy(time.Minute, xtime.Second, 24*time.Hour),
   147  		NewStoragePolicy(time.Minute, xtime.Minute, 24*time.Hour),
   148  	}
   149  
   150  	for _, input := range inputs {
   151  		str := input.String()
   152  		parsed, err := ParseStoragePolicy(str)
   153  		require.NoError(t, err)
   154  		require.Equal(t, input, parsed)
   155  	}
   156  }
   157  
   158  func TestParseStoragePolicyErrors(t *testing.T) {
   159  	inputs := []string{
   160  		"1s:1s:1s",
   161  		"10seconds:1s",
   162  		"10seconds@1s:1d",
   163  		"10s@2s:1d",
   164  		"0.1s@1s:1d",
   165  		"10s@2minutes:2d",
   166  	}
   167  	for _, input := range inputs {
   168  		_, err := ParseStoragePolicy(input)
   169  		require.Error(t, err)
   170  	}
   171  }
   172  
   173  func TestStoragePolicyMarshalJSON(t *testing.T) {
   174  	inputs := []struct {
   175  		storagePolicy StoragePolicy
   176  		expected      string
   177  	}{
   178  		{
   179  			storagePolicy: NewStoragePolicy(time.Second, xtime.Second, time.Hour),
   180  			expected:      "\"1s:1h\"",
   181  		},
   182  		{
   183  			storagePolicy: NewStoragePolicy(10*time.Second, xtime.Second, 24*time.Hour),
   184  			expected:      "\"10s:1d\"",
   185  		},
   186  		{
   187  			storagePolicy: NewStoragePolicy(time.Minute, xtime.Minute, 24*time.Hour),
   188  			expected:      "\"1m:1d\"",
   189  		},
   190  		{
   191  			storagePolicy: NewStoragePolicy(time.Minute, xtime.Minute, 24*time.Hour),
   192  			expected:      "\"1m:1d\"",
   193  		},
   194  		{
   195  			storagePolicy: NewStoragePolicy(time.Second, xtime.Second, time.Hour),
   196  			expected:      "\"1s:1h\"",
   197  		},
   198  		{
   199  			storagePolicy: NewStoragePolicy(10*time.Second, xtime.Second, 24*time.Hour),
   200  			expected:      "\"10s:1d\"",
   201  		},
   202  		{
   203  			storagePolicy: NewStoragePolicy(time.Minute, xtime.Second, 24*time.Hour),
   204  			expected:      "\"1m@1s:1d\"",
   205  		},
   206  		{
   207  			storagePolicy: NewStoragePolicy(time.Minute, xtime.Minute, 24*time.Hour),
   208  			expected:      "\"1m:1d\"",
   209  		},
   210  	}
   211  
   212  	for _, input := range inputs {
   213  		res, err := json.Marshal(input.storagePolicy)
   214  		require.NoError(t, err)
   215  		require.Equal(t, input.expected, string(res))
   216  	}
   217  }
   218  
   219  func TestStoragePolicyUnmarshalJSON(t *testing.T) {
   220  	inputs := []struct {
   221  		str      string
   222  		expected StoragePolicy
   223  	}{
   224  		{
   225  			str:      "\"1s:1h\"",
   226  			expected: NewStoragePolicy(time.Second, xtime.Second, time.Hour),
   227  		},
   228  		{
   229  			str:      "\"10s:1d\"",
   230  			expected: NewStoragePolicy(10*time.Second, xtime.Second, 24*time.Hour),
   231  		},
   232  		{
   233  			str:      "\"60s:24h\"",
   234  			expected: NewStoragePolicy(time.Minute, xtime.Minute, 24*time.Hour),
   235  		},
   236  		{
   237  			str:      "\"1m:1d\"",
   238  			expected: NewStoragePolicy(time.Minute, xtime.Minute, 24*time.Hour),
   239  		},
   240  		{
   241  			str:      "\"1s@1s:1h\"",
   242  			expected: NewStoragePolicy(time.Second, xtime.Second, time.Hour),
   243  		},
   244  		{
   245  			str:      "\"10s@1s:1d\"",
   246  			expected: NewStoragePolicy(10*time.Second, xtime.Second, 24*time.Hour),
   247  		},
   248  		{
   249  			str:      "\"60s@1s:24h\"",
   250  			expected: NewStoragePolicy(time.Minute, xtime.Second, 24*time.Hour),
   251  		},
   252  		{
   253  			str:      "\"1m@1m:1d\"",
   254  			expected: NewStoragePolicy(time.Minute, xtime.Minute, 24*time.Hour),
   255  		},
   256  	}
   257  
   258  	for _, input := range inputs {
   259  		var p StoragePolicy
   260  		require.NoError(t, json.Unmarshal([]byte(input.str), &p))
   261  		require.Equal(t, input.expected, p)
   262  	}
   263  }
   264  
   265  func TestStoragePolicyUnmarshalJSONError(t *testing.T) {
   266  	inputs := []string{
   267  		"1m:1d",
   268  		"1m",
   269  		"1d",
   270  	}
   271  
   272  	for _, input := range inputs {
   273  		var p StoragePolicy
   274  		require.Error(t, json.Unmarshal([]byte(input), &p))
   275  	}
   276  }
   277  
   278  func TestStoragePolicyMarshalRoundtrip(t *testing.T) {
   279  	inputs := StoragePolicies{
   280  		NewStoragePolicy(time.Second, xtime.Second, time.Hour),
   281  		NewStoragePolicy(10*time.Second, xtime.Second, 24*time.Hour),
   282  		NewStoragePolicy(time.Minute, xtime.Minute, 24*time.Hour),
   283  		NewStoragePolicy(time.Minute, xtime.Minute, 24*time.Hour),
   284  		NewStoragePolicy(time.Second, xtime.Second, time.Hour),
   285  		NewStoragePolicy(10*time.Second, xtime.Second, 24*time.Hour),
   286  		NewStoragePolicy(time.Minute, xtime.Second, 24*time.Hour),
   287  		NewStoragePolicy(time.Minute, xtime.Minute, 24*time.Hour),
   288  	}
   289  
   290  	testmarshal.TestMarshalersRoundtrip(t, inputs,
   291  		[]testmarshal.Marshaler{
   292  			testmarshal.YAMLMarshaler,
   293  			testmarshal.TextMarshaler,
   294  			testmarshal.JSONMarshaler})
   295  }
   296  
   297  func TestStoragePolicyYAMLMarshal(t *testing.T) {
   298  	inputs := []struct {
   299  		str          string
   300  		expected     StoragePolicy
   301  		notCanonical bool
   302  	}{
   303  		{
   304  			str:      "1s:1h",
   305  			expected: NewStoragePolicy(time.Second, xtime.Second, time.Hour),
   306  		},
   307  		{
   308  			str:      "10s:1d",
   309  			expected: NewStoragePolicy(10*time.Second, xtime.Second, 24*time.Hour),
   310  		},
   311  		{
   312  			str:          "60s:24h",
   313  			notCanonical: true,
   314  			expected:     NewStoragePolicy(time.Minute, xtime.Minute, 24*time.Hour),
   315  		},
   316  		{
   317  			str:      "1m:1d",
   318  			expected: NewStoragePolicy(time.Minute, xtime.Minute, 24*time.Hour),
   319  		},
   320  		{
   321  			str:          "1s@1s:1h",
   322  			notCanonical: true,
   323  			expected:     NewStoragePolicy(time.Second, xtime.Second, time.Hour),
   324  		},
   325  		{
   326  			str:          "10s@1s:1d",
   327  			notCanonical: true,
   328  			expected:     NewStoragePolicy(10*time.Second, xtime.Second, 24*time.Hour),
   329  		},
   330  		{
   331  			str:          "60s@1s:24h",
   332  			notCanonical: true,
   333  			expected:     NewStoragePolicy(time.Minute, xtime.Second, 24*time.Hour),
   334  		},
   335  		{
   336  			str:          "1m@1m:1d",
   337  			notCanonical: true,
   338  			expected:     NewStoragePolicy(time.Minute, xtime.Minute, 24*time.Hour),
   339  		},
   340  		{
   341  			str:      "2m@1ms:1d",
   342  			expected: NewStoragePolicy(2*time.Minute, 1*xtime.Millisecond, 24*time.Hour),
   343  		},
   344  	}
   345  
   346  	t.Run("marshals", func(t *testing.T) {
   347  		for _, input := range inputs {
   348  			canonical := !input.notCanonical
   349  			if canonical {
   350  				testmarshal.AssertMarshals(t, testmarshal.YAMLMarshaler, input.expected, []byte(input.str+"\n"))
   351  			}
   352  		}
   353  	})
   354  
   355  	t.Run("unmarshals", func(t *testing.T) {
   356  		for _, input := range inputs {
   357  			testmarshal.AssertUnmarshals(t, testmarshal.YAMLMarshaler, input.expected, []byte(input.str))
   358  		}
   359  	})
   360  
   361  }
   362  
   363  func TestMustParseStoragePolicy(t *testing.T) {
   364  	inputs := []struct {
   365  		str         string
   366  		shouldPanic bool
   367  		expected    StoragePolicy
   368  	}{
   369  		{
   370  			str:         "1s:1h",
   371  			shouldPanic: false,
   372  			expected:    NewStoragePolicy(time.Second, xtime.Second, time.Hour),
   373  		},
   374  		{
   375  			str:         "10seconds:1d",
   376  			shouldPanic: true,
   377  		},
   378  	}
   379  	for _, input := range inputs {
   380  		if input.shouldPanic {
   381  			require.Panics(t, func() { MustParseStoragePolicy(input.str) })
   382  		} else {
   383  			require.Equal(t, input.expected, MustParseStoragePolicy(input.str))
   384  		}
   385  	}
   386  }
   387  
   388  func TestStoragePolicyUnmarshalYAMLErrors(t *testing.T) {
   389  	inputs := []string{
   390  		"1s:1s:1s",
   391  		"10seconds:1s",
   392  		"10seconds@1s:1d",
   393  		"10s@2s:1d",
   394  		"0.1s@1s:1d",
   395  		"10s@2minutes:2d",
   396  	}
   397  	for _, input := range inputs {
   398  		var p StoragePolicy
   399  		require.Error(t, yaml.Unmarshal([]byte(input), &p))
   400  	}
   401  }
   402  
   403  func TestNewStoragePolicyFromProto(t *testing.T) {
   404  	inputs := []struct {
   405  		s *policypb.StoragePolicy
   406  		p StoragePolicy
   407  	}{
   408  		{
   409  			s: &policypb.StoragePolicy{
   410  				Resolution: policypb.Resolution{
   411  					WindowSize: int64(10 * time.Second),
   412  					Precision:  int64(time.Second),
   413  				},
   414  				Retention: policypb.Retention{
   415  					Period: int64(24 * time.Hour),
   416  				},
   417  			},
   418  			p: NewStoragePolicy(10*time.Second, xtime.Second, 24*time.Hour),
   419  		},
   420  		{
   421  			s: &policypb.StoragePolicy{
   422  				Resolution: policypb.Resolution{
   423  					WindowSize: int64(time.Minute),
   424  					Precision:  int64(time.Minute),
   425  				},
   426  				Retention: policypb.Retention{
   427  					Period: int64(240 * time.Hour),
   428  				},
   429  			},
   430  			p: NewStoragePolicy(time.Minute, xtime.Minute, 240*time.Hour),
   431  		},
   432  	}
   433  
   434  	for _, input := range inputs {
   435  		res, err := NewStoragePolicyFromProto(input.s)
   436  		require.NoError(t, err)
   437  		require.Equal(t, input.p, res)
   438  	}
   439  }
   440  
   441  func TestStoragePolicyToProto(t *testing.T) {
   442  	var pb policypb.StoragePolicy
   443  	require.NoError(t, testStoragePolicy.ToProto(&pb))
   444  	require.Equal(t, testStoragePolicyProto, pb)
   445  }
   446  
   447  func TestStoragePolicyToProtoBadStoragePolicy(t *testing.T) {
   448  	var pb policypb.StoragePolicy
   449  	require.Error(t, testBadStoragePolicy.ToProto(&pb))
   450  }
   451  
   452  func TestStoragePolicyFromProto(t *testing.T) {
   453  	var res StoragePolicy
   454  	require.NoError(t, res.FromProto(testStoragePolicyProto))
   455  	require.Equal(t, testStoragePolicy, res)
   456  }
   457  
   458  func TestStoragePolicyFromProtoNilResolution(t *testing.T) {
   459  	var res StoragePolicy
   460  	require.Equal(t, errNilResolutionProto, res.FromProto(testStoragePolicyProtoNoResolution))
   461  }
   462  
   463  func TestStoragePolicyFromProtoNilRetention(t *testing.T) {
   464  	var res StoragePolicy
   465  	require.Equal(t, errNilRetentionProto, res.FromProto(testStoragePolicyProtoNoRetention))
   466  }
   467  
   468  func TestStoragePolicyFromProtoBadPrecision(t *testing.T) {
   469  	var res StoragePolicy
   470  	require.Error(t, res.FromProto(testStoragePolicyProtoBadPrecision))
   471  }
   472  
   473  func TestStoragePolicyProtoRoundTrip(t *testing.T) {
   474  	var (
   475  		pb  policypb.StoragePolicy
   476  		res StoragePolicy
   477  	)
   478  	require.NoError(t, testStoragePolicy.ToProto(&pb))
   479  	require.NoError(t, res.FromProto(pb))
   480  	require.Equal(t, testStoragePolicy, res)
   481  }
   482  
   483  func TestStoragePoliciesJSONMarshal(t *testing.T) {
   484  	input := StoragePolicies{
   485  		NewStoragePolicy(time.Second, xtime.Second, time.Hour),
   486  		NewStoragePolicy(10*time.Second, xtime.Second, 24*time.Hour),
   487  		NewStoragePolicy(time.Minute, xtime.Minute, 24*time.Hour),
   488  	}
   489  
   490  	b, err := json.Marshal(input)
   491  	require.NoError(t, err)
   492  	expected := "[\"1s:1h\",\"10s:1d\",\"1m:1d\"]"
   493  	require.Equal(t, expected, string(b))
   494  }
   495  
   496  func TestStoragePoliciesJSONUnMarshal(t *testing.T) {
   497  	input := "[\"1s:1h\",\"10s:1d\",\"1m:1d\"]"
   498  	var storagePolicies StoragePolicies
   499  	require.NoError(t, json.Unmarshal([]byte(input), &storagePolicies))
   500  	expected := StoragePolicies{
   501  		NewStoragePolicy(time.Second, xtime.Second, time.Hour),
   502  		NewStoragePolicy(10*time.Second, xtime.Second, 24*time.Hour),
   503  		NewStoragePolicy(time.Minute, xtime.Minute, 24*time.Hour),
   504  	}
   505  	require.Equal(t, expected, storagePolicies)
   506  }
   507  
   508  func TestStoragePoliciesRoundtrip(t *testing.T) {
   509  	input := StoragePolicies{
   510  		NewStoragePolicy(time.Second, xtime.Second, time.Hour),
   511  		NewStoragePolicy(10*time.Second, xtime.Second, 24*time.Hour),
   512  		NewStoragePolicy(time.Minute, xtime.Minute, 24*time.Hour),
   513  	}
   514  
   515  	testmarshal.TestMarshalersRoundtrip(t, []StoragePolicies{input}, []testmarshal.Marshaler{testmarshal.JSONMarshaler, testmarshal.YAMLMarshaler})
   516  }
   517  
   518  func TestStoragePoliciesByResolutionAscRetentionDesc(t *testing.T) {
   519  	inputs := StoragePolicies{
   520  		NewStoragePolicy(10*time.Second, xtime.Second, 6*time.Hour),
   521  		NewStoragePolicy(10*time.Second, xtime.Second, 2*time.Hour),
   522  		NewStoragePolicy(10*time.Second, xtime.Second, 12*time.Hour),
   523  		NewStoragePolicy(5*time.Minute, xtime.Minute, 48*time.Hour),
   524  		NewStoragePolicy(time.Minute, xtime.Minute, time.Hour),
   525  		NewStoragePolicy(time.Minute, xtime.Minute, 24*time.Hour),
   526  		NewStoragePolicy(10*time.Minute, xtime.Minute, 48*time.Hour),
   527  		NewStoragePolicy(10*time.Minute, xtime.Minute, 48*time.Hour),
   528  		NewStoragePolicy(10*time.Minute, xtime.Minute, 48*time.Hour),
   529  	}
   530  	sort.Sort(ByResolutionAscRetentionDesc(inputs))
   531  
   532  	expected := StoragePolicies{
   533  		NewStoragePolicy(10*time.Second, xtime.Second, 12*time.Hour),
   534  		NewStoragePolicy(10*time.Second, xtime.Second, 6*time.Hour),
   535  		NewStoragePolicy(10*time.Second, xtime.Second, 2*time.Hour),
   536  		NewStoragePolicy(time.Minute, xtime.Minute, 24*time.Hour),
   537  		NewStoragePolicy(time.Minute, xtime.Minute, time.Hour),
   538  		NewStoragePolicy(5*time.Minute, xtime.Minute, 48*time.Hour),
   539  		NewStoragePolicy(10*time.Minute, xtime.Minute, 48*time.Hour),
   540  		NewStoragePolicy(10*time.Minute, xtime.Minute, 48*time.Hour),
   541  		NewStoragePolicy(10*time.Minute, xtime.Minute, 48*time.Hour),
   542  	}
   543  	require.Equal(t, expected, inputs)
   544  }
   545  
   546  func TestStoragePoliciesByRetentionAscResolutionAsc(t *testing.T) {
   547  	inputs := StoragePolicies{
   548  		NewStoragePolicy(10*time.Second, xtime.Second, 6*time.Hour),
   549  		NewStoragePolicy(10*time.Second, xtime.Second, 2*time.Hour),
   550  		NewStoragePolicy(10*time.Second, xtime.Second, 12*time.Hour),
   551  		NewStoragePolicy(5*time.Minute, xtime.Minute, 48*time.Hour),
   552  		NewStoragePolicy(time.Minute, xtime.Minute, time.Hour),
   553  		NewStoragePolicy(time.Minute, xtime.Minute, 24*time.Hour),
   554  		NewStoragePolicy(10*time.Minute, xtime.Minute, 48*time.Hour),
   555  		NewStoragePolicy(10*time.Minute, xtime.Minute, 48*time.Hour),
   556  		NewStoragePolicy(10*time.Second, xtime.Minute, 12*time.Hour),
   557  		NewStoragePolicy(10*time.Minute, xtime.Minute, 48*time.Hour),
   558  		NewStoragePolicy(11*time.Second, xtime.Second, 2*time.Hour),
   559  	}
   560  	sort.Sort(ByRetentionAscResolutionAsc(inputs))
   561  
   562  	expected := StoragePolicies{
   563  		NewStoragePolicy(time.Minute, xtime.Minute, time.Hour),
   564  		NewStoragePolicy(10*time.Second, xtime.Second, 2*time.Hour),
   565  		NewStoragePolicy(11*time.Second, xtime.Second, 2*time.Hour),
   566  		NewStoragePolicy(10*time.Second, xtime.Second, 6*time.Hour),
   567  		NewStoragePolicy(10*time.Second, xtime.Second, 12*time.Hour),
   568  		NewStoragePolicy(10*time.Second, xtime.Minute, 12*time.Hour),
   569  		NewStoragePolicy(time.Minute, xtime.Minute, 24*time.Hour),
   570  		NewStoragePolicy(5*time.Minute, xtime.Minute, 48*time.Hour),
   571  		NewStoragePolicy(10*time.Minute, xtime.Minute, 48*time.Hour),
   572  		NewStoragePolicy(10*time.Minute, xtime.Minute, 48*time.Hour),
   573  		NewStoragePolicy(10*time.Minute, xtime.Minute, 48*time.Hour),
   574  	}
   575  	require.Equal(t, expected, inputs)
   576  }