package services import ( "strings" "testing" "lokistack/models" ) // 删除并发必须按对象存储类型区分:各云 DELETE 限流差别很大, // 统一一个值要么被限流(COS 503 SlowDown),要么白等(S3 能扛更多)。 func TestCompactorDeleteWorkersPerStorageType(t *testing.T) { cases := map[string]int{ "cos": 16, // 实测 150 触发 503 SlowDown "obs": 32, // 华为 OBS 保守值 "minio": 32, // 自建,取决于磁盘 "azure": 32, // 存储账户限流较严 "oss": 64, // 阿里云 OSS QPS 较高 "gcs": 64, "s3": 96, // AWS S3 限流宽松 "": defaultCompactorDeleteWorkers, "unknown": defaultCompactorDeleteWorkers, } for storageType, want := range cases { got := compactorDeleteWorkers(&models.StorageConfig{StorageType: storageType}) if got != want { t.Errorf("storageType=%q: got %d, want %d", storageType, got, want) } } // nil 存储配置不能 panic if got := compactorDeleteWorkers(nil); got != defaultCompactorDeleteWorkers { t.Errorf("nil: got %d, want %d", got, defaultCompactorDeleteWorkers) } } // 运维应能用环境变量覆盖,不必改代码发版 func TestCompactorDeleteWorkersEnvOverride(t *testing.T) { t.Setenv("LOKI_COMPACTOR_DELETE_WORKERS", "48") if got := compactorDeleteWorkers(&models.StorageConfig{StorageType: "cos"}); got != 48 { t.Errorf("env override: got %d, want 48", got) } // 非法值回落到 provider 默认,不能让 Loki 起不来 t.Setenv("LOKI_COMPACTOR_DELETE_WORKERS", "abc") if got := compactorDeleteWorkers(&models.StorageConfig{StorageType: "cos"}); got != 16 { t.Errorf("invalid env: got %d, want 16", got) } } // 生成的配置里必须出现对应 provider 的并发值(防止模板变量漏渲染) func TestGeneratedConfigCarriesProviderDeleteWorkers(t *testing.T) { for storageType, want := range map[string]string{ "cos": "retention_delete_worker_count: 16", "s3": "retention_delete_worker_count: 96", } { d := NewLokiDeployer(&models.LokiDeployment{ RetentionDays: 7, Replicas: 1, StorageConfig: &models.StorageConfig{ StorageType: storageType, Bucket: "b", Region: "r", Endpoint: "e", AccessKey: "ak", SecretKey: "sk", }, }, func(level, message, detail string) {}) cfg := d.generateLokiConfig() if !strings.Contains(cfg, want) { t.Errorf("storageType=%s: generated config missing %q", storageType, want) } if !strings.Contains(cfg, "retention_delete_delay: 10m") { t.Errorf("storageType=%s: missing retention_delete_delay", storageType) } } }