Skip to content

Commit ed5d8ee

Browse files
committed
tests: Add Pod MAC collision detection E2E tests
Add E2E tests for Pod-Pod and cross-type Pod-VMI MAC collision detection, mirroring the existing VMI collision test structure. Pod-Pod tests cover: inter-Pod collisions (with MAC format variations), out-of-range MACs, 3+ Pods, partial collisions on multi-interface Pods, multiple colliding MACs, and collision clearing on Pod deletion. Cross-type tests cover: detecting collisions between a Pod and a VMI sharing the same MAC, and verifying collision clears when either the Pod or the VMI is deleted. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ram Lavi <ralavi@redhat.com>
1 parent 52f78eb commit ed5d8ee

File tree

3 files changed

+880
-0
lines changed

3 files changed

+880
-0
lines changed

tests/pod.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package tests
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
"time"
8+
9+
. "github.com/onsi/gomega"
10+
11+
corev1 "k8s.io/api/core/v1"
12+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13+
14+
networkv1 "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1"
15+
multus "gopkg.in/k8snetworkplumbingwg/multus-cni.v3/pkg/types"
16+
)
17+
18+
const (
19+
podCollisionCleanupTimeout = 2 * time.Minute
20+
podCollisionCleanupInterval = 5 * time.Second
21+
)
22+
23+
type PodOption func(*corev1.Pod)
24+
25+
func WithMultusNetwork(nadName, mac string) PodOption {
26+
return func(pod *corev1.Pod) {
27+
var networks []*multus.NetworkSelectionElement
28+
if existing, ok := pod.Annotations[networkv1.NetworkAttachmentAnnot]; ok {
29+
_ = json.Unmarshal([]byte(existing), &networks)
30+
}
31+
networks = append(networks, &multus.NetworkSelectionElement{
32+
Name: nadName,
33+
Namespace: pod.Namespace,
34+
MacRequest: mac,
35+
})
36+
data, _ := json.Marshal(networks)
37+
pod.Annotations[networkv1.NetworkAttachmentAnnot] = string(data)
38+
}
39+
}
40+
41+
func NewCollisionPod(namespace, name string, opts ...PodOption) *corev1.Pod {
42+
pod := &corev1.Pod{
43+
ObjectMeta: metav1.ObjectMeta{
44+
Name: randName(name),
45+
Namespace: namespace,
46+
Annotations: map[string]string{},
47+
},
48+
Spec: corev1.PodSpec{
49+
TerminationGracePeriodSeconds: &gracePeriodSeconds,
50+
Containers: []corev1.Container{
51+
{
52+
Name: "test",
53+
Image: "quay.io/centos/centos:stream9",
54+
Command: []string{"/bin/bash", "-c", "sleep INF"},
55+
},
56+
},
57+
},
58+
}
59+
for _, opt := range opts {
60+
opt(pod)
61+
}
62+
return pod
63+
}
64+
65+
func getPodEvents(namespace, podName string) (*corev1.EventList, error) {
66+
return testClient.K8sClient.CoreV1().Events(namespace).List(context.TODO(), metav1.ListOptions{
67+
FieldSelector: fmt.Sprintf("involvedObject.name=%s,involvedObject.kind=Pod", podName),
68+
})
69+
}
70+
71+
func cleanupTestPodsInNamespaces(namespaces []string) {
72+
for _, namespace := range namespaces {
73+
podList, err := testClient.K8sClient.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{})
74+
Expect(err).ToNot(HaveOccurred())
75+
76+
for _, pod := range podList.Items {
77+
err = testClient.K8sClient.CoreV1().Pods(namespace).Delete(context.TODO(), pod.Name, metav1.DeleteOptions{})
78+
if err != nil {
79+
continue
80+
}
81+
}
82+
83+
Eventually(func() int {
84+
list, listErr := testClient.K8sClient.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{})
85+
Expect(listErr).ToNot(HaveOccurred())
86+
return len(list.Items)
87+
}).WithTimeout(podCollisionCleanupTimeout).WithPolling(podCollisionCleanupInterval).Should(Equal(0),
88+
"All test pods in namespace %s should be deleted", namespace)
89+
}
90+
}

0 commit comments

Comments
 (0)