mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-30 21:30:16 +00:00 
			
		
		
		
	Adds unit tests covering the problematic scenarios identified
around conflicting data in child owner references
                      Before   After
package level         51%      68%
garbagecollector.go   60%      75%
graph_builder.go      50%      81%
graph.go              50%      68%
Added/improved coverage of key functions that had lacking unit test coverage:
* attemptToDeleteWorker
* attemptToDeleteItem
* processGraphChanges (added coverage of all added code)
		
	
		
			
				
	
	
		
			213 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			213 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
| Copyright 2020 The Kubernetes Authors.
 | |
| 
 | |
| Licensed under the Apache License, Version 2.0 (the "License");
 | |
| you may not use this file except in compliance with the License.
 | |
| You may obtain a copy of the License at
 | |
| 
 | |
|     http://www.apache.org/licenses/LICENSE-2.0
 | |
| 
 | |
| Unless required by applicable law or agreed to in writing, software
 | |
| distributed under the License is distributed on an "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| See the License for the specific language governing permissions and
 | |
| limitations under the License.
 | |
| */
 | |
| 
 | |
| package garbagecollector
 | |
| 
 | |
| import (
 | |
| 	"reflect"
 | |
| 	"testing"
 | |
| )
 | |
| 
 | |
| func TestGetAlternateOwnerIdentity(t *testing.T) {
 | |
| 	ns1child1 := makeID("v1", "Child", "ns1", "child1", "childuid11")
 | |
| 	ns1child2 := makeID("v1", "Child", "ns1", "child2", "childuid12")
 | |
| 
 | |
| 	ns2child1 := makeID("v1", "Child", "ns2", "child1", "childuid21")
 | |
| 
 | |
| 	clusterchild1 := makeID("v1", "Child", "", "child1", "childuidc1")
 | |
| 
 | |
| 	var (
 | |
| 		nsabsentparentns1 = makeID("v1", "NSParent", "ns1", "parentname", "parentuid")
 | |
| 		nsabsentparentns2 = makeID("v1", "NSParent", "ns2", "parentname", "parentuid")
 | |
| 
 | |
| 		nsabsentparent_version = makeID("xx", "NSParent", "ns1", "parentname", "parentuid")
 | |
| 		nsabsentparent_kind    = makeID("v1", "xxxxxxxx", "ns1", "parentname", "parentuid")
 | |
| 		nsabsentparent_name    = makeID("v1", "NSParent", "ns1", "xxxxxxxxxx", "parentuid")
 | |
| 
 | |
| 		clusterabsentparent         = makeID("v1", "ClusterParent", "", "parentname", "parentuid")
 | |
| 		clusterabsentparent_version = makeID("xx", "ClusterParent", "", "parentname", "parentuid")
 | |
| 		clusterabsentparent_kind    = makeID("v1", "xxxxxxxxxxxxx", "", "parentname", "parentuid")
 | |
| 		clusterabsentparent_name    = makeID("v1", "ClusterParent", "", "xxxxxxxxxx", "parentuid")
 | |
| 
 | |
| 		clusterabsentparent_ns1_version = makeID("xx", "ClusterParent", "ns1", "parentname", "parentuid")
 | |
| 		clusterabsentparent_ns1_kind    = makeID("v1", "xxxxxxxxxxxxx", "ns1", "parentname", "parentuid")
 | |
| 	)
 | |
| 
 | |
| 	orderedNamespacedReferences := []objectReference{
 | |
| 		makeID("v1", "kind", "ns1", "name", "uid"),
 | |
| 		makeID("v2", "kind", "ns1", "name", "uid"),
 | |
| 		makeID("v3", "kind", "ns1", "name", "uid"),
 | |
| 		makeID("v4", "kind", "ns1", "name", "uid"),
 | |
| 		makeID("v5", "kind", "ns1", "name", "uid"),
 | |
| 	}
 | |
| 	orderedClusterReferences := []objectReference{
 | |
| 		makeID("v1", "kind", "", "name", "uid"),
 | |
| 		makeID("v2", "kind", "", "name", "uid"),
 | |
| 		makeID("v3", "kind", "", "name", "uid"),
 | |
| 		makeID("v4", "kind", "", "name", "uid"),
 | |
| 		makeID("v5", "kind", "", "name", "uid"),
 | |
| 	}
 | |
| 
 | |
| 	testcases := []struct {
 | |
| 		name              string
 | |
| 		deps              []*node
 | |
| 		verifiedAbsent    objectReference
 | |
| 		expectedAlternate *objectReference
 | |
| 	}{
 | |
| 		{
 | |
| 			name: "namespaced alternate version",
 | |
| 			deps: []*node{
 | |
| 				makeNode(ns1child1, withOwners(nsabsentparentns1)),
 | |
| 				makeNode(ns1child2, withOwners(nsabsentparent_version)),
 | |
| 			},
 | |
| 			verifiedAbsent:    nsabsentparentns1,
 | |
| 			expectedAlternate: &nsabsentparent_version, // switch to alternate version
 | |
| 		},
 | |
| 		{
 | |
| 			name: "namespaced alternate kind",
 | |
| 			deps: []*node{
 | |
| 				makeNode(ns1child1, withOwners(nsabsentparentns1)),
 | |
| 				makeNode(ns1child2, withOwners(nsabsentparent_kind)),
 | |
| 			},
 | |
| 			verifiedAbsent:    nsabsentparentns1,
 | |
| 			expectedAlternate: &nsabsentparent_kind, // switch to alternate kind
 | |
| 		},
 | |
| 		{
 | |
| 			name: "namespaced alternate namespace",
 | |
| 			deps: []*node{
 | |
| 				makeNode(ns1child1, withOwners(nsabsentparentns1)),
 | |
| 				makeNode(ns2child1, withOwners(nsabsentparentns2)),
 | |
| 			},
 | |
| 			verifiedAbsent:    nsabsentparentns1,
 | |
| 			expectedAlternate: &nsabsentparentns2, // switch to alternate namespace
 | |
| 		},
 | |
| 		{
 | |
| 			name: "namespaced alternate name",
 | |
| 			deps: []*node{
 | |
| 				makeNode(ns1child1, withOwners(nsabsentparentns1)),
 | |
| 				makeNode(ns1child1, withOwners(nsabsentparent_name)),
 | |
| 			},
 | |
| 			verifiedAbsent:    nsabsentparentns1,
 | |
| 			expectedAlternate: &nsabsentparent_name, // switch to alternate name
 | |
| 		},
 | |
| 
 | |
| 		{
 | |
| 			name: "cluster alternate version",
 | |
| 			deps: []*node{
 | |
| 				makeNode(ns1child1, withOwners(clusterabsentparent)),
 | |
| 				makeNode(ns1child2, withOwners(clusterabsentparent_version)),
 | |
| 			},
 | |
| 			verifiedAbsent:    clusterabsentparent,
 | |
| 			expectedAlternate: &clusterabsentparent_ns1_version, // switch to alternate version, namespaced to new dependent since we don't know the version is cluster-scoped
 | |
| 		},
 | |
| 		{
 | |
| 			name: "cluster alternate kind",
 | |
| 			deps: []*node{
 | |
| 				makeNode(ns1child1, withOwners(clusterabsentparent)),
 | |
| 				makeNode(ns1child2, withOwners(clusterabsentparent_kind)),
 | |
| 			},
 | |
| 			verifiedAbsent:    clusterabsentparent,
 | |
| 			expectedAlternate: &clusterabsentparent_ns1_kind, // switch to alternate kind, namespaced to new dependent since we don't know the new kind is cluster-scoped
 | |
| 		},
 | |
| 		{
 | |
| 			name: "cluster alternate namespace",
 | |
| 			deps: []*node{
 | |
| 				makeNode(ns1child1, withOwners(clusterabsentparent)),
 | |
| 				makeNode(ns2child1, withOwners(clusterabsentparent)),
 | |
| 			},
 | |
| 			verifiedAbsent:    clusterabsentparent,
 | |
| 			expectedAlternate: nil, // apiVersion/kind verified cluster-scoped, namespace delta ignored, no alternates found
 | |
| 		},
 | |
| 		{
 | |
| 			name: "cluster alternate name",
 | |
| 			deps: []*node{
 | |
| 				makeNode(ns1child1, withOwners(clusterabsentparent)),
 | |
| 				makeNode(ns1child1, withOwners(clusterabsentparent_name)),
 | |
| 			},
 | |
| 			verifiedAbsent:    clusterabsentparent,
 | |
| 			expectedAlternate: &clusterabsentparent_name, // switch to alternate name, apiVersion/kind verified cluster-scoped, namespace dropped
 | |
| 		},
 | |
| 
 | |
| 		{
 | |
| 			name: "namespaced ref from namespaced child returns first if absent is sorted last",
 | |
| 			deps: []*node{
 | |
| 				makeNode(ns1child1, withOwners(orderedNamespacedReferences...)),
 | |
| 			},
 | |
| 			verifiedAbsent:    orderedNamespacedReferences[len(orderedNamespacedReferences)-1],
 | |
| 			expectedAlternate: &orderedNamespacedReferences[0],
 | |
| 		},
 | |
| 		{
 | |
| 			name: "namespaced ref from namespaced child returns next after absent",
 | |
| 			deps: []*node{
 | |
| 				makeNode(ns1child1, withOwners(orderedNamespacedReferences...)),
 | |
| 			},
 | |
| 			verifiedAbsent:    orderedNamespacedReferences[len(orderedNamespacedReferences)-2],
 | |
| 			expectedAlternate: &orderedNamespacedReferences[len(orderedNamespacedReferences)-1],
 | |
| 		},
 | |
| 
 | |
| 		{
 | |
| 			name: "cluster ref from cluster child returns first if absent is sorted last",
 | |
| 			deps: []*node{
 | |
| 				makeNode(clusterchild1, withOwners(orderedClusterReferences...)),
 | |
| 			},
 | |
| 			verifiedAbsent:    orderedClusterReferences[len(orderedClusterReferences)-1],
 | |
| 			expectedAlternate: &orderedClusterReferences[0],
 | |
| 		},
 | |
| 		{
 | |
| 			name: "cluster ref from cluster child returns next after absent",
 | |
| 			deps: []*node{
 | |
| 				makeNode(clusterchild1, withOwners(orderedClusterReferences...)),
 | |
| 			},
 | |
| 			verifiedAbsent:    orderedClusterReferences[len(orderedClusterReferences)-2],
 | |
| 			expectedAlternate: &orderedClusterReferences[len(orderedClusterReferences)-1],
 | |
| 		},
 | |
| 
 | |
| 		{
 | |
| 			name: "ignore unrelated",
 | |
| 			deps: []*node{
 | |
| 				makeNode(ns1child1, withOwners(clusterabsentparent, makeID("v1", "Parent", "ns1", "name", "anotheruid"))),
 | |
| 			},
 | |
| 			verifiedAbsent:    clusterabsentparent,
 | |
| 			expectedAlternate: nil,
 | |
| 		},
 | |
| 		{
 | |
| 			name: "ignore matches",
 | |
| 			deps: []*node{
 | |
| 				makeNode(ns1child1, withOwners(clusterabsentparent, clusterabsentparent)),
 | |
| 			},
 | |
| 			verifiedAbsent:    clusterabsentparent,
 | |
| 			expectedAlternate: nil,
 | |
| 		},
 | |
| 		{
 | |
| 			name: "collapse duplicates",
 | |
| 			deps: []*node{
 | |
| 				makeNode(clusterchild1, withOwners(clusterabsentparent, clusterabsentparent_kind, clusterabsentparent_kind)),
 | |
| 			},
 | |
| 			verifiedAbsent:    clusterabsentparent,
 | |
| 			expectedAlternate: &clusterabsentparent_kind,
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	for _, tc := range testcases {
 | |
| 		t.Run(tc.name, func(t *testing.T) {
 | |
| 			alternate := getAlternateOwnerIdentity(tc.deps, tc.verifiedAbsent)
 | |
| 			if !reflect.DeepEqual(alternate, tc.expectedAlternate) {
 | |
| 				t.Errorf("expected\n%#v\ngot\n%#v", tc.expectedAlternate, alternate)
 | |
| 			}
 | |
| 		})
 | |
| 	}
 | |
| }
 |