k8s.io/kubernetes@v1.29.3/pkg/controller/garbagecollector/graph_builder_test.go (about) 1 /* 2 Copyright 2020 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 garbagecollector 18 19 import ( 20 "reflect" 21 "testing" 22 ) 23 24 func TestGetAlternateOwnerIdentity(t *testing.T) { 25 ns1child1 := makeID("v1", "Child", "ns1", "child1", "childuid11") 26 ns1child2 := makeID("v1", "Child", "ns1", "child2", "childuid12") 27 28 ns2child1 := makeID("v1", "Child", "ns2", "child1", "childuid21") 29 30 clusterchild1 := makeID("v1", "Child", "", "child1", "childuidc1") 31 32 var ( 33 nsabsentparentns1 = makeID("v1", "NSParent", "ns1", "parentname", "parentuid") 34 nsabsentparentns2 = makeID("v1", "NSParent", "ns2", "parentname", "parentuid") 35 36 nsabsentparent_version = makeID("xx", "NSParent", "ns1", "parentname", "parentuid") 37 nsabsentparent_kind = makeID("v1", "xxxxxxxx", "ns1", "parentname", "parentuid") 38 nsabsentparent_name = makeID("v1", "NSParent", "ns1", "xxxxxxxxxx", "parentuid") 39 40 clusterabsentparent = makeID("v1", "ClusterParent", "", "parentname", "parentuid") 41 clusterabsentparent_version = makeID("xx", "ClusterParent", "", "parentname", "parentuid") 42 clusterabsentparent_kind = makeID("v1", "xxxxxxxxxxxxx", "", "parentname", "parentuid") 43 clusterabsentparent_name = makeID("v1", "ClusterParent", "", "xxxxxxxxxx", "parentuid") 44 45 clusterabsentparent_ns1_version = makeID("xx", "ClusterParent", "ns1", "parentname", "parentuid") 46 clusterabsentparent_ns1_kind = makeID("v1", "xxxxxxxxxxxxx", "ns1", "parentname", "parentuid") 47 ) 48 49 orderedNamespacedReferences := []objectReference{ 50 makeID("v1", "kind", "ns1", "name", "uid"), 51 makeID("v2", "kind", "ns1", "name", "uid"), 52 makeID("v3", "kind", "ns1", "name", "uid"), 53 makeID("v4", "kind", "ns1", "name", "uid"), 54 makeID("v5", "kind", "ns1", "name", "uid"), 55 } 56 orderedClusterReferences := []objectReference{ 57 makeID("v1", "kind", "", "name", "uid"), 58 makeID("v2", "kind", "", "name", "uid"), 59 makeID("v3", "kind", "", "name", "uid"), 60 makeID("v4", "kind", "", "name", "uid"), 61 makeID("v5", "kind", "", "name", "uid"), 62 } 63 64 testcases := []struct { 65 name string 66 deps []*node 67 verifiedAbsent objectReference 68 expectedAlternate *objectReference 69 }{ 70 { 71 name: "namespaced alternate version", 72 deps: []*node{ 73 makeNode(ns1child1, withOwners(nsabsentparentns1)), 74 makeNode(ns1child2, withOwners(nsabsentparent_version)), 75 }, 76 verifiedAbsent: nsabsentparentns1, 77 expectedAlternate: &nsabsentparent_version, // switch to alternate version 78 }, 79 { 80 name: "namespaced alternate kind", 81 deps: []*node{ 82 makeNode(ns1child1, withOwners(nsabsentparentns1)), 83 makeNode(ns1child2, withOwners(nsabsentparent_kind)), 84 }, 85 verifiedAbsent: nsabsentparentns1, 86 expectedAlternate: &nsabsentparent_kind, // switch to alternate kind 87 }, 88 { 89 name: "namespaced alternate namespace", 90 deps: []*node{ 91 makeNode(ns1child1, withOwners(nsabsentparentns1)), 92 makeNode(ns2child1, withOwners(nsabsentparentns2)), 93 }, 94 verifiedAbsent: nsabsentparentns1, 95 expectedAlternate: &nsabsentparentns2, // switch to alternate namespace 96 }, 97 { 98 name: "namespaced alternate name", 99 deps: []*node{ 100 makeNode(ns1child1, withOwners(nsabsentparentns1)), 101 makeNode(ns1child1, withOwners(nsabsentparent_name)), 102 }, 103 verifiedAbsent: nsabsentparentns1, 104 expectedAlternate: &nsabsentparent_name, // switch to alternate name 105 }, 106 107 { 108 name: "cluster alternate version", 109 deps: []*node{ 110 makeNode(ns1child1, withOwners(clusterabsentparent)), 111 makeNode(ns1child2, withOwners(clusterabsentparent_version)), 112 }, 113 verifiedAbsent: clusterabsentparent, 114 expectedAlternate: &clusterabsentparent_ns1_version, // switch to alternate version, namespaced to new dependent since we don't know the version is cluster-scoped 115 }, 116 { 117 name: "cluster alternate kind", 118 deps: []*node{ 119 makeNode(ns1child1, withOwners(clusterabsentparent)), 120 makeNode(ns1child2, withOwners(clusterabsentparent_kind)), 121 }, 122 verifiedAbsent: clusterabsentparent, 123 expectedAlternate: &clusterabsentparent_ns1_kind, // switch to alternate kind, namespaced to new dependent since we don't know the new kind is cluster-scoped 124 }, 125 { 126 name: "cluster alternate namespace", 127 deps: []*node{ 128 makeNode(ns1child1, withOwners(clusterabsentparent)), 129 makeNode(ns2child1, withOwners(clusterabsentparent)), 130 }, 131 verifiedAbsent: clusterabsentparent, 132 expectedAlternate: nil, // apiVersion/kind verified cluster-scoped, namespace delta ignored, no alternates found 133 }, 134 { 135 name: "cluster alternate name", 136 deps: []*node{ 137 makeNode(ns1child1, withOwners(clusterabsentparent)), 138 makeNode(ns1child1, withOwners(clusterabsentparent_name)), 139 }, 140 verifiedAbsent: clusterabsentparent, 141 expectedAlternate: &clusterabsentparent_name, // switch to alternate name, apiVersion/kind verified cluster-scoped, namespace dropped 142 }, 143 144 { 145 name: "namespaced ref from namespaced child returns first if absent is sorted last", 146 deps: []*node{ 147 makeNode(ns1child1, withOwners(orderedNamespacedReferences...)), 148 }, 149 verifiedAbsent: orderedNamespacedReferences[len(orderedNamespacedReferences)-1], 150 expectedAlternate: &orderedNamespacedReferences[0], 151 }, 152 { 153 name: "namespaced ref from namespaced child returns next after absent", 154 deps: []*node{ 155 makeNode(ns1child1, withOwners(orderedNamespacedReferences...)), 156 }, 157 verifiedAbsent: orderedNamespacedReferences[len(orderedNamespacedReferences)-2], 158 expectedAlternate: &orderedNamespacedReferences[len(orderedNamespacedReferences)-1], 159 }, 160 161 { 162 name: "cluster ref from cluster child returns first if absent is sorted last", 163 deps: []*node{ 164 makeNode(clusterchild1, withOwners(orderedClusterReferences...)), 165 }, 166 verifiedAbsent: orderedClusterReferences[len(orderedClusterReferences)-1], 167 expectedAlternate: &orderedClusterReferences[0], 168 }, 169 { 170 name: "cluster ref from cluster child returns next after absent", 171 deps: []*node{ 172 makeNode(clusterchild1, withOwners(orderedClusterReferences...)), 173 }, 174 verifiedAbsent: orderedClusterReferences[len(orderedClusterReferences)-2], 175 expectedAlternate: &orderedClusterReferences[len(orderedClusterReferences)-1], 176 }, 177 178 { 179 name: "ignore unrelated", 180 deps: []*node{ 181 makeNode(ns1child1, withOwners(clusterabsentparent, makeID("v1", "Parent", "ns1", "name", "anotheruid"))), 182 }, 183 verifiedAbsent: clusterabsentparent, 184 expectedAlternate: nil, 185 }, 186 { 187 name: "ignore matches", 188 deps: []*node{ 189 makeNode(ns1child1, withOwners(clusterabsentparent, clusterabsentparent)), 190 }, 191 verifiedAbsent: clusterabsentparent, 192 expectedAlternate: nil, 193 }, 194 { 195 name: "collapse duplicates", 196 deps: []*node{ 197 makeNode(clusterchild1, withOwners(clusterabsentparent, clusterabsentparent_kind, clusterabsentparent_kind)), 198 }, 199 verifiedAbsent: clusterabsentparent, 200 expectedAlternate: &clusterabsentparent_kind, 201 }, 202 } 203 204 for _, tc := range testcases { 205 t.Run(tc.name, func(t *testing.T) { 206 alternate := getAlternateOwnerIdentity(tc.deps, tc.verifiedAbsent) 207 if !reflect.DeepEqual(alternate, tc.expectedAlternate) { 208 t.Errorf("expected\n%#v\ngot\n%#v", tc.expectedAlternate, alternate) 209 } 210 }) 211 } 212 }