Skip to content

Commit 2ce13eb

Browse files
authored
Merge pull request kubernetes#126825 from ii/create-node-lifecycle-test
Write e2e test for Node endpoints +2 Endpoints
2 parents 08dd995 + 71d412b commit 2ce13eb

File tree

1 file changed

+117
-0
lines changed

1 file changed

+117
-0
lines changed

test/e2e/node/node_lifecycle.go

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
Copyright 2024 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package node
18+
19+
import (
20+
"context"
21+
"fmt"
22+
"time"
23+
24+
v1 "k8s.io/api/core/v1"
25+
apierrors "k8s.io/apimachinery/pkg/api/errors"
26+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27+
"k8s.io/apimachinery/pkg/labels"
28+
"k8s.io/apimachinery/pkg/types"
29+
utilrand "k8s.io/apimachinery/pkg/util/rand"
30+
"k8s.io/client-go/util/retry"
31+
"k8s.io/kubernetes/test/e2e/framework"
32+
admissionapi "k8s.io/pod-security-admission/api"
33+
34+
"github.com/onsi/ginkgo/v2"
35+
"github.com/onsi/gomega"
36+
)
37+
38+
var _ = SIGDescribe("Node Lifecycle", func() {
39+
40+
f := framework.NewDefaultFramework("fake-node")
41+
f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
42+
43+
ginkgo.It("should run through the lifecycle of a node", func(ctx context.Context) {
44+
// the scope of this test only covers the api-server
45+
46+
nodeClient := f.ClientSet.CoreV1().Nodes()
47+
48+
fakeNode := v1.Node{
49+
ObjectMeta: metav1.ObjectMeta{
50+
Name: "e2e-fake-node-" + utilrand.String(5),
51+
},
52+
Status: v1.NodeStatus{
53+
Phase: v1.NodeRunning,
54+
Conditions: []v1.NodeCondition{
55+
{
56+
Status: v1.ConditionTrue,
57+
Message: "Set from e2e test",
58+
Reason: "E2E",
59+
Type: v1.NodeReady,
60+
},
61+
},
62+
},
63+
}
64+
65+
ginkgo.By(fmt.Sprintf("Create %q", fakeNode.Name))
66+
createdNode, err := nodeClient.Create(ctx, &fakeNode, metav1.CreateOptions{})
67+
framework.ExpectNoError(err, "failed to create node %q", fakeNode.Name)
68+
gomega.Expect(createdNode.Name).To(gomega.Equal(fakeNode.Name), "Checking that the node has been created")
69+
70+
ginkgo.By(fmt.Sprintf("Getting %q", fakeNode.Name))
71+
retrievedNode, err := nodeClient.Get(ctx, fakeNode.Name, metav1.GetOptions{})
72+
framework.ExpectNoError(err, "Failed to retrieve Node %q", fakeNode.Name)
73+
gomega.Expect(retrievedNode.Name).To(gomega.Equal(fakeNode.Name), "Checking that the retrieved name has been found")
74+
75+
ginkgo.By(fmt.Sprintf("Patching %q", fakeNode.Name))
76+
payload := "{\"metadata\":{\"labels\":{\"" + fakeNode.Name + "\":\"patched\"}}}"
77+
patchedNode, err := nodeClient.Patch(ctx, fakeNode.Name, types.StrategicMergePatchType, []byte(payload), metav1.PatchOptions{})
78+
framework.ExpectNoError(err, "Failed to patch %q", fakeNode.Name)
79+
gomega.Expect(patchedNode.Labels).To(gomega.HaveKeyWithValue(fakeNode.Name, "patched"), "Checking that patched label has been applied")
80+
patchedSelector := labels.Set{fakeNode.Name: "patched"}.AsSelector().String()
81+
82+
ginkgo.By(fmt.Sprintf("Listing nodes with LabelSelector %q", patchedSelector))
83+
nodes, err := nodeClient.List(ctx, metav1.ListOptions{LabelSelector: patchedSelector})
84+
framework.ExpectNoError(err, "failed to list nodes")
85+
gomega.Expect(nodes.Items).To(gomega.HaveLen(1), "confirm that the patched node has been found")
86+
87+
ginkgo.By(fmt.Sprintf("Updating %q", fakeNode.Name))
88+
var updatedNode *v1.Node
89+
90+
err = retry.RetryOnConflict(retry.DefaultRetry, func() error {
91+
tmpNode, err := nodeClient.Get(ctx, fakeNode.Name, metav1.GetOptions{})
92+
framework.ExpectNoError(err, "Unable to get %q", fakeNode.Name)
93+
tmpNode.Labels[fakeNode.Name] = "updated"
94+
updatedNode, err = nodeClient.Update(ctx, tmpNode, metav1.UpdateOptions{})
95+
96+
return err
97+
})
98+
framework.ExpectNoError(err, "failed to update %q", fakeNode.Name)
99+
gomega.Expect(updatedNode.Labels).To(gomega.HaveKeyWithValue(fakeNode.Name, "updated"), "Checking that updated label has been applied")
100+
101+
ginkgo.By(fmt.Sprintf("Delete %q", fakeNode.Name))
102+
err = nodeClient.Delete(ctx, fakeNode.Name, metav1.DeleteOptions{})
103+
framework.ExpectNoError(err, "failed to delete node")
104+
105+
ginkgo.By(fmt.Sprintf("Confirm deletion of %q", fakeNode.Name))
106+
gomega.Eventually(ctx, func(ctx context.Context) error {
107+
_, err := nodeClient.Get(ctx, fakeNode.Name, metav1.GetOptions{})
108+
if apierrors.IsNotFound(err) {
109+
return nil
110+
}
111+
if err != nil {
112+
return fmt.Errorf("nodeClient.Get returned an unexpected error: %w", err)
113+
}
114+
return fmt.Errorf("node still exists: %s", fakeNode.Name)
115+
}, 3*time.Minute, 5*time.Second).Should(gomega.Succeed(), "Timeout while waiting to confirm Node deletion")
116+
})
117+
})

0 commit comments

Comments
 (0)