mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-07-31 20:36:47 +00:00
Durability mode implementation (sync_all, sync_quorum, best_effort): - DurabilityMode type with superblock persistence, parse/validate/string - MakeDistributedSync mode-aware barrier enforcement in dist_group_commit - blockerr sentinel package (ErrDurabilityBarrierFailed, ErrDurabilityQuorumLost) - gRPC create path: mode validation, idempotent create consistency, partial cleanup - F1: strict mode rejects partial replica provisioning with cleanup - F3: empty heartbeat does not overwrite persisted strict mode - F4: SCSI error mapping uses errors.Is sentinels (not string matching) - Proto/wire/blockapi/CLI/UI plumbing for durability_mode field - Observability dashboard: cluster health cards + per-volume columns Testrunner platform (YAML-driven integration test framework): - Engine, parser, registry, reporter (JUnit XML + HTML), metrics scraping - 52 registered actions: block, iSCSI, I/O, fault injection, assertions - Baseline regression framework with 7 hard-fail conditions - 15 YAML scenarios (smoke, crash, HA, fault, consistency, snapshot) - 49 unit tests for testrunner internals QA adversarial suite (21 tests, all PASS): - Idempotent create mode/RF mismatch detection - Heartbeat mode downgrade prevention (F3) - sync_all/sync_quorum partial replica enforcement (F1) - Concurrent create race safety - Failover/expand mode preservation - Cleanup resilience when delete fails - Master restart auto-register mode handling - Superblock roundtrip all 3 modes - Validate edge cases (mode×RF matrix) - RequiredReplicas quorum math verification - Sentinel error categorization Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
37 lines
807 B
Go
37 lines
807 B
Go
package testrunner
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
func TestIsPathSafe(t *testing.T) {
|
|
tests := []struct {
|
|
path string
|
|
want bool
|
|
}{
|
|
{"/tmp/sw-test-runner/binary", true},
|
|
{"/tmp/sw-test-runner/subdir/file", true},
|
|
{"/tmp/sw-test-runner/nested/deep/file", true},
|
|
{"/tmp/other/file", false},
|
|
{"/etc/passwd", false},
|
|
{"/tmp/sw-test-runner/../etc/passwd", false},
|
|
{"../etc/passwd", false},
|
|
{"/tmp/sw-test-runner/../../root", false},
|
|
{"", false},
|
|
{"/tmp/sw-test-runner-evil/file", false},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
got := isPathSafe(tt.path)
|
|
if got != tt.want {
|
|
t.Errorf("isPathSafe(%q) = %v, want %v", tt.path, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAuthTokenHeaderConstant(t *testing.T) {
|
|
if AuthTokenHeader != "X-Auth-Token" {
|
|
t.Errorf("AuthTokenHeader = %q", AuthTokenHeader)
|
|
}
|
|
}
|