diff --git a/sonic_data_client/client_test.go b/sonic_data_client/client_test.go index e22bb1de0..df13d4155 100644 --- a/sonic_data_client/client_test.go +++ b/sonic_data_client/client_test.go @@ -872,6 +872,53 @@ func TestInitRedisDbClients(t *testing.T) { } }) + t.Run("SkipUnconfiguredDbWithoutGetDbSock", func(t *testing.T) { + defer saveAndResetTarget2RedisDb()() + + const skippedDb = "CHASSIS_STATE_DB" + configuredDbs := []string{"CONFIG_DB", "APPL_DB", "STATE_DB"} + getDbSockCalls := 0 + getDbSockCalledForSkipped := false + + patches := gomonkey.ApplyFunc(sdcfg.GetDbAllNamespaces, func() ([]string, error) { + return []string{ns}, nil + }) + defer patches.Reset() + + patches.ApplyFunc(sdcfg.GetDbList, func(_ string) ([]string, error) { + return configuredDbs, nil + }) + + patches.ApplyFunc(sdcfg.GetDbSock, func(dbName string, _ string) (string, error) { + getDbSockCalls++ + if dbName == skippedDb { + getDbSockCalledForSkipped = true + } + return "/var/run/redis/redis.sock", nil + }) + + initRedisDbClients() + + nsMap, ok := Target2RedisDb[ns] + if !ok { + t.Fatal("Expected namespace to exist in Target2RedisDb") + } + if _, exists := nsMap[skippedDb]; exists { + t.Errorf("%s should have been skipped because it is not configured", skippedDb) + } + if getDbSockCalledForSkipped { + t.Errorf("GetDbSock should not be called for unconfigured DB %s", skippedDb) + } + if getDbSockCalls != len(configuredDbs) { + t.Errorf("Expected GetDbSock to be called %d times, got %d", len(configuredDbs), getDbSockCalls) + } + for _, dbName := range configuredDbs { + if _, exists := nsMap[dbName]; !exists { + t.Errorf("Expected %s to be initialized", dbName) + } + } + }) + t.Run("AllDbsAvailable", func(t *testing.T) { defer saveAndResetTarget2RedisDb()() @@ -1008,6 +1055,59 @@ func TestUseRedisTcpClient(t *testing.T) { } }) + t.Run("SkipUnconfiguredDbWithoutGetDbTcpAddr", func(t *testing.T) { + defer saveAndResetTarget2RedisDb()() + origFlag := UseRedisLocalTcpPort + UseRedisLocalTcpPort = true + defer func() { UseRedisLocalTcpPort = origFlag }() + + const skippedDb = "CHASSIS_STATE_DB" + configuredDbs := []string{"CONFIG_DB", "APPL_DB", "STATE_DB"} + getDbTcpAddrCalls := 0 + getDbTcpAddrCalledForSkipped := false + + patches := gomonkey.ApplyFunc(sdcfg.GetDbAllNamespaces, func() ([]string, error) { + return []string{ns}, nil + }) + defer patches.Reset() + + patches.ApplyFunc(sdcfg.GetDbList, func(_ string) ([]string, error) { + return configuredDbs, nil + }) + + patches.ApplyFunc(sdcfg.GetDbTcpAddr, func(dbName string, _ string) (string, error) { + getDbTcpAddrCalls++ + if dbName == skippedDb { + getDbTcpAddrCalledForSkipped = true + } + return "127.0.0.1:6379", nil + }) + + err := useRedisTcpClient() + if err != nil { + t.Fatalf("Expected no error when skipping unconfigured DB, got: %v", err) + } + + nsMap, ok := Target2RedisDb[ns] + if !ok { + t.Fatal("Expected namespace to exist in Target2RedisDb") + } + if _, exists := nsMap[skippedDb]; exists { + t.Errorf("%s should have been skipped because it is not configured", skippedDb) + } + if getDbTcpAddrCalledForSkipped { + t.Errorf("GetDbTcpAddr should not be called for unconfigured DB %s", skippedDb) + } + if getDbTcpAddrCalls != len(configuredDbs) { + t.Errorf("Expected GetDbTcpAddr to be called %d times, got %d", len(configuredDbs), getDbTcpAddrCalls) + } + for _, dbName := range configuredDbs { + if _, exists := nsMap[dbName]; !exists { + t.Errorf("Expected %s to be initialized in TCP mode", dbName) + } + } + }) + t.Run("GetDbAllNamespacesFails", func(t *testing.T) { defer saveAndResetTarget2RedisDb()() origFlag := UseRedisLocalTcpPort @@ -1029,6 +1129,19 @@ func TestUseRedisTcpClient(t *testing.T) { }) } +func TestConfiguredDbSet(t *testing.T) { + t.Run("GetDbListFailureReturnsNil", func(t *testing.T) { + patches := gomonkey.ApplyFunc(sdcfg.GetDbList, func(_ string) ([]string, error) { + return nil, fmt.Errorf("GetDbList failure") + }) + defer patches.Reset() + + if got := configuredDbSet("asic0"); got != nil { + t.Fatalf("expected nil set on GetDbList failure, got: %#v", got) + } + }) +} + // setupTestTarget2RedisDb populates Target2RedisDb with real TCP Redis clients // using the same gomonkey pattern as TestUseRedisTcpClient. func setupTestTarget2RedisDb(t *testing.T) func() { diff --git a/sonic_data_client/db_client.go b/sonic_data_client/db_client.go index 5c7a528b7..bf5d83d3b 100644 --- a/sonic_data_client/db_client.go +++ b/sonic_data_client/db_client.go @@ -546,8 +546,15 @@ func useRedisTcpClient() error { } for _, dbNamespace := range AllNamespaces { Target2RedisDb[dbNamespace] = make(map[string]*redis.Client) + configured := configuredDbSet(dbNamespace) for dbName, dbn := range spb.Target_value { if dbName != "OTHERS" { + if configured != nil { + if _, ok := configured[dbName]; !ok { + log.V(2).Infof("Skipping %s in namespace %s: not configured on this platform", dbName, dbNamespace) + continue + } + } addr, err := sdcfg.GetDbTcpAddr(dbName, dbNamespace) if err != nil { log.Warningf("Skipping %s in namespace %s: %v", dbName, dbNamespace, err) @@ -573,6 +580,24 @@ func init() { initRedisDbClients() } +// configuredDbSet returns the set of DB names defined in the device's +// SONiC database_config.json for the given namespace. +func configuredDbSet(dbNamespace string) map[string]struct{} { + dbList, err := sdcfg.GetDbList(dbNamespace) + if err != nil { + log.V(2).Infof("GetDbList failed for namespace %s: %v", dbNamespace, err) + return nil + } + if len(dbList) == 0 { + return nil + } + set := make(map[string]struct{}, len(dbList)) + for _, name := range dbList { + set[name] = struct{}{} + } + return set +} + func initRedisDbClients() { AllNamespaces, err := sdcfg.GetDbAllNamespaces() if err != nil { @@ -581,8 +606,15 @@ func initRedisDbClients() { } for _, dbNamespace := range AllNamespaces { Target2RedisDb[dbNamespace] = make(map[string]*redis.Client) + configured := configuredDbSet(dbNamespace) for dbName, dbn := range spb.Target_value { if dbName != "OTHERS" { + if configured != nil { + if _, ok := configured[dbName]; !ok { + log.V(2).Infof("Skipping %s in namespace %s: not configured on this platform", dbName, dbNamespace) + continue + } + } addr, err := sdcfg.GetDbSock(dbName, dbNamespace) if err != nil { log.Warningf("Skipping %s in namespace %s: %v", dbName, dbNamespace, err)