Skip to content

Commit 2a2f478

Browse files
committed
test: Improve pkg/exporters/kubernetes test coverage from 74.7% to 83.3%
Add comprehensive tests for previously uncovered functions: - IsReloadable, Reload, needsClientRecreation, annotationsEqual - performHealthCheck, logMetrics, StatsWithLastError - ReloadWithClientRecreation - ConditionUpdate.String - ConvertConditionsToNodeConditions with status mapping and type prefixing All tests use table-driven patterns and cover edge cases including nil inputs, empty collections, and error conditions.
1 parent 8175489 commit 2a2f478

File tree

2 files changed

+753
-0
lines changed

2 files changed

+753
-0
lines changed

pkg/exporters/kubernetes/client_test.go

Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package kubernetes
22

33
import (
44
"context"
5+
"strings"
56
"testing"
67
"time"
78

@@ -452,3 +453,278 @@ func TestJsonMarshal(t *testing.T) {
452453
})
453454
}
454455
}
456+
457+
// TestConditionUpdateString tests the String method of ConditionUpdate
458+
func TestConditionUpdateString(t *testing.T) {
459+
tests := []struct {
460+
name string
461+
update ConditionUpdate
462+
expected string
463+
}{
464+
{
465+
name: "true condition",
466+
update: ConditionUpdate{
467+
Type: "TestCondition",
468+
Status: corev1.ConditionTrue,
469+
Reason: "TestReason",
470+
Message: "Test message",
471+
},
472+
expected: "TestCondition=True: Test message",
473+
},
474+
{
475+
name: "false condition",
476+
update: ConditionUpdate{
477+
Type: "FailedCondition",
478+
Status: corev1.ConditionFalse,
479+
Reason: "Failed",
480+
Message: "Something failed",
481+
},
482+
expected: "FailedCondition=False: Something failed",
483+
},
484+
{
485+
name: "unknown condition",
486+
update: ConditionUpdate{
487+
Type: "UnknownCondition",
488+
Status: corev1.ConditionUnknown,
489+
Reason: "Unknown",
490+
Message: "Status is unknown",
491+
},
492+
expected: "UnknownCondition=Unknown: Status is unknown",
493+
},
494+
{
495+
name: "empty message",
496+
update: ConditionUpdate{
497+
Type: "EmptyMessage",
498+
Status: corev1.ConditionTrue,
499+
Reason: "EmptyReason",
500+
Message: "",
501+
},
502+
expected: "EmptyMessage=True: ",
503+
},
504+
}
505+
506+
for _, tt := range tests {
507+
t.Run(tt.name, func(t *testing.T) {
508+
got := tt.update.String()
509+
if got != tt.expected {
510+
t.Errorf("ConditionUpdate.String() = %q, want %q", got, tt.expected)
511+
}
512+
})
513+
}
514+
}
515+
516+
// TestConvertConditionsToNodeConditions tests the ConvertConditionsToNodeConditions function
517+
func TestConvertConditionsToNodeConditions(t *testing.T) {
518+
now := time.Now()
519+
520+
tests := []struct {
521+
name string
522+
conditions []types.Condition
523+
wantCount int
524+
}{
525+
{
526+
name: "empty conditions",
527+
conditions: []types.Condition{},
528+
wantCount: 0,
529+
},
530+
{
531+
name: "nil conditions",
532+
conditions: nil,
533+
wantCount: 0,
534+
},
535+
{
536+
name: "single condition",
537+
conditions: []types.Condition{
538+
{
539+
Type: "TestCondition",
540+
Status: types.ConditionTrue,
541+
Transition: now,
542+
Reason: "TestReason",
543+
Message: "Test message",
544+
},
545+
},
546+
wantCount: 1,
547+
},
548+
{
549+
name: "multiple conditions",
550+
conditions: []types.Condition{
551+
{
552+
Type: "Condition1",
553+
Status: types.ConditionTrue,
554+
Transition: now,
555+
Reason: "Reason1",
556+
Message: "Message 1",
557+
},
558+
{
559+
Type: "Condition2",
560+
Status: types.ConditionFalse,
561+
Transition: now,
562+
Reason: "Reason2",
563+
Message: "Message 2",
564+
},
565+
{
566+
Type: "Condition3",
567+
Status: types.ConditionUnknown,
568+
Transition: now,
569+
Reason: "Reason3",
570+
Message: "Message 3",
571+
},
572+
},
573+
wantCount: 3,
574+
},
575+
}
576+
577+
for _, tt := range tests {
578+
t.Run(tt.name, func(t *testing.T) {
579+
result := ConvertConditionsToNodeConditions(tt.conditions)
580+
if len(result) != tt.wantCount {
581+
t.Errorf("ConvertConditionsToNodeConditions() returned %d conditions, want %d", len(result), tt.wantCount)
582+
}
583+
584+
// Verify the conversion was correct for non-empty results
585+
for i, cond := range result {
586+
if tt.wantCount > 0 {
587+
// Check that the condition type was set
588+
if string(cond.Type) == "" {
589+
t.Errorf("Condition %d has empty type", i)
590+
}
591+
// Check that status was mapped correctly
592+
if cond.Status == "" {
593+
t.Errorf("Condition %d has empty status", i)
594+
}
595+
}
596+
}
597+
})
598+
}
599+
}
600+
601+
// TestConvertConditionsToNodeConditionsStatusMapping tests status mapping in ConvertConditionsToNodeConditions
602+
func TestConvertConditionsToNodeConditionsStatusMapping(t *testing.T) {
603+
now := time.Now()
604+
605+
tests := []struct {
606+
name string
607+
inputStatus types.ConditionStatus
608+
expectStatus corev1.ConditionStatus
609+
}{
610+
{
611+
name: "True status",
612+
inputStatus: types.ConditionTrue,
613+
expectStatus: corev1.ConditionTrue,
614+
},
615+
{
616+
name: "False status",
617+
inputStatus: types.ConditionFalse,
618+
expectStatus: corev1.ConditionFalse,
619+
},
620+
{
621+
name: "Unknown status",
622+
inputStatus: types.ConditionUnknown,
623+
expectStatus: corev1.ConditionUnknown,
624+
},
625+
{
626+
name: "Invalid status defaults to Unknown",
627+
inputStatus: types.ConditionStatus("Invalid"),
628+
expectStatus: corev1.ConditionUnknown,
629+
},
630+
}
631+
632+
for _, tt := range tests {
633+
t.Run(tt.name, func(t *testing.T) {
634+
conditions := []types.Condition{
635+
{
636+
Type: "TestCondition",
637+
Status: tt.inputStatus,
638+
Transition: now,
639+
Reason: "TestReason",
640+
Message: "Test message",
641+
},
642+
}
643+
644+
result := ConvertConditionsToNodeConditions(conditions)
645+
if len(result) != 1 {
646+
t.Fatalf("Expected 1 condition, got %d", len(result))
647+
}
648+
649+
if result[0].Status != tt.expectStatus {
650+
t.Errorf("ConvertConditionsToNodeConditions() status = %v, want %v", result[0].Status, tt.expectStatus)
651+
}
652+
})
653+
}
654+
}
655+
656+
// TestConvertConditionsToNodeConditionsTypePrefixing tests that non-standard conditions get prefixed
657+
func TestConvertConditionsToNodeConditionsTypePrefixing(t *testing.T) {
658+
now := time.Now()
659+
660+
tests := []struct {
661+
name string
662+
inputType string
663+
shouldBePrefixed bool
664+
}{
665+
{
666+
name: "Ready is not prefixed (standard)",
667+
inputType: "Ready",
668+
shouldBePrefixed: false,
669+
},
670+
{
671+
name: "MemoryPressure is not prefixed (standard)",
672+
inputType: "MemoryPressure",
673+
shouldBePrefixed: false,
674+
},
675+
{
676+
name: "DiskPressure is not prefixed (standard)",
677+
inputType: "DiskPressure",
678+
shouldBePrefixed: false,
679+
},
680+
{
681+
name: "PIDPressure is not prefixed (standard)",
682+
inputType: "PIDPressure",
683+
shouldBePrefixed: false,
684+
},
685+
{
686+
name: "NetworkUnavailable is not prefixed (standard)",
687+
inputType: "NetworkUnavailable",
688+
shouldBePrefixed: false,
689+
},
690+
{
691+
name: "CustomCondition is prefixed",
692+
inputType: "CustomCondition",
693+
shouldBePrefixed: true,
694+
},
695+
{
696+
name: "ServiceFailed is prefixed",
697+
inputType: "ServiceFailed",
698+
shouldBePrefixed: true,
699+
},
700+
}
701+
702+
for _, tt := range tests {
703+
t.Run(tt.name, func(t *testing.T) {
704+
conditions := []types.Condition{
705+
{
706+
Type: tt.inputType,
707+
Status: types.ConditionTrue,
708+
Transition: now,
709+
Reason: "TestReason",
710+
Message: "Test message",
711+
},
712+
}
713+
714+
result := ConvertConditionsToNodeConditions(conditions)
715+
if len(result) != 1 {
716+
t.Fatalf("Expected 1 condition, got %d", len(result))
717+
}
718+
719+
condType := string(result[0].Type)
720+
hasPrefix := strings.HasPrefix(condType, "NodeDoctor")
721+
722+
if tt.shouldBePrefixed && !hasPrefix {
723+
t.Errorf("Expected condition type %q to be prefixed with NodeDoctor, got %q", tt.inputType, condType)
724+
}
725+
if !tt.shouldBePrefixed && hasPrefix {
726+
t.Errorf("Expected condition type %q to NOT be prefixed, got %q", tt.inputType, condType)
727+
}
728+
})
729+
}
730+
}

0 commit comments

Comments
 (0)