Skip to content

Commit 8d92cb2

Browse files
committed
minor changes
Signed-off-by: Ajay Mishra <ajmishra@nvidia.com>
1 parent 6477c72 commit 8d92cb2

2 files changed

Lines changed: 77 additions & 45 deletions

File tree

commons/pkg/kubeclient/nodepatch_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func node(labels, annotations map[string]string) *v1.Node {
3333
}
3434
}
3535

36-
func TestNodeMergePatch(t *testing.T) {
36+
func TestNodeMergePatch_MetadataChanges_ReturnsExpectedPatch(t *testing.T) {
3737
tests := []struct {
3838
name string
3939
original *v1.Node
@@ -110,7 +110,7 @@ func TestNodeMergePatch(t *testing.T) {
110110
// only one annotation and clears Spec entirely — and a patch derived from that
111111
// projection must not describe the fields the projection dropped, or it would erase
112112
// them on the real object.
113-
func TestNodeMergePatchLeavesProjectedFieldsAlone(t *testing.T) {
113+
func TestNodeMergePatch_ProjectedFields_LeavesThemAlone(t *testing.T) {
114114
projected := &v1.Node{
115115
ObjectMeta: metav1.ObjectMeta{
116116
Name: "node-1",
@@ -132,7 +132,7 @@ func TestNodeMergePatchLeavesProjectedFieldsAlone(t *testing.T) {
132132
"a cleared Spec must never reach the patch, or real taints would be dropped")
133133
}
134134

135-
func TestNodeMergePatchIgnoresSpecChanges(t *testing.T) {
135+
func TestNodeMergePatch_SpecChanges_ReturnsNoPatch(t *testing.T) {
136136
original := node(nil, nil)
137137
modified := original.DeepCopy()
138138
modified.Spec.Unschedulable = true

labeler/pkg/labeler/labeler_test.go

Lines changed: 74 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
"k8s.io/client-go/kubernetes"
3636
"k8s.io/client-go/kubernetes/fake"
3737
listersv1 "k8s.io/client-go/listers/core/v1"
38+
k8stesting "k8s.io/client-go/testing"
3839
"k8s.io/client-go/tools/cache"
3940
"k8s.io/client-go/util/retry"
4041
"sigs.k8s.io/controller-runtime/pkg/envtest"
@@ -2440,12 +2441,11 @@ func TestUpdateNodeLabelsForPod_ManagedGate(t *testing.T) {
24402441
})
24412442
}
24422443

2443-
// TestLabelerWriteCosts pins the API-call budget of the label write path. Reading the
2444-
// node from the informer cache instead of the API server is what makes a label change
2445-
// cost a single PATCH, and it lets a reconcile with nothing to do cost nothing at all
2446-
// — on a large cluster that difference is per node, on every reconcile.
2447-
func TestLabelerWriteCosts(t *testing.T) {
2448-
nodeName := "gpu-node"
2444+
// TestUpdateNodeLabels_CachedNode_UsesPatchOnly pins the API-call budget and payload
2445+
// of the label write path.
2446+
func TestUpdateNodeLabels_CachedNode_UsesPatchOnly(t *testing.T) {
2447+
const nodeName = "gpu-node"
2448+
24492449
clientset := fake.NewSimpleClientset(&corev1.Node{
24502450
ObjectMeta: metav1.ObjectMeta{
24512451
Name: nodeName,
@@ -2454,50 +2454,66 @@ func TestLabelerWriteCosts(t *testing.T) {
24542454
})
24552455

24562456
labeler, _ := startTransformTestLabeler(t, clientset, devicecounts.Config{})
2457-
2458-
// Let startup reconciliation settle, so every write counted below is one this
2459-
// test asked for.
24602457
requireCachedLabel(t, labeler, nodeName, KataEnabledLabel, LabelValueFalse)
24612458

2462-
t.Run("a label change costs one patch and nothing else", func(t *testing.T) {
2463-
// KataEnabledLabel is the labeler's own output, not one of the inputs
2464-
// nodeRequiresReconciliation watches, so dropping it cannot kick off a
2465-
// reconcile behind this test's back.
2466-
node, err := clientset.CoreV1().Nodes().Get(context.Background(), nodeName, metav1.GetOptions{})
2467-
require.NoError(t, err)
2468-
delete(node.Labels, KataEnabledLabel)
2469-
_, err = clientset.CoreV1().Nodes().Update(context.Background(), node, metav1.UpdateOptions{})
2470-
require.NoError(t, err)
2471-
2472-
requireCachedLabelAbsent(t, labeler, nodeName, KataEnabledLabel)
2473-
clientset.ClearActions()
2474-
2475-
require.NoError(t, labeler.updateNodeLabels(nodeName))
2459+
tests := []struct {
2460+
name string
2461+
setup func(*testing.T)
2462+
expectedPatch string
2463+
}{
2464+
{
2465+
name: "label change costs one merge patch",
2466+
setup: func(t *testing.T) {
2467+
node, getErr := clientset.CoreV1().Nodes().Get(t.Context(), nodeName, metav1.GetOptions{})
2468+
require.NoError(t, getErr)
2469+
delete(node.Labels, KataEnabledLabel)
2470+
_, updateErr := clientset.CoreV1().Nodes().Update(t.Context(), node, metav1.UpdateOptions{})
2471+
require.NoError(t, updateErr)
2472+
requireCachedLabelAbsent(t, labeler, nodeName, KataEnabledLabel)
2473+
},
2474+
expectedPatch: fmt.Sprintf(
2475+
`{"metadata":{"labels":{%q:%q}}}`,
2476+
KataEnabledLabel,
2477+
LabelValueFalse,
2478+
),
2479+
},
2480+
{
2481+
name: "no-op reconcile costs no API call",
2482+
setup: func(t *testing.T) {
2483+
requireCachedLabel(t, labeler, nodeName, KataEnabledLabel, LabelValueFalse)
2484+
},
2485+
},
2486+
}
24762487

2477-
assert.Equal(t, 1, countNodeActions(clientset, "patch"), "the write itself")
2478-
assert.Equal(t, 0, countNodeActions(clientset, "get"), "the node came from the cache")
2479-
assert.Equal(t, 0, countNodeActions(clientset, "update"), "PUT is no longer used")
2488+
for _, tt := range tests {
2489+
t.Run(tt.name, func(t *testing.T) {
2490+
tt.setup(t)
2491+
clientset.ClearActions()
24802492

2481-
updated, err := clientset.CoreV1().Nodes().Get(context.Background(), nodeName, metav1.GetOptions{})
2482-
require.NoError(t, err)
2483-
assert.Equal(t, LabelValueFalse, updated.Labels[KataEnabledLabel], "the patch landed")
2484-
assert.Equal(t, LabelValueTrue, updated.Labels[gpuPresentLabel],
2485-
"a merge patch must leave labels it does not mention alone")
2486-
})
2493+
require.NoError(t, labeler.updateNodeLabels(nodeName))
24872494

2488-
t.Run("a reconcile with nothing to do costs no api call", func(t *testing.T) {
2489-
requireCachedLabel(t, labeler, nodeName, KataEnabledLabel, LabelValueFalse)
2490-
clientset.ClearActions()
2495+
expectedPatchCount := 0
2496+
if tt.expectedPatch != "" {
2497+
expectedPatchCount = 1
2498+
action := nodePatchAction(t, clientset.Actions())
2499+
assert.Equal(t, types.MergePatchType, action.GetPatchType())
2500+
assert.JSONEq(t, tt.expectedPatch, string(action.GetPatch()))
2501+
}
24912502

2492-
require.NoError(t, labeler.updateNodeLabels(nodeName))
2503+
assert.Equal(t, expectedPatchCount, countNodeActions(clientset, "patch"))
2504+
assert.Equal(t, 0, countNodeActions(clientset, "get"))
2505+
assert.Equal(t, 0, countNodeActions(clientset, "update"))
24932506

2494-
assert.Equal(t, 0, countNodeActions(clientset, "patch"))
2495-
assert.Equal(t, 0, countNodeActions(clientset, "get"))
2496-
assert.Equal(t, 0, countNodeActions(clientset, "update"))
2497-
})
2507+
updated, getErr := clientset.CoreV1().Nodes().Get(t.Context(), nodeName, metav1.GetOptions{})
2508+
require.NoError(t, getErr)
2509+
assert.Equal(t, LabelValueFalse, updated.Labels[KataEnabledLabel], "the desired label is present")
2510+
assert.Equal(t, LabelValueTrue, updated.Labels[gpuPresentLabel],
2511+
"a merge patch must leave labels it does not mention alone")
2512+
})
2513+
}
24982514
}
24992515

2500-
// TestLabelsConvergeUnderNodeChurn attacks the assumption the PATCH path rests on:
2516+
// TestLabelsConvergeUnderNodeChurn_FinalInputs_Converge attacks the assumption the PATCH path rests on:
25012517
// that reading the node from the informer cache can go stale without ever losing a
25022518
// write.
25032519
//
@@ -2513,7 +2529,7 @@ func TestLabelerWriteCosts(t *testing.T) {
25132529
// The churn below rewrites the input far faster than the cache can follow. Whatever
25142530
// the labeler does in the middle, every node has to end up on the label its final
25152531
// input implies.
2516-
func TestLabelsConvergeUnderNodeChurn(t *testing.T) {
2532+
func TestLabelsConvergeUnderNodeChurn_FinalInputs_Converge(t *testing.T) {
25172533
const (
25182534
nodeCount = 20
25192535
rounds = 8
@@ -2613,6 +2629,22 @@ func countNodeActions(clientset *fake.Clientset, verb string) int {
26132629
return count
26142630
}
26152631

2632+
func nodePatchAction(t *testing.T, actions []k8stesting.Action) k8stesting.PatchAction {
2633+
t.Helper()
2634+
2635+
for _, action := range actions {
2636+
if action.GetVerb() == "patch" && action.GetResource().Resource == "nodes" {
2637+
patchAction, ok := action.(k8stesting.PatchAction)
2638+
require.True(t, ok)
2639+
2640+
return patchAction
2641+
}
2642+
}
2643+
2644+
require.FailNow(t, "node PATCH action not found")
2645+
return nil
2646+
}
2647+
26162648
// requireCachedLabel waits for the informer cache to show the given label, which is
26172649
// how a test tells that the labeler has finished reacting to earlier events.
26182650
func requireCachedLabel(t *testing.T, l *Labeler, nodeName, key, value string) {

0 commit comments

Comments
 (0)