k8s.io/apiserver@v0.31.1/pkg/quota/v1/resources_test.go (about)

     1  /*
     2  Copyright 2016 The Kubernetes 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 v1
    18  
    19  import (
    20  	"reflect"
    21  	"testing"
    22  
    23  	corev1 "k8s.io/api/core/v1"
    24  	"k8s.io/apimachinery/pkg/api/resource"
    25  )
    26  
    27  func TestEquals(t *testing.T) {
    28  	testCases := map[string]struct {
    29  		a        corev1.ResourceList
    30  		b        corev1.ResourceList
    31  		expected bool
    32  	}{
    33  		"isEqual": {
    34  			a:        corev1.ResourceList{},
    35  			b:        corev1.ResourceList{},
    36  			expected: true,
    37  		},
    38  		"isEqualWithKeys": {
    39  			a: corev1.ResourceList{
    40  				corev1.ResourceCPU:    resource.MustParse("100m"),
    41  				corev1.ResourceMemory: resource.MustParse("1Gi"),
    42  			},
    43  			b: corev1.ResourceList{
    44  				corev1.ResourceCPU:    resource.MustParse("100m"),
    45  				corev1.ResourceMemory: resource.MustParse("1Gi"),
    46  			},
    47  			expected: true,
    48  		},
    49  		"isNotEqualSameKeys": {
    50  			a: corev1.ResourceList{
    51  				corev1.ResourceCPU:    resource.MustParse("200m"),
    52  				corev1.ResourceMemory: resource.MustParse("1Gi"),
    53  			},
    54  			b: corev1.ResourceList{
    55  				corev1.ResourceCPU:    resource.MustParse("100m"),
    56  				corev1.ResourceMemory: resource.MustParse("1Gi"),
    57  			},
    58  			expected: false,
    59  		},
    60  		"isNotEqualDiffKeys": {
    61  			a: corev1.ResourceList{
    62  				corev1.ResourceCPU:    resource.MustParse("100m"),
    63  				corev1.ResourceMemory: resource.MustParse("1Gi"),
    64  			},
    65  			b: corev1.ResourceList{
    66  				corev1.ResourceCPU:    resource.MustParse("100m"),
    67  				corev1.ResourceMemory: resource.MustParse("1Gi"),
    68  				corev1.ResourcePods:   resource.MustParse("1"),
    69  			},
    70  			expected: false,
    71  		},
    72  	}
    73  	for testName, testCase := range testCases {
    74  		if result := Equals(testCase.a, testCase.b); result != testCase.expected {
    75  			t.Errorf("%s expected: %v, actual: %v, a=%v, b=%v", testName, testCase.expected, result, testCase.a, testCase.b)
    76  		}
    77  	}
    78  }
    79  
    80  func TestLessThanOrEqual(t *testing.T) {
    81  	testCases := map[string]struct {
    82  		a        corev1.ResourceList
    83  		b        corev1.ResourceList
    84  		expected bool
    85  		out      []corev1.ResourceName
    86  	}{
    87  		"isEmpty": {
    88  			a:        corev1.ResourceList{},
    89  			b:        corev1.ResourceList{},
    90  			expected: true,
    91  			out:      []corev1.ResourceName{},
    92  		},
    93  		"isEqual": {
    94  			a:        corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
    95  			b:        corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
    96  			expected: true,
    97  			out:      []corev1.ResourceName{},
    98  		},
    99  		"isLessThan": {
   100  			a:        corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
   101  			b:        corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("200m")},
   102  			expected: true,
   103  			out:      []corev1.ResourceName{},
   104  		},
   105  		"isGreaterThan": {
   106  			a:        corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("200m")},
   107  			b:        corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
   108  			expected: false,
   109  			out:      []corev1.ResourceName{corev1.ResourceCPU},
   110  		},
   111  	}
   112  	for testName, testCase := range testCases {
   113  		if result, out := LessThanOrEqual(testCase.a, testCase.b); result != testCase.expected && !reflect.DeepEqual(out, testCase.out) {
   114  			t.Errorf("%s expected: %v/%v, actual: %v/%v", testName, testCase.expected, testCase.out, result, out)
   115  		}
   116  	}
   117  }
   118  
   119  func TestMax(t *testing.T) {
   120  	testCases := map[string]struct {
   121  		a        corev1.ResourceList
   122  		b        corev1.ResourceList
   123  		expected corev1.ResourceList
   124  	}{
   125  		"noKeys": {
   126  			a:        corev1.ResourceList{},
   127  			b:        corev1.ResourceList{},
   128  			expected: corev1.ResourceList{},
   129  		},
   130  		"toEmpty": {
   131  			a:        corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
   132  			b:        corev1.ResourceList{},
   133  			expected: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
   134  		},
   135  		"matching": {
   136  			a:        corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
   137  			b:        corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("150m")},
   138  			expected: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("150m")},
   139  		},
   140  		"matching(reverse)": {
   141  			a:        corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("150m")},
   142  			b:        corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
   143  			expected: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("150m")},
   144  		},
   145  		"matching-equal": {
   146  			a:        corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
   147  			b:        corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
   148  			expected: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
   149  		},
   150  	}
   151  	for testName, testCase := range testCases {
   152  		sum := Max(testCase.a, testCase.b)
   153  		if result := Equals(testCase.expected, sum); !result {
   154  			t.Errorf("%s expected: %v, actual: %v", testName, testCase.expected, sum)
   155  		}
   156  	}
   157  }
   158  
   159  func TestAdd(t *testing.T) {
   160  	testCases := map[string]struct {
   161  		a        corev1.ResourceList
   162  		b        corev1.ResourceList
   163  		expected corev1.ResourceList
   164  	}{
   165  		"noKeys": {
   166  			a:        corev1.ResourceList{},
   167  			b:        corev1.ResourceList{},
   168  			expected: corev1.ResourceList{},
   169  		},
   170  		"toEmpty": {
   171  			a:        corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
   172  			b:        corev1.ResourceList{},
   173  			expected: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
   174  		},
   175  		"matching": {
   176  			a:        corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
   177  			b:        corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
   178  			expected: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("200m")},
   179  		},
   180  	}
   181  	for testName, testCase := range testCases {
   182  		sum := Add(testCase.a, testCase.b)
   183  		if result := Equals(testCase.expected, sum); !result {
   184  			t.Errorf("%s expected: %v, actual: %v", testName, testCase.expected, sum)
   185  		}
   186  	}
   187  }
   188  
   189  func TestSubtract(t *testing.T) {
   190  	testCases := map[string]struct {
   191  		a        corev1.ResourceList
   192  		b        corev1.ResourceList
   193  		expected corev1.ResourceList
   194  	}{
   195  		"noKeys": {
   196  			a:        corev1.ResourceList{},
   197  			b:        corev1.ResourceList{},
   198  			expected: corev1.ResourceList{},
   199  		},
   200  		"value-empty": {
   201  			a:        corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
   202  			b:        corev1.ResourceList{},
   203  			expected: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
   204  		},
   205  		"empty-value": {
   206  			a:        corev1.ResourceList{},
   207  			b:        corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
   208  			expected: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("-100m")},
   209  		},
   210  		"value-value": {
   211  			a:        corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("200m")},
   212  			b:        corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
   213  			expected: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")},
   214  		},
   215  	}
   216  	for testName, testCase := range testCases {
   217  		sub := Subtract(testCase.a, testCase.b)
   218  		if result := Equals(testCase.expected, sub); !result {
   219  			t.Errorf("%s expected: %v, actual: %v", testName, testCase.expected, sub)
   220  		}
   221  	}
   222  }
   223  
   224  func TestResourceNames(t *testing.T) {
   225  	testCases := map[string]struct {
   226  		a        corev1.ResourceList
   227  		expected []corev1.ResourceName
   228  	}{
   229  		"empty": {
   230  			a:        corev1.ResourceList{},
   231  			expected: []corev1.ResourceName{},
   232  		},
   233  		"values": {
   234  			a: corev1.ResourceList{
   235  				corev1.ResourceCPU:    resource.MustParse("100m"),
   236  				corev1.ResourceMemory: resource.MustParse("1Gi"),
   237  			},
   238  			expected: []corev1.ResourceName{corev1.ResourceMemory, corev1.ResourceCPU},
   239  		},
   240  	}
   241  	for testName, testCase := range testCases {
   242  		actualSet := ToSet(ResourceNames(testCase.a))
   243  		expectedSet := ToSet(testCase.expected)
   244  		if !actualSet.Equal(expectedSet) {
   245  			t.Errorf("%s expected: %v, actual: %v", testName, expectedSet, actualSet)
   246  		}
   247  	}
   248  }
   249  
   250  func TestContains(t *testing.T) {
   251  	testCases := map[string]struct {
   252  		a        []corev1.ResourceName
   253  		b        corev1.ResourceName
   254  		expected bool
   255  	}{
   256  		"does-not-contain": {
   257  			a:        []corev1.ResourceName{corev1.ResourceMemory},
   258  			b:        corev1.ResourceCPU,
   259  			expected: false,
   260  		},
   261  		"does-contain": {
   262  			a:        []corev1.ResourceName{corev1.ResourceMemory, corev1.ResourceCPU},
   263  			b:        corev1.ResourceCPU,
   264  			expected: true,
   265  		},
   266  	}
   267  	for testName, testCase := range testCases {
   268  		if actual := Contains(testCase.a, testCase.b); actual != testCase.expected {
   269  			t.Errorf("%s expected: %v, actual: %v", testName, testCase.expected, actual)
   270  		}
   271  	}
   272  }
   273  
   274  func TestContainsPrefix(t *testing.T) {
   275  	testCases := map[string]struct {
   276  		a        []string
   277  		b        corev1.ResourceName
   278  		expected bool
   279  	}{
   280  		"does-not-contain": {
   281  			a:        []string{corev1.ResourceHugePagesPrefix},
   282  			b:        corev1.ResourceCPU,
   283  			expected: false,
   284  		},
   285  		"does-contain": {
   286  			a:        []string{corev1.ResourceHugePagesPrefix},
   287  			b:        corev1.ResourceName(corev1.ResourceHugePagesPrefix + "2Mi"),
   288  			expected: true,
   289  		},
   290  	}
   291  	for testName, testCase := range testCases {
   292  		if actual := ContainsPrefix(testCase.a, testCase.b); actual != testCase.expected {
   293  			t.Errorf("%s expected: %v, actual: %v", testName, testCase.expected, actual)
   294  		}
   295  	}
   296  }
   297  
   298  func TestIsZero(t *testing.T) {
   299  	testCases := map[string]struct {
   300  		a        corev1.ResourceList
   301  		expected bool
   302  	}{
   303  		"empty": {
   304  			a:        corev1.ResourceList{},
   305  			expected: true,
   306  		},
   307  		"zero": {
   308  			a: corev1.ResourceList{
   309  				corev1.ResourceCPU:    resource.MustParse("0"),
   310  				corev1.ResourceMemory: resource.MustParse("0"),
   311  			},
   312  			expected: true,
   313  		},
   314  		"non-zero": {
   315  			a: corev1.ResourceList{
   316  				corev1.ResourceCPU:    resource.MustParse("200m"),
   317  				corev1.ResourceMemory: resource.MustParse("1Gi"),
   318  			},
   319  			expected: false,
   320  		},
   321  	}
   322  	for testName, testCase := range testCases {
   323  		if result := IsZero(testCase.a); result != testCase.expected {
   324  			t.Errorf("%s expected: %v, actual: %v", testName, testCase.expected, result)
   325  		}
   326  	}
   327  }
   328  
   329  func TestRemoveZeros(t *testing.T) {
   330  	testCases := map[string]struct {
   331  		a        corev1.ResourceList
   332  		expected corev1.ResourceList
   333  	}{
   334  		"empty": {
   335  			a:        corev1.ResourceList{},
   336  			expected: corev1.ResourceList{},
   337  		},
   338  		"all-zeros": {
   339  			a: corev1.ResourceList{
   340  				corev1.ResourceCPU:    resource.MustParse("0"),
   341  				corev1.ResourceMemory: resource.MustParse("0"),
   342  			},
   343  			expected: corev1.ResourceList{},
   344  		},
   345  		"some-zeros": {
   346  			a: corev1.ResourceList{
   347  				corev1.ResourceCPU:     resource.MustParse("0"),
   348  				corev1.ResourceMemory:  resource.MustParse("0"),
   349  				corev1.ResourceStorage: resource.MustParse("100Gi"),
   350  			},
   351  			expected: corev1.ResourceList{
   352  				corev1.ResourceStorage: resource.MustParse("100Gi"),
   353  			},
   354  		},
   355  		"non-zero": {
   356  			a: corev1.ResourceList{
   357  				corev1.ResourceCPU:    resource.MustParse("200m"),
   358  				corev1.ResourceMemory: resource.MustParse("1Gi"),
   359  			},
   360  			expected: corev1.ResourceList{
   361  				corev1.ResourceCPU:    resource.MustParse("200m"),
   362  				corev1.ResourceMemory: resource.MustParse("1Gi"),
   363  			},
   364  		},
   365  	}
   366  	for testName, testCase := range testCases {
   367  		if result := RemoveZeros(testCase.a); !Equals(result, testCase.expected) {
   368  			t.Errorf("%s expected: %v, actual: %v", testName, testCase.expected, result)
   369  		}
   370  	}
   371  }
   372  
   373  func TestIsNegative(t *testing.T) {
   374  	testCases := map[string]struct {
   375  		a        corev1.ResourceList
   376  		expected []corev1.ResourceName
   377  	}{
   378  		"empty": {
   379  			a:        corev1.ResourceList{},
   380  			expected: []corev1.ResourceName{},
   381  		},
   382  		"some-negative": {
   383  			a: corev1.ResourceList{
   384  				corev1.ResourceCPU:    resource.MustParse("-10"),
   385  				corev1.ResourceMemory: resource.MustParse("0"),
   386  			},
   387  			expected: []corev1.ResourceName{corev1.ResourceCPU},
   388  		},
   389  		"all-negative": {
   390  			a: corev1.ResourceList{
   391  				corev1.ResourceCPU:    resource.MustParse("-200m"),
   392  				corev1.ResourceMemory: resource.MustParse("-1Gi"),
   393  			},
   394  			expected: []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceMemory},
   395  		},
   396  	}
   397  	for testName, testCase := range testCases {
   398  		actual := IsNegative(testCase.a)
   399  		actualSet := ToSet(actual)
   400  		expectedSet := ToSet(testCase.expected)
   401  		if !actualSet.Equal(expectedSet) {
   402  			t.Errorf("%s expected: %v, actual: %v", testName, expectedSet, actualSet)
   403  		}
   404  	}
   405  }
   406  
   407  func TestIntersection(t *testing.T) {
   408  	testCases := map[string]struct {
   409  		a        []corev1.ResourceName
   410  		b        []corev1.ResourceName
   411  		expected []corev1.ResourceName
   412  	}{
   413  		"empty": {
   414  			a:        []corev1.ResourceName{},
   415  			b:        []corev1.ResourceName{},
   416  			expected: []corev1.ResourceName{},
   417  		},
   418  		"equal": {
   419  			a:        []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceMemory},
   420  			b:        []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceMemory},
   421  			expected: []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceMemory},
   422  		},
   423  		"a has extra": {
   424  			a:        []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceMemory},
   425  			b:        []corev1.ResourceName{corev1.ResourceCPU},
   426  			expected: []corev1.ResourceName{corev1.ResourceCPU},
   427  		},
   428  		"b has extra": {
   429  			a:        []corev1.ResourceName{corev1.ResourceCPU},
   430  			b:        []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceMemory},
   431  			expected: []corev1.ResourceName{corev1.ResourceCPU},
   432  		},
   433  		"dedupes": {
   434  			a:        []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceCPU, corev1.ResourceMemory, corev1.ResourceMemory},
   435  			b:        []corev1.ResourceName{corev1.ResourceCPU},
   436  			expected: []corev1.ResourceName{corev1.ResourceCPU},
   437  		},
   438  		"sorts": {
   439  			a:        []corev1.ResourceName{corev1.ResourceMemory, corev1.ResourceMemory, corev1.ResourceCPU, corev1.ResourceCPU},
   440  			b:        []corev1.ResourceName{corev1.ResourceMemory, corev1.ResourceMemory, corev1.ResourceCPU, corev1.ResourceCPU},
   441  			expected: []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceMemory},
   442  		},
   443  	}
   444  	for testName, testCase := range testCases {
   445  		actual := Intersection(testCase.a, testCase.b)
   446  		if !reflect.DeepEqual(actual, testCase.expected) {
   447  			t.Errorf("%s expected: %#v, actual: %#v", testName, testCase.expected, actual)
   448  		}
   449  	}
   450  }
   451  
   452  func TestDifference(t *testing.T) {
   453  	testCases := map[string]struct {
   454  		a        []corev1.ResourceName
   455  		b        []corev1.ResourceName
   456  		expected []corev1.ResourceName
   457  	}{
   458  		"empty": {
   459  			a:        []corev1.ResourceName{},
   460  			b:        []corev1.ResourceName{},
   461  			expected: []corev1.ResourceName{},
   462  		},
   463  		"equal": {
   464  			a:        []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceMemory},
   465  			b:        []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceMemory},
   466  			expected: []corev1.ResourceName{},
   467  		},
   468  		"a has extra": {
   469  			a:        []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceMemory},
   470  			b:        []corev1.ResourceName{corev1.ResourceCPU},
   471  			expected: []corev1.ResourceName{corev1.ResourceMemory},
   472  		},
   473  		"b has extra": {
   474  			a:        []corev1.ResourceName{corev1.ResourceCPU},
   475  			b:        []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceMemory},
   476  			expected: []corev1.ResourceName{},
   477  		},
   478  		"dedupes": {
   479  			a:        []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceCPU, corev1.ResourceMemory, corev1.ResourceMemory},
   480  			b:        []corev1.ResourceName{corev1.ResourceCPU},
   481  			expected: []corev1.ResourceName{corev1.ResourceMemory},
   482  		},
   483  		"sorts": {
   484  			a:        []corev1.ResourceName{corev1.ResourceMemory, corev1.ResourceMemory, corev1.ResourceCPU, corev1.ResourceCPU},
   485  			b:        []corev1.ResourceName{},
   486  			expected: []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceMemory},
   487  		},
   488  	}
   489  	for testName, testCase := range testCases {
   490  		actual := Difference(testCase.a, testCase.b)
   491  		if !reflect.DeepEqual(actual, testCase.expected) {
   492  			t.Errorf("%s expected: %#v, actual: %#v", testName, testCase.expected, actual)
   493  		}
   494  	}
   495  }