Skip to content
This repository was archived by the owner on Oct 6, 2025. It is now read-only.

Commit 39fde66

Browse files
committed
Increase test coverage
Signed-off-by: Jonathan Ogilvie <[email protected]>
1 parent 175bb33 commit 39fde66

File tree

1 file changed

+306
-0
lines changed

1 file changed

+306
-0
lines changed

pkg/cache/cluster_test.go

Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,6 +1255,312 @@ func TestIterateHierarchyV2_CrossNamespaceOwnerReference(t *testing.T) {
12551255
assert.True(t, foundNamespacedChild, "Should visit Deployment child (this tests the fix)")
12561256
}
12571257

1258+
// TestBuildGraph_NilAllResources tests buildGraph with nil allResources parameter
1259+
func TestBuildGraph_NilAllResources(t *testing.T) {
1260+
// Create test resources
1261+
parentUID := types.UID("parent-123")
1262+
childUID := types.UID("child-456")
1263+
1264+
parent := &Resource{
1265+
Ref: corev1.ObjectReference{
1266+
APIVersion: "v1",
1267+
Kind: "ConfigMap",
1268+
Name: "parent",
1269+
Namespace: "test-ns",
1270+
UID: parentUID,
1271+
},
1272+
}
1273+
1274+
child := &Resource{
1275+
Ref: corev1.ObjectReference{
1276+
APIVersion: "v1",
1277+
Kind: "Pod",
1278+
Name: "child",
1279+
Namespace: "test-ns",
1280+
UID: childUID,
1281+
},
1282+
OwnerRefs: []metav1.OwnerReference{{
1283+
APIVersion: "v1",
1284+
Kind: "ConfigMap",
1285+
Name: "parent",
1286+
UID: parentUID,
1287+
}},
1288+
}
1289+
1290+
nsNodes := map[kube.ResourceKey]*Resource{
1291+
parent.ResourceKey(): parent,
1292+
child.ResourceKey(): child,
1293+
}
1294+
1295+
// Call buildGraph with nil allResources
1296+
graph := buildGraph(nsNodes, nil)
1297+
1298+
// Should still work for same-namespace relationships
1299+
assert.Contains(t, graph, parent.ResourceKey())
1300+
assert.Contains(t, graph[parent.ResourceKey()], childUID)
1301+
}
1302+
1303+
// TestBuildGraph_InvalidAPIVersion tests handling of invalid API versions in owner references
1304+
func TestBuildGraph_InvalidAPIVersion(t *testing.T) {
1305+
childUID := types.UID("child-123")
1306+
1307+
child := &Resource{
1308+
Ref: corev1.ObjectReference{
1309+
APIVersion: "v1",
1310+
Kind: "Pod",
1311+
Name: "child",
1312+
Namespace: "test-ns",
1313+
UID: childUID,
1314+
},
1315+
OwnerRefs: []metav1.OwnerReference{{
1316+
APIVersion: "invalid/api/version", // Invalid API version
1317+
Kind: "ConfigMap",
1318+
Name: "parent",
1319+
// No UID - should trigger API version parsing
1320+
}},
1321+
}
1322+
1323+
nsNodes := map[kube.ResourceKey]*Resource{
1324+
child.ResourceKey(): child,
1325+
}
1326+
1327+
allResources := map[kube.ResourceKey]*Resource{
1328+
child.ResourceKey(): child,
1329+
}
1330+
1331+
// Should not panic and should handle invalid API version gracefully
1332+
graph := buildGraph(nsNodes, allResources)
1333+
1334+
// No parent should be found due to invalid API version
1335+
assert.Empty(t, graph)
1336+
}
1337+
1338+
// TestBuildGraph_CrossNamespaceMissingUID tests cross-namespace parent resolution with missing UID
1339+
func TestBuildGraph_CrossNamespaceMissingUID(t *testing.T) {
1340+
parentUID := types.UID("parent-123")
1341+
childUID := types.UID("child-456")
1342+
1343+
// Cluster-scoped parent
1344+
parent := &Resource{
1345+
Ref: corev1.ObjectReference{
1346+
APIVersion: "v1",
1347+
Kind: "ConfigMap",
1348+
Name: "parent",
1349+
Namespace: "", // Cluster-scoped
1350+
UID: parentUID,
1351+
},
1352+
}
1353+
1354+
// Namespaced child with owner reference missing UID
1355+
child := &Resource{
1356+
Ref: corev1.ObjectReference{
1357+
APIVersion: "v1",
1358+
Kind: "Pod",
1359+
Name: "child",
1360+
Namespace: "test-ns",
1361+
UID: childUID,
1362+
},
1363+
OwnerRefs: []metav1.OwnerReference{{
1364+
APIVersion: "v1",
1365+
Kind: "ConfigMap",
1366+
Name: "parent",
1367+
// UID is missing - should be resolved via cross-namespace lookup
1368+
}},
1369+
}
1370+
1371+
nsNodes := map[kube.ResourceKey]*Resource{
1372+
child.ResourceKey(): child,
1373+
}
1374+
1375+
allResources := map[kube.ResourceKey]*Resource{
1376+
parent.ResourceKey(): parent,
1377+
child.ResourceKey(): child,
1378+
}
1379+
1380+
graph := buildGraph(nsNodes, allResources)
1381+
1382+
// Should find the parent via cross-namespace lookup and establish relationship
1383+
assert.Contains(t, graph, parent.ResourceKey())
1384+
assert.Contains(t, graph[parent.ResourceKey()], childUID)
1385+
1386+
// Verify UID was backfilled
1387+
assert.Equal(t, parentUID, child.OwnerRefs[0].UID)
1388+
}
1389+
1390+
// TestBuildGraph_NonExistentParent tests cross-namespace child with non-existent parent
1391+
func TestBuildGraph_NonExistentParent(t *testing.T) {
1392+
childUID := types.UID("child-456")
1393+
1394+
child := &Resource{
1395+
Ref: corev1.ObjectReference{
1396+
APIVersion: "v1",
1397+
Kind: "Pod",
1398+
Name: "child",
1399+
Namespace: "test-ns",
1400+
UID: childUID,
1401+
},
1402+
OwnerRefs: []metav1.OwnerReference{{
1403+
APIVersion: "v1",
1404+
Kind: "ConfigMap",
1405+
Name: "non-existent-parent",
1406+
// No UID - should trigger lookup that fails
1407+
}},
1408+
}
1409+
1410+
nsNodes := map[kube.ResourceKey]*Resource{
1411+
child.ResourceKey(): child,
1412+
}
1413+
1414+
allResources := map[kube.ResourceKey]*Resource{
1415+
child.ResourceKey(): child,
1416+
// Parent is not in allResources
1417+
}
1418+
1419+
graph := buildGraph(nsNodes, allResources)
1420+
1421+
// No relationships should be established
1422+
assert.Empty(t, graph)
1423+
}
1424+
1425+
// TestBuildGraph_CrossNamespaceUIDLookup tests cross-namespace parent lookup by UID
1426+
func TestBuildGraph_CrossNamespaceUIDLookup(t *testing.T) {
1427+
parentUID := types.UID("parent-123")
1428+
childUID := types.UID("child-456")
1429+
1430+
// Cluster-scoped parent
1431+
parent := &Resource{
1432+
Ref: corev1.ObjectReference{
1433+
APIVersion: "v1",
1434+
Kind: "ConfigMap",
1435+
Name: "parent",
1436+
Namespace: "", // Cluster-scoped
1437+
UID: parentUID,
1438+
},
1439+
}
1440+
1441+
// Namespaced child with owner reference that has UID but parent not in same namespace
1442+
child := &Resource{
1443+
Ref: corev1.ObjectReference{
1444+
APIVersion: "v1",
1445+
Kind: "Pod",
1446+
Name: "child",
1447+
Namespace: "test-ns",
1448+
UID: childUID,
1449+
},
1450+
OwnerRefs: []metav1.OwnerReference{{
1451+
APIVersion: "v1",
1452+
Kind: "ConfigMap",
1453+
Name: "parent",
1454+
UID: parentUID, // UID is present
1455+
}},
1456+
}
1457+
1458+
nsNodes := map[kube.ResourceKey]*Resource{
1459+
child.ResourceKey(): child,
1460+
// Parent is not in same namespace
1461+
}
1462+
1463+
allResources := map[kube.ResourceKey]*Resource{
1464+
parent.ResourceKey(): parent,
1465+
child.ResourceKey(): child,
1466+
}
1467+
1468+
graph := buildGraph(nsNodes, allResources)
1469+
1470+
// Should establish cross-namespace relationship via UID lookup
1471+
assert.Contains(t, graph, parent.ResourceKey())
1472+
assert.Contains(t, graph[parent.ResourceKey()], childUID)
1473+
}
1474+
1475+
// TestBuildGraph_DuplicateUIDs tests handling of resources with duplicate UIDs
1476+
func TestBuildGraph_DuplicateUIDs(t *testing.T) {
1477+
parentUID := types.UID("parent-123")
1478+
duplicateUID := types.UID("duplicate-456")
1479+
1480+
parent := &Resource{
1481+
Ref: corev1.ObjectReference{
1482+
APIVersion: "v1",
1483+
Kind: "ConfigMap",
1484+
Name: "parent",
1485+
Namespace: "test-ns",
1486+
UID: parentUID,
1487+
},
1488+
}
1489+
1490+
// Two children with the same UID (simulating replicasets from different API groups)
1491+
child1 := &Resource{
1492+
Ref: corev1.ObjectReference{
1493+
APIVersion: "apps/v1",
1494+
Kind: "ReplicaSet",
1495+
Name: "child-apps",
1496+
Namespace: "test-ns",
1497+
UID: duplicateUID,
1498+
},
1499+
OwnerRefs: []metav1.OwnerReference{{
1500+
APIVersion: "v1",
1501+
Kind: "ConfigMap",
1502+
Name: "parent",
1503+
UID: parentUID,
1504+
}},
1505+
}
1506+
1507+
child2 := &Resource{
1508+
Ref: corev1.ObjectReference{
1509+
APIVersion: "extensions/v1beta1",
1510+
Kind: "ReplicaSet",
1511+
Name: "child-extensions",
1512+
Namespace: "test-ns",
1513+
UID: duplicateUID,
1514+
},
1515+
OwnerRefs: []metav1.OwnerReference{{
1516+
APIVersion: "v1",
1517+
Kind: "ConfigMap",
1518+
Name: "parent",
1519+
UID: parentUID,
1520+
}},
1521+
}
1522+
1523+
nsNodes := map[kube.ResourceKey]*Resource{
1524+
parent.ResourceKey(): parent,
1525+
child1.ResourceKey(): child1,
1526+
child2.ResourceKey(): child2,
1527+
}
1528+
1529+
graph := buildGraph(nsNodes, nil)
1530+
1531+
// Should handle duplicate UIDs gracefully by picking consistently
1532+
assert.Contains(t, graph, parent.ResourceKey())
1533+
assert.Contains(t, graph[parent.ResourceKey()], duplicateUID)
1534+
1535+
// Should pick the same child consistently (based on string comparison)
1536+
selectedChild := graph[parent.ResourceKey()][duplicateUID]
1537+
assert.NotNil(t, selectedChild)
1538+
}
1539+
1540+
// TestIterateHierarchyV2_EdgeCases tests additional edge cases for hierarchy iteration
1541+
func TestIterateHierarchyV2_EdgeCases(t *testing.T) {
1542+
cluster := newCluster(t)
1543+
1544+
t.Run("EmptyKeysList", func(t *testing.T) {
1545+
var visited []kube.ResourceKey
1546+
cluster.IterateHierarchyV2([]kube.ResourceKey{}, func(resource *Resource, _ map[kube.ResourceKey]*Resource) bool {
1547+
visited = append(visited, resource.ResourceKey())
1548+
return true
1549+
})
1550+
assert.Empty(t, visited)
1551+
})
1552+
1553+
t.Run("NonExistentKeys", func(t *testing.T) {
1554+
var visited []kube.ResourceKey
1555+
nonExistentKey := kube.ResourceKey{Group: "fake", Kind: "Fake", Namespace: "fake", Name: "fake"}
1556+
cluster.IterateHierarchyV2([]kube.ResourceKey{nonExistentKey}, func(resource *Resource, _ map[kube.ResourceKey]*Resource) bool {
1557+
visited = append(visited, resource.ResourceKey())
1558+
return true
1559+
})
1560+
assert.Empty(t, visited)
1561+
})
1562+
}
1563+
12581564
// Test_watchEvents_Deadlock validates that starting watches will not create a deadlock
12591565
// caused by using improper locking in various callback methods when there is a high load on the
12601566
// system.

0 commit comments

Comments
 (0)