package utils import ( "reflect" "testing" "time" ) type testNamespaceSubscriber struct { name string } func (s testNamespaceSubscriber) Name() string { return s.name } func TestNamespaceManagerSnapshotAndGet(t *testing.T) { manager := NewNamespaceManager() now := time.Now().UTC() manager.Upsert(NamespaceEvent{Type: NamespaceEventAdd, Name: "tenant-b", Source: NamespaceSourceWatcher, ObservedAt: now}) manager.Upsert(NamespaceEvent{Type: NamespaceEventAdd, Name: "tenant-a", Source: NamespaceSourceWatcher, ObservedAt: now}) expected := []string{"tenant-a", "tenant-b"} if !reflect.DeepEqual(expected, manager.Snapshot()) { t.Fatalf("expected snapshot %v, got %v", expected, manager.Snapshot()) } record, ok := manager.Get("tenant-a") if !ok { t.Fatalf("expected tenant-a to exist") } if record.Name != "tenant-a" || record.Phase != NamespacePhaseDiscovered { t.Fatalf("unexpected record returned: %+v", record) } } func TestNamespaceManagerUpsertIncrementsGeneration(t *testing.T) { manager := NewNamespaceManager() now := time.Now().UTC() first := manager.Upsert(NamespaceEvent{Type: NamespaceEventAdd, Name: "tenant-a", Source: NamespaceSourceWatcher, ObservedAt: now}) second := manager.Upsert(NamespaceEvent{Type: NamespaceEventUpdate, Name: "tenant-a", Source: NamespaceSourceWatcher, ObservedAt: now.Add(time.Second)}) if first.Generation != 1 { t.Fatalf("expected first generation to be 1, got %d", first.Generation) } if second.Generation != 2 { t.Fatalf("expected second generation to be 2, got %d", second.Generation) } } func TestNamespaceManagerMarkPartState(t *testing.T) { manager := NewNamespaceManager() manager.Upsert(NamespaceEvent{Type: NamespaceEventAdd, Name: "tenant-a", Source: NamespaceSourceWatcher}) record, ok := manager.MarkPartState("tenant-a", "router", NamespacePartState{State: NamespacePartStateActive}) if !ok { t.Fatalf("expected mark part state to succeed") } if record.RegisteredParts["router"].State != NamespacePartStateActive { t.Fatalf("expected router part state to be stored") } if record.Phase != NamespacePhaseActive { t.Fatalf("expected phase to become active, got %s", record.Phase) } } func TestNamespaceManagerRemove(t *testing.T) { manager := NewNamespaceManager() manager.Upsert(NamespaceEvent{Type: NamespaceEventAdd, Name: "tenant-a", Source: NamespaceSourceWatcher}) if !manager.Remove("tenant-a") { t.Fatalf("expected remove to succeed") } if _, ok := manager.Get("tenant-a"); ok { t.Fatalf("expected record to be removed") } if manager.Remove("tenant-a") { t.Fatalf("expected second remove to report false") } } func TestNamespaceManagerSnapshotRecordsReturnsCopies(t *testing.T) { manager := NewNamespaceManager() manager.Upsert(NamespaceEvent{ Type: NamespaceEventAdd, Name: "tenant-a", Source: NamespaceSourceWatcher, Labels: map[string]string{"fission.io/managed": "true"}, }) _, _ = manager.MarkPartState("tenant-a", "router", NamespacePartState{State: NamespacePartStateActive}) records := manager.SnapshotRecords() records[0].Labels["fission.io/managed"] = "false" records[0].RegisteredParts["router"] = NamespacePartState{State: "failed"} record, ok := manager.Get("tenant-a") if !ok { t.Fatalf("expected tenant-a to exist") } if record.Labels["fission.io/managed"] != "true" { t.Fatalf("expected snapshot records to be detached copies") } if record.RegisteredParts["router"].State != NamespacePartStateActive { t.Fatalf("expected part states to be detached copies") } } func TestNamespaceManagerSubscribers(t *testing.T) { manager := NewNamespaceManager() manager.Subscribe(testNamespaceSubscriber{name: "router"}) manager.Subscribe(testNamespaceSubscriber{name: "buildermgr"}) manager.Subscribe(testNamespaceSubscriber{name: "router"}) expected := []string{"buildermgr", "router"} if !reflect.DeepEqual(expected, manager.SnapshotSubscribers()) { t.Fatalf("expected subscribers %v, got %v", expected, manager.SnapshotSubscribers()) } } func TestNamespaceManagerMarkPartStateDerivesPhase(t *testing.T) { manager := NewNamespaceManager() manager.Upsert(NamespaceEvent{Type: NamespaceEventAdd, Name: "tenant-a", Source: NamespaceSourceWatcher}) record, ok := manager.MarkPartState("tenant-a", "router", NamespacePartState{State: NamespacePartStateRegistering}) if !ok { t.Fatalf("expected registering state update to succeed") } if record.Phase != NamespacePhaseRegistering { t.Fatalf("expected phase registering, got %s", record.Phase) } record, ok = manager.MarkPartState("tenant-a", "router", NamespacePartState{State: NamespacePartStateFailed}) if !ok { t.Fatalf("expected failed state update to succeed") } if record.Phase != NamespacePhaseFailed { t.Fatalf("expected phase failed, got %s", record.Phase) } } func TestNamespaceManagerBootstrap(t *testing.T) { manager := NewNamespaceManager() now := time.Now().UTC() records := manager.Bootstrap([]string{"tenant-b", "tenant-a"}, NamespaceSourceBackfill, now) if len(records) != 2 { t.Fatalf("expected 2 bootstrap records, got %d", len(records)) } if !reflect.DeepEqual([]string{"tenant-a", "tenant-b"}, manager.Snapshot()) { t.Fatalf("expected manager snapshot to contain bootstrapped namespaces") } record, ok := manager.Get("tenant-a") if !ok { t.Fatalf("expected tenant-a after bootstrap") } if record.Source != NamespaceSourceBackfill { t.Fatalf("expected bootstrap source backfill, got %s", record.Source) } }