Skip to content

Commit 9bba282

Browse files
kkumardamyan
kkumar
authored andcommitted
Add tests for OOB plugin
1 parent e098ef8 commit 9bba282

File tree

4 files changed

+481
-1
lines changed

4 files changed

+481
-1
lines changed

internal/kubernetes/client.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,7 @@ func SetClient(client *client.Client) {
4444
func GetClient() client.Client { return kubeClient }
4545

4646
func GetConfig() *rest.Config { return cfg }
47+
48+
func SetConfig(c *rest.Config) {
49+
cfg = c
50+
}

plugins/oob/k8s.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ func (k K8sClient) doCreateIpamIP(
240240
} else {
241241
ipamIP, err = k.waitForCreation(ipamIP)
242242
if err != nil {
243-
return nil, fmt.Errorf("failed to create IP %s/%s: %w", ipamIP.Namespace, ipamIP.Name, err)
243+
return nil, fmt.Errorf("failed to create IP %w", err)
244244
} else {
245245
log.Infof("New IP %s (%s/%s) created in subnet %s", ipamIP.Status.Reserved.String(),
246246
ipamIP.Namespace, ipamIP.Name, ipamIP.Spec.Subnet.Name)

plugins/oob/plugin_test.go

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors
2+
// SPDX-License-Identifier: MIT
3+
4+
package oob
5+
6+
import (
7+
"net"
8+
"os"
9+
10+
"github.com/insomniacslk/dhcp/dhcpv4"
11+
"github.com/insomniacslk/dhcp/dhcpv6"
12+
"github.com/ironcore-dev/fedhcp/internal/api"
13+
ipamv1alpha1 "github.com/ironcore-dev/ipam/api/ipam/v1alpha1"
14+
"github.com/mdlayher/netx/eui64"
15+
. "github.com/onsi/ginkgo/v2"
16+
. "github.com/onsi/gomega"
17+
"gopkg.in/yaml.v2"
18+
)
19+
20+
var _ = Describe("OOB Plugin", func() {
21+
var (
22+
err error
23+
)
24+
25+
Describe("Configuration Loading", func() {
26+
It("should successfully load a valid configuration file", func() {
27+
config, err := loadConfig(testConfigPath)
28+
Expect(err).NotTo(HaveOccurred())
29+
Expect(config).NotTo(BeNil())
30+
Expect(config.Namespace).To(Equal(ns.Name))
31+
Expect(config.SubnetLabel).To(Equal("subnet=foo"))
32+
})
33+
34+
It("should return an error if the configuration file is missing", func() {
35+
_, err := loadConfig("nonexistent.yaml")
36+
Expect(err).To(HaveOccurred())
37+
})
38+
39+
It("should return an error if the configuration file is invalid", func() {
40+
err = os.WriteFile(testConfigPath, []byte("Invalid YAML"), 0644)
41+
Expect(err).NotTo(HaveOccurred())
42+
_, err = loadConfig(testConfigPath)
43+
Expect(err).To(HaveOccurred())
44+
})
45+
})
46+
47+
Describe("Plugin Setup6", func() {
48+
It("should return an error for invalid subnetLabel in the config", func() {
49+
invalidConfig := &api.OOBConfig{
50+
Namespace: ns.Name,
51+
SubnetLabel: "subnet-foo",
52+
}
53+
invalidConfigData, err := yaml.Marshal(invalidConfig)
54+
Expect(err).NotTo(HaveOccurred())
55+
file, err := os.CreateTemp(GinkgoT().TempDir(), "invalidConfig.yaml")
56+
Expect(err).NotTo(HaveOccurred())
57+
defer func() {
58+
_ = file.Close()
59+
}()
60+
Expect(os.WriteFile(file.Name(), invalidConfigData, 0644)).To(Succeed())
61+
62+
_, err = setup6(file.Name())
63+
Expect(err).To(HaveOccurred())
64+
Expect(err.Error()).To(ContainSubstring("should be 'key=value'"))
65+
})
66+
67+
It("Setup6 should return error if less arguments are provided", func() {
68+
_, err := setup6()
69+
Expect(err).To(HaveOccurred())
70+
})
71+
72+
It("Setup6 should return error if more arguments are provided", func() {
73+
_, err := setup6("foo", "bar")
74+
Expect(err).To(HaveOccurred())
75+
})
76+
77+
It("Setup6 should return error if config file does not exist", func() {
78+
_, err := setup6("does-not-exist.yaml")
79+
Expect(err).To(HaveOccurred())
80+
})
81+
82+
})
83+
84+
Describe("Plugin handler6", func() {
85+
It("Should break plugin chain, if getting an IPv6 DHCP request directly (no relay)", func() {
86+
req, _ := dhcpv6.NewMessage()
87+
req.MessageType = dhcpv6.MessageTypeRequest
88+
89+
stub, _ := dhcpv6.NewMessage()
90+
stub.MessageType = dhcpv6.MessageTypeReply
91+
resp, breakChain := handler6(req, stub)
92+
93+
Eventually(resp).Should(BeNil())
94+
Eventually(breakChain).Should(BeTrue())
95+
})
96+
97+
It("should successfully handle request", func() {
98+
req, _ := dhcpv6.NewMessage()
99+
req.MessageType = dhcpv6.MessageTypeRequest
100+
relayedRequest, _ := dhcpv6.EncapsulateRelay(req, dhcpv6.MessageTypeRelayForward, linkLocalIPV6Addr, linkLocalIPV6Addr)
101+
102+
res, _ := dhcpv6.NewMessage()
103+
resp, stop := handler6(relayedRequest, res)
104+
Expect(stop).To(BeFalse())
105+
Expect(resp).NotTo(BeNil())
106+
})
107+
})
108+
109+
Describe("K8s Client tests", func() {
110+
It("should successfully match the subnet", func() {
111+
subnets := k8sClient.getOOBNetworks(ipamv1alpha1.CIPv6SubnetType)
112+
Expect(subnets).NotTo(BeNil())
113+
Expect(subnets).To(HaveLen(1))
114+
})
115+
116+
It("should match the subnet", func() {
117+
subnet, err := k8sClient.getMatchingSubnet("foo-v6", linkLocalIPV6Addr)
118+
Expect(err).NotTo(HaveOccurred())
119+
Expect(subnet).NotTo(BeNil())
120+
})
121+
122+
It("should return (nil, nil) and not match the subnet if random subnet passed", func() {
123+
subnet, err := k8sClient.getMatchingSubnet("randomfoo", linkLocalIPV6Addr)
124+
Expect(err).ToNot(HaveOccurred())
125+
Expect(subnet).To(BeNil())
126+
})
127+
128+
It("should not match the subnet", func() {
129+
m, err := net.ParseMAC(unknownMachineMACAddress)
130+
Expect(err).NotTo(HaveOccurred())
131+
i := net.ParseIP("fe90::")
132+
unknownIPV6Addr, err := eui64.ParseMAC(i, m)
133+
Expect(err).NotTo(HaveOccurred())
134+
135+
subnet, err := k8sClient.getMatchingSubnet("foo", unknownIPV6Addr)
136+
Expect(err).ToNot(HaveOccurred())
137+
Expect(subnet).To(BeNil())
138+
})
139+
140+
It("return true checks the ip in CIDR", func() {
141+
checkIP := checkIPInCIDR(linkLocalIPV6Addr, "fe80::/64")
142+
Expect(checkIP).To(BeTrue())
143+
})
144+
145+
It("return false, if invalid CIDR", func() {
146+
checkIP := checkIPInCIDR(linkLocalIPV6Addr, "fe80::")
147+
Expect(checkIP).To(BeFalse())
148+
})
149+
})
150+
151+
Describe("Plugin Setup4", func() {
152+
It("should return an error for invalid subnetLabel in the config", func() {
153+
invalidConfig := &api.OOBConfig{
154+
Namespace: ns.Name,
155+
SubnetLabel: "subnet-foo",
156+
}
157+
invalidConfigData, err := yaml.Marshal(invalidConfig)
158+
Expect(err).NotTo(HaveOccurred())
159+
file, err := os.CreateTemp(GinkgoT().TempDir(), "invalidConfig.yaml")
160+
Expect(err).NotTo(HaveOccurred())
161+
defer func() {
162+
_ = file.Close()
163+
}()
164+
Expect(os.WriteFile(file.Name(), invalidConfigData, 0644)).To(Succeed())
165+
166+
_, err = setup4(file.Name())
167+
Expect(err).To(HaveOccurred())
168+
Expect(err.Error()).To(ContainSubstring("should be 'key=value'"))
169+
})
170+
171+
It("Setup6 should return error if less arguments are provided", func() {
172+
_, err := setup4()
173+
Expect(err).To(HaveOccurred())
174+
})
175+
176+
It("Setup6 should return error if more arguments are provided", func() {
177+
_, err := setup4("foo", "bar")
178+
Expect(err).To(HaveOccurred())
179+
})
180+
181+
It("Setup6 should return error if config file does not exist", func() {
182+
_, err := setup4("does-not-exist.yaml")
183+
Expect(err).To(HaveOccurred())
184+
})
185+
})
186+
187+
Describe("Plugin handler4", func() {
188+
It("Should break plugin chain, if not sending empty request ", func() {
189+
req, _ := dhcpv4.New()
190+
resp, _ := dhcpv4.NewReplyFromRequest(req)
191+
resp, stop := handler4(req, resp)
192+
Expect(stop).To(BeTrue())
193+
Expect(resp).To(BeNil())
194+
})
195+
196+
It("should successfully handle request", func() {
197+
req, _ := dhcpv4.New()
198+
req.ClientHWAddr, _ = net.ParseMAC(machineWithIPAddressMACAddress)
199+
req.ClientIPAddr = net.ParseIP(privateIPV4Address)
200+
resp, _ := dhcpv4.NewReplyFromRequest(req)
201+
202+
_, stop := handler4(req, resp)
203+
Expect(stop).To(BeFalse())
204+
Expect(resp).NotTo(BeNil())
205+
})
206+
})
207+
})

0 commit comments

Comments
 (0)