Skip to content

Commit 716d059

Browse files
committed
Improve tests for the bootserver
1 parent 901b4e7 commit 716d059

File tree

5 files changed

+181
-8
lines changed

5 files changed

+181
-8
lines changed

api/v1alpha1/constants.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
package v1alpha1
55

66
const (
7-
DefaultIgnitionKey = "ignition" // Key for accessing Ignition configuration data within a Kubernetes Secret object.
8-
DefaultIPXEScriptKey = "ipxe-script" // Key for accessing iPXE script data within the iPXE-specific Secret object.
9-
SystemUUIDIndexKey = "spec.systemUUID" // Field to index resources by their system UUID.
10-
SystemIPIndexKey = "spec.systemIPs" // Field to index resources by their system IP addresses.
11-
DefaultFormatKey = "format" // Key for determining the format of the data stored in a Secret, such as fcos or plain-ignition.
12-
FCOSFormat = "fcos" // Specifies the format value used for Fedora CoreOS specific configurations.
7+
DefaultIgnitionKey = "ignition" // Key for accessing Ignition configuration data within a Kubernetes Secret object.
8+
DefaultIPXEScriptKey = "ipxe-script" // Key for accessing iPXE script data within the iPXE-specific Secret object.
9+
SystemUUIDIndexKey = "spec.systemUUID" // Field to index resources by their system UUID.
10+
SystemIPIndexKey = "spec.systemIPs" // Field to index resources by their system IP addresses.
11+
NetworkIdentifierIndexKey = "spec.networkIdentifiers" // Field to index resources by their network identifiers (IP addresses and MAC addresses).
12+
DefaultFormatKey = "format" // Key for determining the format of the data stored in a Secret, such as fcos or plain-ignition.
13+
FCOSFormat = "fcos" // Specifies the format value used for Fedora CoreOS specific configurations.
1314
)

cmd/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ func IndexHTTPBootConfigByNetworkIDs(ctx context.Context, mgr ctrl.Manager) erro
354354
return mgr.GetFieldIndexer().IndexField(
355355
ctx,
356356
&bootv1alpha1.HTTPBootConfig{},
357-
bootv1alpha1.SystemIPIndexKey,
357+
bootv1alpha1.NetworkIdentifierIndexKey,
358358
func(Obj client.Object) []string {
359359
HTTPBootConfig := Obj.(*bootv1alpha1.HTTPBootConfig)
360360
return HTTPBootConfig.Spec.NetworkIdentifiers

server/bootserver.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ func handleHTTPBoot(w http.ResponseWriter, r *http.Request, k8sClient client.Cli
393393

394394
var httpBootConfigs bootv1alpha1.HTTPBootConfigList
395395
for _, ip := range clientIPs {
396-
if err := k8sClient.List(ctx, &httpBootConfigs, client.MatchingFields{bootv1alpha1.SystemIPIndexKey: ip}); err != nil {
396+
if err := k8sClient.List(ctx, &httpBootConfigs, client.MatchingFields{bootv1alpha1.NetworkIdentifierIndexKey: ip}); err != nil {
397397
log.Info("Failed to list HTTPBootConfig for IP", "IP", ip, "error", err)
398398
continue
399399
}

server/bootserver_suit_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package server
5+
6+
import (
7+
"net/http"
8+
"testing"
9+
10+
"github.com/go-logr/logr"
11+
bootv1alpha1 "github.com/ironcore-dev/boot-operator/api/v1alpha1"
12+
. "github.com/onsi/ginkgo/v2"
13+
. "github.com/onsi/gomega"
14+
corev1 "k8s.io/api/core/v1"
15+
"k8s.io/apimachinery/pkg/runtime"
16+
"sigs.k8s.io/controller-runtime/pkg/client"
17+
"sigs.k8s.io/controller-runtime/pkg/client/fake"
18+
)
19+
20+
var (
21+
testServerAddr = ":30003"
22+
testServerURL = "http://localhost:30003"
23+
24+
defaultUKIURL = "https://example.com/default.efi"
25+
ipxeServiceURL = "http://localhost:30004"
26+
27+
k8sClient client.Client
28+
)
29+
30+
func TestBootServer(t *testing.T) {
31+
RegisterFailHandler(Fail)
32+
RunSpecs(t, "Boot Server Suite")
33+
}
34+
35+
var _ = BeforeSuite(func() {
36+
scheme := runtime.NewScheme()
37+
Expect(corev1.AddToScheme(scheme)).To(Succeed())
38+
Expect(bootv1alpha1.AddToScheme(scheme)).To(Succeed())
39+
40+
k8sClient = fake.NewClientBuilder().
41+
WithScheme(scheme).
42+
Build()
43+
44+
go func() {
45+
defer GinkgoRecover()
46+
RunBootServer(testServerAddr, ipxeServiceURL, k8sClient, logr.Discard(), defaultUKIURL)
47+
}()
48+
49+
Eventually(func() error {
50+
_, err := http.Get(testServerURL + "/httpboot")
51+
return err
52+
}, "5s", "200ms").Should(Succeed())
53+
})

server/bootserver_test.go

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package server
5+
6+
import (
7+
"context"
8+
"encoding/json"
9+
"net/http"
10+
11+
"github.com/go-logr/logr"
12+
bootv1alpha1 "github.com/ironcore-dev/boot-operator/api/v1alpha1"
13+
. "github.com/onsi/ginkgo/v2"
14+
. "github.com/onsi/gomega"
15+
corev1 "k8s.io/api/core/v1"
16+
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
17+
)
18+
19+
type httpBootResponse struct {
20+
ClientIPs string `json:"ClientIPs"`
21+
UKIURL string `json:"UKIURL"`
22+
SystemUUID string `json:"SystemUUID,omitempty"`
23+
}
24+
25+
var _ = Describe("BootServer", func() {
26+
Context("/httpboot endpoint", func() {
27+
It("delivers default httpboot data when no HTTPBootConfig matches the client IP", func() {
28+
resp, err := http.Get(testServerURL + "/httpboot")
29+
Expect(err).NotTo(HaveOccurred())
30+
defer func() {
31+
_ = resp.Body.Close()
32+
}()
33+
34+
Expect(resp.StatusCode).To(Equal(http.StatusOK))
35+
Expect(resp.Header.Get("Content-Type")).To(Equal("application/json"))
36+
37+
var body httpBootResponse
38+
Expect(json.NewDecoder(resp.Body).Decode(&body)).To(Succeed())
39+
40+
By("returning the default UKI URL")
41+
Expect(body.UKIURL).To(Equal(defaultUKIURL))
42+
43+
By("including the recorded client IPs")
44+
Expect(body.ClientIPs).NotTo(BeEmpty())
45+
46+
By("not setting a SystemUUID in the default case")
47+
Expect(body.SystemUUID).To(SatisfyAny(BeEmpty(), Equal("")))
48+
})
49+
})
50+
51+
It("converts valid Butane YAML to JSON", func() {
52+
butaneYAML := []byte(`
53+
variant: fcos
54+
version: 1.5.0
55+
systemd:
56+
units:
57+
- name: test.service
58+
enabled: true
59+
`)
60+
61+
jsonData, err := renderIgnition(butaneYAML)
62+
Expect(err).ToNot(HaveOccurred())
63+
Expect(jsonData).ToNot(BeEmpty())
64+
Expect(string(jsonData)).To(ContainSubstring(`"systemd"`))
65+
})
66+
67+
It("returns an error for invalid YAML", func() {
68+
bad := []byte("this ::: is not yaml")
69+
_, err := renderIgnition(bad)
70+
Expect(err).To(HaveOccurred())
71+
})
72+
73+
Context("Verify the SetStatusCondition method", func() {
74+
75+
var testLog = logr.Discard()
76+
77+
It("returns an error for unknown condition type", func() {
78+
cfg := &bootv1alpha1.IPXEBootConfig{
79+
ObjectMeta: v1.ObjectMeta{
80+
Name: "unknown-cond",
81+
Namespace: "default",
82+
},
83+
}
84+
Expect(k8sClient.Create(context.Background(), cfg)).To(Succeed())
85+
86+
err := SetStatusCondition(
87+
context.Background(),
88+
k8sClient,
89+
testLog,
90+
cfg,
91+
"DoesNotExist",
92+
)
93+
94+
Expect(err).To(HaveOccurred())
95+
Expect(err.Error()).To(ContainSubstring("condition type DoesNotExist not found"))
96+
})
97+
98+
It("returns an error for unsupported resource types", func() {
99+
secret := &corev1.Secret{
100+
ObjectMeta: v1.ObjectMeta{
101+
Name: "bad-type",
102+
Namespace: "default",
103+
},
104+
}
105+
_ = k8sClient.Create(context.Background(), secret)
106+
107+
err := SetStatusCondition(
108+
context.Background(),
109+
k8sClient,
110+
testLog,
111+
secret,
112+
"IgnitionDataFetched",
113+
)
114+
115+
Expect(err).To(HaveOccurred())
116+
Expect(err.Error()).To(ContainSubstring("unsupported resource type"))
117+
})
118+
})
119+
})

0 commit comments

Comments
 (0)