@@ -17,6 +17,7 @@ limitations under the License.
1717package v1alpha2_test
1818
1919import (
20+ "testing"
2021 "time"
2122
2223 "dario.cat/mergo"
@@ -25,105 +26,149 @@ import (
2526 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2627 karpv1 "sigs.k8s.io/karpenter/pkg/apis/v1"
2728 "sigs.k8s.io/karpenter/pkg/test"
28-
29- . "github.com/onsi/ginkgo/v2"
30- . "github.com/onsi/gomega"
3129)
3230
33- var _ = Describe ("Hash" , func () {
31+ func newHashTestNodeClassV1Alpha2 () * v1alpha2.AKSNodeClass {
32+ return & v1alpha2.AKSNodeClass {
33+ ObjectMeta : test .ObjectMeta (metav1.ObjectMeta {}),
34+ Spec : v1alpha2.AKSNodeClassSpec {
35+ VNETSubnetID : lo .ToPtr ("subnet-id" ),
36+ OSDiskSizeGB : lo .ToPtr (int32 (30 )),
37+ ImageFamily : lo .ToPtr ("Ubuntu2204" ),
38+ Tags : map [string ]string {
39+ "keyTag-1" : "valueTag-1" ,
40+ "keyTag-2" : "valueTag-2" ,
41+ },
42+ Kubelet : & v1alpha2.KubeletConfiguration {
43+ CPUManagerPolicy : lo .ToPtr ("static" ),
44+ CPUCFSQuota : lo .ToPtr (true ),
45+ CPUCFSQuotaPeriod : metav1.Duration {Duration : lo .Must (time .ParseDuration ("100ms" ))},
46+ ImageGCHighThresholdPercent : lo .ToPtr (int32 (85 )),
47+ ImageGCLowThresholdPercent : lo .ToPtr (int32 (80 )),
48+ TopologyManagerPolicy : lo .ToPtr ("none" ),
49+ AllowedUnsafeSysctls : []string {"net.core.somaxconn" },
50+ ContainerLogMaxSize : lo .ToPtr ("10Mi" ),
51+ ContainerLogMaxFiles : lo .ToPtr (int32 (10 )),
52+ },
53+ MaxPods : lo .ToPtr (int32 (100 )),
54+ },
55+ }
56+ }
57+
58+ //nolint:gocyclo
59+ func TestHash (t * testing.T ) {
3460 // NOTE: When the hashing algorithm is updated, these tests are expected to fail; test hash constants here would have to be updated, and currentHashVersion would have to be updated to the new version matching v1alpha2.AKSNodeClassHashVersion
3561 const staticHash = "4108492229247269128"
36- var nodeClass * v1alpha2.AKSNodeClass
37- BeforeEach (func () {
38- nodeClass = & v1alpha2.AKSNodeClass {
39- ObjectMeta : test .ObjectMeta (metav1.ObjectMeta {}),
40- Spec : v1alpha2.AKSNodeClassSpec {
41- VNETSubnetID : lo .ToPtr ("subnet-id" ),
42- OSDiskSizeGB : lo .ToPtr (int32 (30 )),
43- ImageFamily : lo .ToPtr ("Ubuntu2204" ),
44- Tags : map [string ]string {
45- "keyTag-1" : "valueTag-1" ,
46- "keyTag-2" : "valueTag-2" ,
47- },
48- Kubelet : & v1alpha2.KubeletConfiguration {
49- CPUManagerPolicy : lo .ToPtr ("static" ),
50- CPUCFSQuota : lo .ToPtr (true ),
51- CPUCFSQuotaPeriod : metav1.Duration {Duration : lo .Must (time .ParseDuration ("100ms" ))},
52- ImageGCHighThresholdPercent : lo .ToPtr (int32 (85 )),
53- ImageGCLowThresholdPercent : lo .ToPtr (int32 (80 )),
54- TopologyManagerPolicy : lo .ToPtr ("none" ),
55- AllowedUnsafeSysctls : []string {"net.core.somaxconn" },
56- ContainerLogMaxSize : lo .ToPtr ("10Mi" ),
57- ContainerLogMaxFiles : lo .ToPtr (int32 (10 )),
58- },
59- MaxPods : lo .ToPtr (int32 (100 )),
60- },
62+
63+ t .Run ("should match static hash on field value change" , func (t * testing.T ) {
64+ tests := []struct {
65+ name string
66+ hash string
67+ changes v1alpha2.AKSNodeClass
68+ }{
69+ {"Base AKSNodeClass" , staticHash , v1alpha2.AKSNodeClass {}},
70+ // Static fields, expect changed hash from base
71+ {"VNETSubnetID" , "13971920214979852468" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {VNETSubnetID : lo .ToPtr ("subnet-id-2" )}}},
72+ {"OSDiskSizeGB" , "7816855636861645563" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {OSDiskSizeGB : lo .ToPtr (int32 (40 ))}}},
73+ {"ImageFamily" , "15616969746300892810" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {ImageFamily : lo .ToPtr ("AzureLinux" )}}},
74+ {"Kubelet" , "33638514539106194" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {Kubelet : & v1alpha2.KubeletConfiguration {CPUManagerPolicy : lo .ToPtr ("none" )}}}},
75+ {"MaxPods" , "15508761509963240710" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {MaxPods : lo .ToPtr (int32 (200 ))}}},
76+ {"LocalDNS.Mode" , "17805442572569734619" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {LocalDNS : & v1alpha2.LocalDNS {Mode : v1alpha2 .LocalDNSModeRequired }}}},
77+ {"LocalDNS.VnetDNSOverrides" , "14608914734386108436" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {LocalDNS : & v1alpha2.LocalDNS {VnetDNSOverrides : []v1alpha2.LocalDNSZoneOverride {{Zone : "example.com" , QueryLogging : v1alpha2 .LocalDNSQueryLoggingLog }}}}}},
78+ {"LocalDNS.KubeDNSOverrides" , "4529827108104295737" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {LocalDNS : & v1alpha2.LocalDNS {KubeDNSOverrides : []v1alpha2.LocalDNSZoneOverride {{Zone : "example.com" , Protocol : v1alpha2 .LocalDNSProtocolForceTCP }}}}}},
79+ {"LocalDNS.VnetDNSOverrides.CacheDuration" , "11008649797056761238" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {LocalDNS : & v1alpha2.LocalDNS {VnetDNSOverrides : []v1alpha2.LocalDNSZoneOverride {{Zone : "example.com" , CacheDuration : karpv1 .MustParseNillableDuration ("1h" )}}}}}},
80+ {"LocalDNS.VnetDNSOverrides.ServeStaleDuration" , "4895720480850206885" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {LocalDNS : & v1alpha2.LocalDNS {VnetDNSOverrides : []v1alpha2.LocalDNSZoneOverride {{Zone : "example.com" , ServeStaleDuration : karpv1 .MustParseNillableDuration ("30m" )}}}}}},
81+ }
82+ for _ , tt := range tests {
83+ t .Run (tt .name , func (t * testing.T ) {
84+ nodeClass := newHashTestNodeClassV1Alpha2 ()
85+ if err := mergo .Merge (nodeClass , tt .changes , mergo .WithOverride , mergo .WithSliceDeepCopy ); err != nil {
86+ t .Fatalf ("mergo.Merge failed: %v" , err )
87+ }
88+ if got := nodeClass .Hash (); got != tt .hash {
89+ t .Errorf ("Hash() = %s, want %s" , got , tt .hash )
90+ }
91+ })
6192 }
6293 })
63- DescribeTable (
64- "should match static hash on field value change" ,
65- func (hash string , changes v1alpha2.AKSNodeClass ) {
66- Expect (mergo .Merge (nodeClass , changes , mergo .WithOverride , mergo .WithSliceDeepCopy )).To (Succeed ())
67- Expect (nodeClass .Hash ()).To (Equal (hash ))
68- },
69- Entry ("Base AKSNodeClass" , staticHash , v1alpha2.AKSNodeClass {}),
7094
71- // Static fields, expect changed hash from base
72- Entry ("VNETSubnetID" , "13971920214979852468" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {VNETSubnetID : lo .ToPtr ("subnet-id-2" )}}),
73- Entry ("OSDiskSizeGB" , "7816855636861645563" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {OSDiskSizeGB : lo .ToPtr (int32 (40 ))}}),
74- Entry ("ImageFamily" , "15616969746300892810" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {ImageFamily : lo .ToPtr ("AzureLinux" )}}),
75- Entry ("Kubelet" , "33638514539106194" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {Kubelet : & v1alpha2.KubeletConfiguration {CPUManagerPolicy : lo .ToPtr ("none" )}}}),
76- Entry ("MaxPods" , "15508761509963240710" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {MaxPods : lo .ToPtr (int32 (200 ))}}),
77- Entry ("LocalDNS.Mode" , "17805442572569734619" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {LocalDNS : & v1alpha2.LocalDNS {Mode : v1alpha2 .LocalDNSModeRequired }}}),
78- Entry ("LocalDNS.VnetDNSOverrides" , "14608914734386108436" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {LocalDNS : & v1alpha2.LocalDNS {VnetDNSOverrides : []v1alpha2.LocalDNSZoneOverride {{Zone : "example.com" , QueryLogging : v1alpha2 .LocalDNSQueryLoggingLog }}}}}),
79- Entry ("LocalDNS.KubeDNSOverrides" , "4529827108104295737" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {LocalDNS : & v1alpha2.LocalDNS {KubeDNSOverrides : []v1alpha2.LocalDNSZoneOverride {{Zone : "example.com" , Protocol : v1alpha2 .LocalDNSProtocolForceTCP }}}}}),
80- Entry ("LocalDNS.VnetDNSOverrides.CacheDuration" , "11008649797056761238" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {LocalDNS : & v1alpha2.LocalDNS {VnetDNSOverrides : []v1alpha2.LocalDNSZoneOverride {{Zone : "example.com" , CacheDuration : karpv1 .MustParseNillableDuration ("1h" )}}}}}),
81- Entry ("LocalDNS.VnetDNSOverrides.ServeStaleDuration" , "4895720480850206885" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {LocalDNS : & v1alpha2.LocalDNS {VnetDNSOverrides : []v1alpha2.LocalDNSZoneOverride {{Zone : "example.com" , ServeStaleDuration : karpv1 .MustParseNillableDuration ("30m" )}}}}}),
82- )
83- It ("should match static hash when reordering tags" , func () {
95+ t .Run ("should match static hash when reordering tags" , func (t * testing.T ) {
96+ nodeClass := newHashTestNodeClassV1Alpha2 ()
8497 nodeClass .Spec .Tags = map [string ]string {"keyTag-2" : "valueTag-2" , "keyTag-1" : "valueTag-1" }
85- Expect (nodeClass .Hash ()).To (Equal (staticHash ))
98+ if got := nodeClass .Hash (); got != staticHash {
99+ t .Errorf ("Hash() = %s, want %s after tag reorder" , got , staticHash )
100+ }
86101 })
87- DescribeTable ("should change hash when static fields are updated" , func (changes v1alpha2.AKSNodeClass ) {
88- hash := nodeClass .Hash ()
89- Expect (mergo .Merge (nodeClass , changes , mergo .WithOverride , mergo .WithSliceDeepCopy )).To (Succeed ())
90- updatedHash := nodeClass .Hash ()
91- Expect (hash ).ToNot (Equal (updatedHash ))
92- },
93- Entry ("VNETSubnetID" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {VNETSubnetID : lo .ToPtr ("subnet-id-2" )}}),
94- Entry ("OSDiskSizeGB" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {OSDiskSizeGB : lo .ToPtr (int32 (40 ))}}),
95- Entry ("ImageFamily" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {ImageFamily : lo .ToPtr ("AzureLinux" )}}),
96- Entry ("Kubelet" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {Kubelet : & v1alpha2.KubeletConfiguration {CPUManagerPolicy : lo .ToPtr ("none" )}}}),
97- Entry ("MaxPods" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {MaxPods : lo .ToPtr (int32 (200 ))}}),
98- Entry ("LocalDNS.Mode" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {LocalDNS : & v1alpha2.LocalDNS {Mode : v1alpha2 .LocalDNSModeRequired }}}),
99- Entry ("LocalDNS.VnetDNSOverrides" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {LocalDNS : & v1alpha2.LocalDNS {VnetDNSOverrides : []v1alpha2.LocalDNSZoneOverride {{Zone : "example.com" , QueryLogging : v1alpha2 .LocalDNSQueryLoggingLog }}}}}),
100- Entry ("LocalDNS.KubeDNSOverrides" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {LocalDNS : & v1alpha2.LocalDNS {KubeDNSOverrides : []v1alpha2.LocalDNSZoneOverride {{Zone : "example.com" , Protocol : v1alpha2 .LocalDNSProtocolForceTCP }}}}}),
101- Entry ("LocalDNS.VnetDNSOverrides.CacheDuration" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {LocalDNS : & v1alpha2.LocalDNS {VnetDNSOverrides : []v1alpha2.LocalDNSZoneOverride {{Zone : "example.com" , CacheDuration : karpv1 .MustParseNillableDuration ("2h" )}}}}}),
102- Entry ("LocalDNS.VnetDNSOverrides.ServeStaleDuration" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {LocalDNS : & v1alpha2.LocalDNS {VnetDNSOverrides : []v1alpha2.LocalDNSZoneOverride {{Zone : "example.com" , ServeStaleDuration : karpv1 .MustParseNillableDuration ("1h" )}}}}}),
103- )
104- It ("should not change hash when tags are changed" , func () {
102+
103+ t .Run ("should change hash when static fields are updated" , func (t * testing.T ) {
104+ tests := []struct {
105+ name string
106+ changes v1alpha2.AKSNodeClass
107+ }{
108+ {"VNETSubnetID" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {VNETSubnetID : lo .ToPtr ("subnet-id-2" )}}},
109+ {"OSDiskSizeGB" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {OSDiskSizeGB : lo .ToPtr (int32 (40 ))}}},
110+ {"ImageFamily" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {ImageFamily : lo .ToPtr ("AzureLinux" )}}},
111+ {"Kubelet" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {Kubelet : & v1alpha2.KubeletConfiguration {CPUManagerPolicy : lo .ToPtr ("none" )}}}},
112+ {"MaxPods" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {MaxPods : lo .ToPtr (int32 (200 ))}}},
113+ {"LocalDNS.Mode" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {LocalDNS : & v1alpha2.LocalDNS {Mode : v1alpha2 .LocalDNSModeRequired }}}},
114+ {"LocalDNS.VnetDNSOverrides" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {LocalDNS : & v1alpha2.LocalDNS {VnetDNSOverrides : []v1alpha2.LocalDNSZoneOverride {{Zone : "example.com" , QueryLogging : v1alpha2 .LocalDNSQueryLoggingLog }}}}}},
115+ {"LocalDNS.KubeDNSOverrides" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {LocalDNS : & v1alpha2.LocalDNS {KubeDNSOverrides : []v1alpha2.LocalDNSZoneOverride {{Zone : "example.com" , Protocol : v1alpha2 .LocalDNSProtocolForceTCP }}}}}},
116+ {"LocalDNS.VnetDNSOverrides.CacheDuration" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {LocalDNS : & v1alpha2.LocalDNS {VnetDNSOverrides : []v1alpha2.LocalDNSZoneOverride {{Zone : "example.com" , CacheDuration : karpv1 .MustParseNillableDuration ("2h" )}}}}}},
117+ {"LocalDNS.VnetDNSOverrides.ServeStaleDuration" , v1alpha2.AKSNodeClass {Spec : v1alpha2.AKSNodeClassSpec {LocalDNS : & v1alpha2.LocalDNS {VnetDNSOverrides : []v1alpha2.LocalDNSZoneOverride {{Zone : "example.com" , ServeStaleDuration : karpv1 .MustParseNillableDuration ("1h" )}}}}}},
118+ }
119+ for _ , tt := range tests {
120+ t .Run (tt .name , func (t * testing.T ) {
121+ nodeClass := newHashTestNodeClassV1Alpha2 ()
122+ hash := nodeClass .Hash ()
123+ if err := mergo .Merge (nodeClass , tt .changes , mergo .WithOverride , mergo .WithSliceDeepCopy ); err != nil {
124+ t .Fatalf ("mergo.Merge failed: %v" , err )
125+ }
126+ updatedHash := nodeClass .Hash ()
127+ if hash == updatedHash {
128+ t .Errorf ("expected hash to change after updating %s, but got same hash %s" , tt .name , hash )
129+ }
130+ })
131+ }
132+ })
133+
134+ t .Run ("should not change hash when tags are changed" , func (t * testing.T ) {
135+ nodeClass := newHashTestNodeClassV1Alpha2 ()
105136 hash := nodeClass .Hash ()
106137 nodeClass .Spec .Tags = map [string ]string {"keyTag-3" : "valueTag-3" }
107138 updatedHash := nodeClass .Hash ()
108- Expect (hash ).To (Equal (updatedHash ))
139+ if hash != updatedHash {
140+ t .Errorf ("expected hash to remain %s after tag change, got %s" , hash , updatedHash )
141+ }
109142 })
110- It ("should expect two AKSNodeClasses with the same spec to have the same hash" , func () {
143+
144+ t .Run ("should expect two AKSNodeClasses with the same spec to have the same hash" , func (t * testing.T ) {
145+ nodeClass := newHashTestNodeClassV1Alpha2 ()
111146 otherNodeClass := & v1alpha2.AKSNodeClass {
112147 Spec : nodeClass .Spec ,
113148 }
114- Expect (nodeClass .Hash ()).To (Equal (otherNodeClass .Hash ()))
149+ if nodeClass .Hash () != otherNodeClass .Hash () {
150+ t .Errorf ("expected same hash for identical specs, got %s and %s" , nodeClass .Hash (), otherNodeClass .Hash ())
151+ }
115152 })
153+
116154 // This test is a sanity check to update the hashing version if the algorithm has been updated.
117155 // Note: this will only catch a missing version update, if the staticHash hasn't been updated yet.
118- It ("when hashing algorithm updates, we should update the hash version" , func () {
156+ t .Run ("when hashing algorithm updates, we should update the hash version" , func (t * testing.T ) {
157+ nodeClass := newHashTestNodeClassV1Alpha2 ()
119158 currentHashVersion := "v3"
120159 if nodeClass .Hash () != staticHash {
121- Expect (v1alpha2 .AKSNodeClassHashVersion ).ToNot (Equal (currentHashVersion ))
160+ if v1alpha2 .AKSNodeClassHashVersion == currentHashVersion {
161+ t .Errorf ("hash changed from static hash, expected AKSNodeClassHashVersion to differ from %s" , currentHashVersion )
162+ }
122163 } else {
123164 // Note: this failure case is to ensure you have updated currentHashVersion, not AKSNodeClassHashVersion
124- Expect (currentHashVersion ).To (Equal (v1alpha2 .AKSNodeClassHashVersion ))
165+ if currentHashVersion != v1alpha2 .AKSNodeClassHashVersion {
166+ t .Errorf ("expected currentHashVersion %s to equal AKSNodeClassHashVersion %s" , currentHashVersion , v1alpha2 .AKSNodeClassHashVersion )
167+ }
125168 }
126169 // Note: this failure case is to ensure you have updated staticHash value
127- Expect (staticHash ).To (Equal (nodeClass .Hash ()))
170+ if staticHash != nodeClass .Hash () {
171+ t .Errorf ("expected staticHash %s to equal computed hash %s" , staticHash , nodeClass .Hash ())
172+ }
128173 })
129- })
174+ }
0 commit comments