test: add integration test for NSWatcher with fake Kubernetes client

TestStartManagedNamespaceWatcherIntegration проверяет полный маршрут
горячей регистрации namespace без real cluster:

1. RunManagedNamespaceWatcher запускается с k8sfake.NewSimpleClientset()
2. В fake client создаётся Namespace с label fission.io/managed=true
3. Kubernetes informer детектирует событие (без polling, через Watch)
4. SubscriberFuncs.OnNamespaceAdd вызывается
5. NamespaceManager содержит запись со статусом Active

Тест доказывает, что вся цепочка
  fake k8s event → informer → AddFunc → subscriber → manager
работает корректно без rolling restart процесса.

Также добавлен import metav1 в test file (требовался для CreateOptions).
This commit is contained in:
“Naeel”
2026-05-15 07:11:48 +04:00
parent 5f0ab79f00
commit 5d52c9ba94
+71
View File
@@ -10,6 +10,7 @@ import (
"go.uber.org/zap"
"go.uber.org/zap/zaptest/observer"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8sfake "k8s.io/client-go/kubernetes/fake"
k8sCache "k8s.io/client-go/tools/cache"
@@ -818,6 +819,76 @@ func TestNamespaceManagerDispatchRemoveFailure(t *testing.T) {
}
}
// TestStartManagedNamespaceWatcherIntegration проверяет полный маршрут:
// fake k8s client → информер → AddFunc → subscriber.OnNamespaceAdd.
// Это интеграционный тест без real cluster — использует k8sfake.
func TestStartManagedNamespaceWatcherIntegration(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fakeClient := k8sfake.NewSimpleClientset()
mgr := managerPkg.New()
router := &testNamespaceSubscriber{name: "router"}
// Запускаем watcher — не Bootstrap, только informer.
// config.Namespaces пусто, чтобы не было pre-loaded namespace-ов.
manager, err := RunManagedNamespaceWatcher(ctx, zap.NewNop(), fakeClient, mgr, ManagedNamespaceWatcherConfig{
Component: "router.NSWatcher",
Namespaces: nil,
RemovalStrategy: NamespaceRemovalStrategyTrackOnly,
Subscriber: router,
})
if err != nil {
t.Fatalf("RunManagedNamespaceWatcher failed: %v", err)
}
// Создаём namespace с managed label в fake client.
ns := &corev1.Namespace{}
ns.Name = "tenant-integration-a"
ns.Labels = map[string]string{ManagedNamespaceLabelKey: ManagedNamespaceLabelValue}
if _, err := fakeClient.CoreV1().Namespaces().Create(ctx, ns, metav1.CreateOptions{}); err != nil {
t.Fatalf("failed to create test namespace in fake client: %v", err)
}
// Ждём, пока informer обработает event и subscriber получит вызов.
// Timeout намеренно короткий (3 секунды) — fake client синхронный.
deadline := time.Now().Add(3 * time.Second)
for time.Now().Before(deadline) {
if router.addCalls >= 1 {
break
}
time.Sleep(10 * time.Millisecond)
}
if router.addCalls == 0 {
t.Fatalf("expected subscriber.OnNamespaceAdd to be called after namespace creation, got 0 calls")
}
if router.addCalls != 1 {
t.Fatalf("expected exactly 1 add call (namespace is new), got %d", router.addCalls)
}
// Namespace должен быть в manager snapshot.
snapshot := manager.Snapshot()
found := false
for _, name := range snapshot {
if name == ns.Name {
found = true
break
}
}
if !found {
t.Fatalf("expected %s in manager snapshot after informer event, got %v", ns.Name, snapshot)
}
record, ok := manager.Get(ns.Name)
if !ok {
t.Fatalf("expected record for %s in manager", ns.Name)
}
if record.Phase != NamespacePhaseActive {
t.Fatalf("expected active phase after informer add, got %s", record.Phase)
}
}
func TestNamespaceSubscriberFuncs(t *testing.T) {
addCalls := 0
removeCalls := 0