github.com/kubewharf/katalyst-core@v0.5.3/pkg/util/general/window_test.go (about)

     1  /*
     2  Copyright 2022 The Katalyst Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package general
    18  
    19  import (
    20  	"testing"
    21  	"time"
    22  
    23  	"github.com/stretchr/testify/assert"
    24  	"github.com/stretchr/testify/require"
    25  	"k8s.io/apimachinery/pkg/api/resource"
    26  )
    27  
    28  func TestNewCappedSmoothWindow(t *testing.T) {
    29  	t.Parallel()
    30  
    31  	type args struct {
    32  		minStep      resource.Quantity
    33  		maxStep      resource.Quantity
    34  		smoothWindow SmoothWindow
    35  	}
    36  	tests := []struct {
    37  		name string
    38  		args args
    39  	}{
    40  		{
    41  			name: "test-cpu",
    42  			args: args{
    43  				minStep:      resource.MustParse("0.3"),
    44  				maxStep:      resource.MustParse("4"),
    45  				smoothWindow: NewAggregatorSmoothWindow(SmoothWindowOpts{WindowSize: 5, TTL: 100 * time.Millisecond, UsedMillValue: true, AggregateFunc: SmoothWindowAggFuncAvg}),
    46  			},
    47  		},
    48  		{
    49  			name: "test-memory",
    50  			args: args{
    51  				minStep:      resource.MustParse("300Mi"),
    52  				maxStep:      resource.MustParse("5Gi"),
    53  				smoothWindow: NewAggregatorSmoothWindow(SmoothWindowOpts{WindowSize: 5, TTL: 100 * time.Millisecond, UsedMillValue: false, AggregateFunc: SmoothWindowAggFuncAvg}),
    54  			},
    55  		},
    56  	}
    57  	for _, tt := range tests {
    58  		tt := tt
    59  		t.Run(tt.name, func(t *testing.T) {
    60  			t.Parallel()
    61  			NewCappedSmoothWindow(tt.args.minStep, tt.args.maxStep, tt.args.smoothWindow)
    62  		})
    63  	}
    64  }
    65  
    66  func TestCappedSmoothWindow_GetWindowedResources(t *testing.T) {
    67  	t.Parallel()
    68  
    69  	w := NewCappedSmoothWindow(
    70  		resource.MustParse("0.3"),
    71  		resource.MustParse("4"),
    72  		NewAggregatorSmoothWindow(SmoothWindowOpts{WindowSize: 3, TTL: 100 * time.Millisecond, UsedMillValue: true, AggregateFunc: SmoothWindowAggFuncAvg}),
    73  	)
    74  
    75  	time.Sleep(10 * time.Millisecond)
    76  	v := w.GetWindowedResources(resource.MustParse("0.6"))
    77  	require.Nil(t, v)
    78  
    79  	time.Sleep(10 * time.Millisecond)
    80  	v = w.GetWindowedResources(resource.MustParse("0.8"))
    81  	require.Nil(t, v)
    82  
    83  	time.Sleep(10 * time.Millisecond)
    84  	v = w.GetWindowedResources(resource.MustParse("0.4"))
    85  	require.NotNil(t, v)
    86  	require.Zero(t, v.Cmp(resource.MustParse("0.6")))
    87  
    88  	time.Sleep(10 * time.Millisecond)
    89  	v = w.GetWindowedResources(resource.MustParse("1.2"))
    90  	require.NotNil(t, v)
    91  	require.True(t, resource.MustParse("0.6").Equal(*v))
    92  
    93  	time.Sleep(10 * time.Millisecond)
    94  	v = w.GetWindowedResources(resource.MustParse("1.4"))
    95  	require.NotNil(t, v)
    96  	require.Equal(t, int64(1000), v.MilliValue())
    97  
    98  	time.Sleep(10 * time.Millisecond)
    99  	v = w.GetWindowedResources(resource.MustParse("15"))
   100  	require.NotNil(t, v)
   101  	require.Equal(t, int64(5000), v.MilliValue())
   102  
   103  	time.Sleep(90 * time.Millisecond)
   104  	v = w.GetWindowedResources(resource.MustParse("0"))
   105  	require.NotNil(t, v)
   106  	require.Equal(t, int64(5000), v.MilliValue())
   107  
   108  	time.Sleep(10 * time.Millisecond)
   109  	v = w.GetWindowedResources(resource.MustParse("0"))
   110  	require.NotNil(t, v)
   111  	require.Equal(t, int64(5000), v.MilliValue())
   112  
   113  	time.Sleep(30 * time.Millisecond)
   114  	v = w.GetWindowedResources(resource.MustParse("0"))
   115  	require.NotNil(t, v)
   116  	require.Equal(t, int64(1000), v.MilliValue())
   117  }
   118  
   119  func TestPercentileWithTTLSmoothWindow(t *testing.T) {
   120  	t.Parallel()
   121  
   122  	type args struct {
   123  		windowSize int
   124  		ttl        time.Duration
   125  		percentile float64
   126  		values     []resource.Quantity
   127  	}
   128  	tests := []struct {
   129  		name       string
   130  		args       args
   131  		wantValues []resource.Quantity
   132  	}{
   133  		{
   134  			name: "p100(max)",
   135  			args: args{
   136  				windowSize: 5,
   137  				ttl:        1 * time.Second,
   138  				percentile: 100,
   139  				values: []resource.Quantity{
   140  					resource.MustParse("1"),
   141  					resource.MustParse("2"),
   142  					resource.MustParse("1.5"),
   143  					resource.MustParse("3"),
   144  					resource.MustParse("2"),
   145  					resource.MustParse("6"),
   146  					resource.MustParse("5"),
   147  					resource.MustParse("1"),
   148  					resource.MustParse("1"),
   149  					resource.MustParse("1"),
   150  					resource.MustParse("1"),
   151  					resource.MustParse("1"),
   152  				},
   153  			},
   154  			wantValues: []resource.Quantity{
   155  				resource.MustParse("0"),
   156  				resource.MustParse("0"),
   157  				resource.MustParse("0"),
   158  				resource.MustParse("0"),
   159  				resource.MustParse("3"),
   160  				resource.MustParse("6"),
   161  				resource.MustParse("6"),
   162  				resource.MustParse("6"),
   163  				resource.MustParse("6"),
   164  				resource.MustParse("6"),
   165  				resource.MustParse("5"),
   166  				resource.MustParse("1"),
   167  			},
   168  		},
   169  		{
   170  			name: "p0(min)",
   171  			args: args{
   172  				windowSize: 5,
   173  				ttl:        1 * time.Second,
   174  				percentile: 0.0,
   175  				values: []resource.Quantity{
   176  					resource.MustParse("1"),
   177  					resource.MustParse("2"),
   178  					resource.MustParse("1.5"),
   179  					resource.MustParse("3"),
   180  					resource.MustParse("2"),
   181  					resource.MustParse("6"),
   182  					resource.MustParse("5"),
   183  					resource.MustParse("1"),
   184  					resource.MustParse("1"),
   185  					resource.MustParse("1"),
   186  					resource.MustParse("1"),
   187  					resource.MustParse("1"),
   188  				},
   189  			},
   190  			wantValues: []resource.Quantity{
   191  				resource.MustParse("0"),
   192  				resource.MustParse("0"),
   193  				resource.MustParse("0"),
   194  				resource.MustParse("0"),
   195  				resource.MustParse("1"),
   196  				resource.MustParse("1.5"),
   197  				resource.MustParse("1.5"),
   198  				resource.MustParse("1"),
   199  				resource.MustParse("1"),
   200  				resource.MustParse("1"),
   201  				resource.MustParse("1"),
   202  				resource.MustParse("1"),
   203  			},
   204  		},
   205  		{
   206  			name: "p20",
   207  			args: args{
   208  				windowSize: 10,
   209  				ttl:        111111 * time.Second,
   210  				percentile: 20,
   211  				values: []resource.Quantity{
   212  					resource.MustParse("1"),
   213  					resource.MustParse("2"),
   214  					resource.MustParse("3"),
   215  					resource.MustParse("4"),
   216  					resource.MustParse("5"),
   217  					resource.MustParse("6"),
   218  					resource.MustParse("7"),
   219  					resource.MustParse("8"),
   220  					resource.MustParse("9"),
   221  					resource.MustParse("10"),
   222  					resource.MustParse("11"),
   223  					resource.MustParse("12"),
   224  				},
   225  			},
   226  			wantValues: []resource.Quantity{
   227  				resource.MustParse("0"),
   228  				resource.MustParse("0"),
   229  				resource.MustParse("0"),
   230  				resource.MustParse("0"),
   231  				resource.MustParse("0"),
   232  				resource.MustParse("0"),
   233  				resource.MustParse("0"),
   234  				resource.MustParse("0"),
   235  				resource.MustParse("0"),
   236  				resource.MustParse("2"),
   237  				resource.MustParse("3"),
   238  				resource.MustParse("4"),
   239  			},
   240  		},
   241  	}
   242  	for _, tt := range tests {
   243  		tt := tt
   244  		t.Run(tt.name, func(t *testing.T) {
   245  			t.Parallel()
   246  			w := NewPercentileWithTTLSmoothWindow(tt.args.windowSize, tt.args.ttl, tt.args.percentile, true)
   247  			for i, v := range tt.args.values {
   248  				ret := w.GetWindowedResources(v)
   249  				if ret == nil {
   250  					require.Equal(t, tt.wantValues[i].MilliValue(), int64(0))
   251  				} else {
   252  					require.Equal(t, tt.wantValues[i].MilliValue(), ret.MilliValue())
   253  				}
   254  			}
   255  		})
   256  	}
   257  }
   258  
   259  func TestWindowEmpty(t *testing.T) {
   260  	t.Parallel()
   261  
   262  	type args struct {
   263  		windowSize int
   264  		ttl        time.Duration
   265  		percentile float64
   266  		samples    []*sample
   267  	}
   268  	tests := []struct {
   269  		name string
   270  		args args
   271  		want bool
   272  	}{
   273  		{
   274  			name: "empty",
   275  			args: args{
   276  				windowSize: 10,
   277  				ttl:        111111 * time.Second,
   278  				percentile: 20,
   279  				samples:    []*sample{},
   280  			},
   281  			want: true,
   282  		},
   283  		{
   284  			name: "samples all expired",
   285  			args: args{
   286  				windowSize: 10,
   287  				ttl:        111111 * time.Second,
   288  				percentile: 20,
   289  				samples: []*sample{
   290  					{
   291  						resource.MustParse("1"),
   292  						time.Date(2000, 0, 0, 0, 0, 0, 0, time.UTC),
   293  					},
   294  				},
   295  			},
   296  			want: true,
   297  		},
   298  		{
   299  			name: "have valid sample",
   300  			args: args{
   301  				windowSize: 10,
   302  				ttl:        111111 * time.Second,
   303  				percentile: 20,
   304  				samples: []*sample{
   305  					{
   306  						resource.MustParse("1"),
   307  						time.Now(),
   308  					},
   309  				},
   310  			},
   311  			want: false,
   312  		},
   313  	}
   314  	for _, tt := range tests {
   315  		tt := tt
   316  		t.Run(tt.name, func(t *testing.T) {
   317  			t.Parallel()
   318  
   319  			w := NewPercentileWithTTLSmoothWindow(tt.args.windowSize, tt.args.ttl, tt.args.percentile, true)
   320  			window := w.(*percentileWithTTLSmoothWindow)
   321  			window.samples = tt.args.samples
   322  
   323  			assert.Equal(t, tt.want, window.Empty())
   324  			window.Empty()
   325  		})
   326  	}
   327  }