k8s.io/kubernetes@v1.29.3/pkg/util/hash/hash_test.go (about) 1 /* 2 Copyright 2015 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 hash 18 19 import ( 20 "fmt" 21 "hash/adler32" 22 "testing" 23 24 "k8s.io/apimachinery/pkg/util/dump" 25 ) 26 27 type A struct { 28 x int 29 y string 30 } 31 32 type B struct { 33 x []int 34 y map[string]bool 35 } 36 37 type C struct { 38 x int 39 y string 40 } 41 42 func (c C) String() string { 43 return fmt.Sprintf("%d:%s", c.x, c.y) 44 } 45 46 func TestDeepHashObject(t *testing.T) { 47 successCases := []func() interface{}{ 48 func() interface{} { return 8675309 }, 49 func() interface{} { return "Jenny, I got your number" }, 50 func() interface{} { return []string{"eight", "six", "seven"} }, 51 func() interface{} { return [...]int{5, 3, 0, 9} }, 52 func() interface{} { return map[int]string{8: "8", 6: "6", 7: "7"} }, 53 func() interface{} { return map[string]int{"5": 5, "3": 3, "0": 0, "9": 9} }, 54 func() interface{} { return A{867, "5309"} }, 55 func() interface{} { return &A{867, "5309"} }, 56 func() interface{} { 57 return B{[]int{8, 6, 7}, map[string]bool{"5": true, "3": true, "0": true, "9": true}} 58 }, 59 func() interface{} { return map[A]bool{{8675309, "Jenny"}: true, {9765683, "!Jenny"}: false} }, 60 func() interface{} { return map[C]bool{{8675309, "Jenny"}: true, {9765683, "!Jenny"}: false} }, 61 func() interface{} { return map[*A]bool{{8675309, "Jenny"}: true, {9765683, "!Jenny"}: false} }, 62 func() interface{} { return map[*C]bool{{8675309, "Jenny"}: true, {9765683, "!Jenny"}: false} }, 63 } 64 65 for _, tc := range successCases { 66 hasher1 := adler32.New() 67 DeepHashObject(hasher1, tc()) 68 hash1 := hasher1.Sum32() 69 DeepHashObject(hasher1, tc()) 70 hash2 := hasher1.Sum32() 71 if hash1 != hash2 { 72 t.Fatalf("hash of the same object (%q) produced different results: %d vs %d", toString(tc()), hash1, hash2) 73 } 74 for i := 0; i < 100; i++ { 75 hasher2 := adler32.New() 76 77 DeepHashObject(hasher1, tc()) 78 hash1a := hasher1.Sum32() 79 DeepHashObject(hasher2, tc()) 80 hash2a := hasher2.Sum32() 81 82 if hash1a != hash1 { 83 t.Errorf("repeated hash of the same object (%q) produced different results: %d vs %d", toString(tc()), hash1, hash1a) 84 } 85 if hash2a != hash2 { 86 t.Errorf("repeated hash of the same object (%q) produced different results: %d vs %d", toString(tc()), hash2, hash2a) 87 } 88 if hash1a != hash2a { 89 t.Errorf("hash of the same object produced (%q) different results: %d vs %d", toString(tc()), hash1a, hash2a) 90 } 91 } 92 } 93 } 94 95 func toString(obj interface{}) string { 96 return dump.Pretty(obj) 97 } 98 99 type wheel struct { 100 radius uint32 101 } 102 103 type unicycle struct { 104 primaryWheel *wheel 105 licencePlateID string 106 tags map[string]string 107 } 108 109 func TestDeepObjectPointer(t *testing.T) { 110 // Arrange 111 wheel1 := wheel{radius: 17} 112 wheel2 := wheel{radius: 22} 113 wheel3 := wheel{radius: 17} 114 115 myUni1 := unicycle{licencePlateID: "blah", primaryWheel: &wheel1, tags: map[string]string{"color": "blue", "name": "john"}} 116 myUni2 := unicycle{licencePlateID: "blah", primaryWheel: &wheel2, tags: map[string]string{"color": "blue", "name": "john"}} 117 myUni3 := unicycle{licencePlateID: "blah", primaryWheel: &wheel3, tags: map[string]string{"color": "blue", "name": "john"}} 118 119 // Run it more than once to verify determinism of hasher. 120 for i := 0; i < 100; i++ { 121 hasher1 := adler32.New() 122 hasher2 := adler32.New() 123 hasher3 := adler32.New() 124 // Act 125 DeepHashObject(hasher1, myUni1) 126 hash1 := hasher1.Sum32() 127 DeepHashObject(hasher1, myUni1) 128 hash1a := hasher1.Sum32() 129 DeepHashObject(hasher2, myUni2) 130 hash2 := hasher2.Sum32() 131 DeepHashObject(hasher3, myUni3) 132 hash3 := hasher3.Sum32() 133 134 // Assert 135 if hash1 != hash1a { 136 t.Errorf("repeated hash of the same object produced different results: %d vs %d", hash1, hash1a) 137 } 138 139 if hash1 == hash2 { 140 t.Errorf("hash1 (%d) and hash2(%d) must be different because they have different values for wheel size", hash1, hash2) 141 } 142 143 if hash1 != hash3 { 144 t.Errorf("hash1 (%d) and hash3(%d) must be the same because although they point to different objects, they have the same values for wheel size", hash1, hash3) 145 } 146 } 147 }