mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-07 14:57:48 +02:00
CP10-3 Tier 1 optimizations (T1-T4): - TCP_NODELAY + 256KB socket buffers on NVMe/TCP connections - Response batching: all C2H data chunks + CapsuleResp in single flush - Tiered buffer pool (4KB/64KB/256KB sync.Pool) for write payloads - Configurable MaxH2CDataLength wiring through controller/IC/chunking BUG-CP103-1: NVMe write retry with jittered backoff for transient WAL pressure - writeWithRetry() with bounded backoff [50/200/800ms] - throttleOnWALPressure() pre-write delay above 90% WAL usage - WALPressureProvider interface + NVMeAdapter.WALPressure() BUG-CP103-2: Volume-level WAL admission control - WALAdmission with counting semaphore (max concurrent writers) - Soft watermark (0.7): small delay to desynchronize herd - Hard watermark (0.9): block until flusher drains - Single-deadline budget shared across watermark wait + semaphore - Close-aware during both watermark and semaphore waits - Wired into BlockVol.WriteLBA() and Trim() Benchmark platform enhancements: - NVMe benchmark actions and scenarios (A/B, CW sweep, IOQ sweep) - Database benchmark actions (SQLite, pgbench) - K8s operator QA reconciler tests - New testrunner scenarios for HA, fault injection, CSI lifecycle Test counts: 213 NVMe + 625 engine + operator + testrunner tests, all passing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
160 lines
3.8 KiB
Go
160 lines
3.8 KiB
Go
package actions
|
|
|
|
import (
|
|
"sort"
|
|
"testing"
|
|
|
|
tr "github.com/seaweedfs/seaweedfs/weed/storage/blockvol/testrunner"
|
|
)
|
|
|
|
func TestDevOpsActions_Registration(t *testing.T) {
|
|
registry := tr.NewRegistry()
|
|
RegisterDevOpsActions(registry)
|
|
|
|
expected := []string{
|
|
"build_deploy_weed",
|
|
"start_weed_master",
|
|
"start_weed_volume",
|
|
"stop_weed",
|
|
"wait_cluster_ready",
|
|
"create_block_volume",
|
|
"cluster_status",
|
|
}
|
|
|
|
for _, name := range expected {
|
|
if _, err := registry.Get(name); err != nil {
|
|
t.Errorf("action %q not registered: %v", name, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDevOpsActions_Tier(t *testing.T) {
|
|
registry := tr.NewRegistry()
|
|
RegisterDevOpsActions(registry)
|
|
|
|
byTier := registry.ListByTier()
|
|
devopsActions := byTier[tr.TierDevOps]
|
|
|
|
if len(devopsActions) != 7 {
|
|
t.Errorf("devops tier has %d actions, want 7", len(devopsActions))
|
|
}
|
|
|
|
// Verify all are in devops tier.
|
|
sort.Strings(devopsActions)
|
|
for _, name := range devopsActions {
|
|
if tier := registry.ActionTier(name); tier != tr.TierDevOps {
|
|
t.Errorf("action %q has tier %q, want devops", name, tier)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDevOpsActions_TierGating(t *testing.T) {
|
|
registry := tr.NewRegistry()
|
|
RegisterDevOpsActions(registry)
|
|
|
|
// Without gating, all should be accessible.
|
|
if _, err := registry.Get("start_weed_master"); err != nil {
|
|
t.Errorf("ungated: %v", err)
|
|
}
|
|
|
|
// Enable only core tier — devops should be blocked.
|
|
registry.EnableTiers([]string{tr.TierCore})
|
|
if _, err := registry.Get("start_weed_master"); err == nil {
|
|
t.Error("expected error when devops tier is disabled")
|
|
}
|
|
|
|
// Enable devops tier — should work again.
|
|
registry.EnableTiers([]string{tr.TierDevOps})
|
|
if _, err := registry.Get("start_weed_master"); err != nil {
|
|
t.Errorf("devops enabled: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestAllActions_Registration(t *testing.T) {
|
|
registry := tr.NewRegistry()
|
|
RegisterAll(registry)
|
|
|
|
byTier := registry.ListByTier()
|
|
|
|
// Verify tier counts.
|
|
if n := len(byTier[tr.TierCore]); n != 11 {
|
|
t.Errorf("core: %d, want 11", n)
|
|
}
|
|
if n := len(byTier[tr.TierBlock]); n != 52 {
|
|
t.Errorf("block: %d, want 52", n)
|
|
}
|
|
if n := len(byTier[tr.TierDevOps]); n != 7 {
|
|
t.Errorf("devops: %d, want 7", n)
|
|
}
|
|
if n := len(byTier[tr.TierChaos]); n != 5 {
|
|
t.Errorf("chaos: %d, want 5", n)
|
|
}
|
|
if n := len(byTier[TierK8s]); n != 14 {
|
|
t.Errorf("k8s: %d, want 14", n)
|
|
}
|
|
|
|
// Total should be 89 (85 existing + 3 pgbench + 1 bench_stats).
|
|
total := 0
|
|
for _, actions := range byTier {
|
|
total += len(actions)
|
|
}
|
|
if total != 89 {
|
|
t.Errorf("total actions: %d, want 89", total)
|
|
}
|
|
}
|
|
|
|
func TestK8sActions_Registration(t *testing.T) {
|
|
registry := tr.NewRegistry()
|
|
RegisterK8sActions(registry)
|
|
|
|
expected := []string{
|
|
"kubectl_apply",
|
|
"kubectl_delete",
|
|
"kubectl_get_field",
|
|
"kubectl_wait_condition",
|
|
"kubectl_set_image",
|
|
"kubectl_assert_exists",
|
|
"kubectl_assert_not_exists",
|
|
"kubectl_logs",
|
|
"kubectl_rollout_status",
|
|
"kubectl_exec",
|
|
"kubectl_delete_pod",
|
|
"kubectl_pod_ready_count",
|
|
"kubectl_label",
|
|
"kubectl_get_condition",
|
|
}
|
|
|
|
for _, name := range expected {
|
|
if _, err := registry.Get(name); err != nil {
|
|
t.Errorf("action %q not registered: %v", name, err)
|
|
}
|
|
}
|
|
|
|
byTier := registry.ListByTier()
|
|
if n := len(byTier[TierK8s]); n != 14 {
|
|
t.Errorf("k8s tier has %d actions, want 14", n)
|
|
}
|
|
}
|
|
|
|
func TestK8sActions_TierGating(t *testing.T) {
|
|
registry := tr.NewRegistry()
|
|
RegisterK8sActions(registry)
|
|
|
|
// Without gating, all should be accessible.
|
|
if _, err := registry.Get("kubectl_apply"); err != nil {
|
|
t.Errorf("ungated: %v", err)
|
|
}
|
|
|
|
// Enable only core tier — k8s should be blocked.
|
|
registry.EnableTiers([]string{tr.TierCore})
|
|
if _, err := registry.Get("kubectl_apply"); err == nil {
|
|
t.Error("expected error when k8s tier is disabled")
|
|
}
|
|
|
|
// Enable k8s tier — should work again.
|
|
registry.EnableTiers([]string{TierK8s})
|
|
if _, err := registry.Get("kubectl_apply"); err != nil {
|
|
t.Errorf("k8s enabled: %v", err)
|
|
}
|
|
}
|