internal/home/kv_helpers_test.go
Rama main · réplica de lectura del repositorio original.
package home
import (
"bytes"
"context"
"path/filepath"
"strings"
"testing"
"github.com/router-for-me/CLIProxyAPI/v8/internal/config"
"github.com/router-for-me/CLIProxyAPI/v8/internal/kvstore"
log "github.com/sirupsen/logrus"
)
func TestHashKeyPart(t *testing.T) {
first := HashKeyPart("secret-value")
again := HashKeyPart("secret-value")
other := HashKeyPart("other-value")
if first == "" || len(first) != 64 {
t.Fatalf("HashKeyPart() = %q, want 64 hex chars", first)
}
if first != again {
t.Fatalf("HashKeyPart() is not stable")
}
if first == other {
t.Fatalf("HashKeyPart() returned same hash for different inputs")
}
if strings.Contains(first, "secret") || strings.Contains(first, "value") {
t.Fatalf("HashKeyPart() leaked input: %q", first)
}
}
func TestKVRequiredHelpersReturnNonHomeMode(t *testing.T) {
ClearCurrent()
t.Cleanup(ClearCurrent)
var out map[string]string
homeMode, found, errGet := KVGetJSONRequired(context.Background(), "key", &out)
if errGet != nil {
t.Fatalf("KVGetJSONRequired() error = %v", errGet)
}
if homeMode || found {
t.Fatalf("KVGetJSONRequired() = homeMode %v found %v, want false false", homeMode, found)
}
}
func TestCurrentKVClientUnavailableErrors(t *testing.T) {
t.Cleanup(ClearCurrent)
disabled := New(config.HomeConfig{Enabled: false})
SetCurrent(disabled)
if _, homeMode, errClient := CurrentKVClient(); !homeMode || errClient == nil {
t.Fatalf("CurrentKVClient(disabled) = homeMode %v err %v, want true error", homeMode, errClient)
}
notReady := New(config.HomeConfig{Enabled: true, Host: "127.0.0.1", Port: 1})
SetCurrent(notReady)
if _, homeMode, errClient := CurrentKVClient(); !homeMode || errClient == nil {
t.Fatalf("CurrentKVClient(no heartbeat) = homeMode %v err %v, want true error", homeMode, errClient)
}
}
func TestKVRequiredHelpersPropagateClientErrors(t *testing.T) {
client, _ := newRedisCommandTestClient(t, func(args []string) string {
return "-ERR home kv unavailable\r\n"
})
client.heartbeatOK.Store(true)
SetCurrent(client)
t.Cleanup(ClearCurrent)
var out map[string]string
homeMode, _, errGet := KVGetJSONRequired(context.Background(), "cpa:test:key", &out)
if !homeMode || errGet == nil {
t.Fatalf("KVGetJSONRequired() = homeMode %v err %v, want true error", homeMode, errGet)
}
homeMode, errSet := KVSetJSONRequired(context.Background(), "cpa:test:key", map[string]string{"value": "secret"}, 0)
if !homeMode || errSet == nil {
t.Fatalf("KVSetJSONRequired() = homeMode %v err %v, want true error", homeMode, errSet)
}
}
func TestKVBestEffortWriteSwallowsErrorAndRedactsLog(t *testing.T) {
client, _ := newRedisCommandTestClient(t, func(args []string) string {
return "-ERR home kv unavailable\r\n"
})
client.heartbeatOK.Store(true)
SetCurrent(client)
t.Cleanup(ClearCurrent)
logger := log.StandardLogger()
previousOutput := logger.Out
previousLevel := log.GetLevel()
buffer := &bytes.Buffer{}
log.SetOutput(buffer)
log.SetLevel(log.ErrorLevel)
t.Cleanup(func() {
log.SetOutput(previousOutput)
log.SetLevel(previousLevel)
})
ok := KVSetJSONBestEffort(context.Background(), "cpa:test:secret-key", map[string]string{"value": "secret-value"}, 0)
if ok {
t.Fatalf("KVSetJSONBestEffort() = true, want false")
}
logText := buffer.String()
if !strings.Contains(logText, "cpa:test:*") {
t.Fatalf("log = %q, want redacted key prefix", logText)
}
if strings.Contains(logText, "secret-key") || strings.Contains(logText, "secret-value") {
t.Fatalf("log leaked key or value: %q", logText)
}
}
func TestCurrentKVClientBridgesLocalBoltStoreAndPrioritizesHome(t *testing.T) {
ClearCurrent()
_ = kvstore.ShutdownLocal()
t.Cleanup(func() {
ClearCurrent()
_ = kvstore.ShutdownLocal()
})
dbPath := filepath.Join(t.TempDir(), "bridge.db")
if errCfg := kvstore.ConfigureLocal(true, dbPath); errCfg != nil {
t.Fatalf("kvstore.ConfigureLocal(true, %q) error = %v", dbPath, errCfg)
}
client, kvMode, errClient := CurrentKVClient()
if errClient != nil || !kvMode || client == nil {
t.Fatalf("CurrentKVClient() with local enabled = (%v, %v, %v), want (*BoltStore, true, nil)", client, kvMode, errClient)
}
if _, ok := client.(*kvstore.BoltStore); !ok {
t.Fatalf("CurrentKVClient() type = %T, want *kvstore.BoltStore", client)
}
// When Home is active, CurrentKVClient must return the Home client even while local bbolt is enabled.
homeClient, _ := newRedisCommandTestClient(t, func(args []string) string {
return "+OK\r\n"
})
homeClient.heartbeatOK.Store(true)
SetCurrent(homeClient)
activeClient, activeMode, errActive := CurrentKVClient()
if errActive != nil || !activeMode || activeClient != homeClient {
t.Fatalf("CurrentKVClient() with active Home = (%v, %v, %v), want (%v, true, nil)", activeClient, activeMode, errActive, homeClient)
}
}