package proc import ( "strings" "sync" "testing" "time" ) // 锁仲裁回归内核(§3.7 已裁定)的行为验证,含实验 9 的崩溃自愈机制。 func TestStageLock_MutualExclusion(t *testing.T) { l := newStageLock() if err := l.Acquire("A"); err != nil { t.Fatalf("A 应能获得锁: %v", err) } if l.Owner() != "A" { t.Errorf("Owner 应为 A,实际 %q", l.Owner()) } // B 在 A 持锁期间不得进入 entered := make(chan struct{}) go func() { _ = l.Acquire("B") close(entered) }() select { case <-entered: t.Fatal("A 持锁期间 B 不应获得锁") case <-time.After(50 * time.Millisecond): } if err := l.Release("A"); err != nil { t.Fatalf("A 释放失败: %v", err) } select { case <-entered: case <-time.After(2 * time.Second): t.Fatal("A 释放后 B 应获得锁") } if l.Owner() != "B" { t.Errorf("Owner 应为 B,实际 %q", l.Owner()) } _ = l.Release("B") } // 非持锁者不得释放他人的锁(防止串扰导致并发正确性被破坏)。 func TestStageLock_ReleaseByNonOwnerRejected(t *testing.T) { l := newStageLock() if err := l.Acquire("A"); err != nil { t.Fatalf("Acquire: %v", err) } defer l.Release("A") err := l.Release("B") if err == nil { t.Fatal("非持锁者释放应被拒绝") } if !strings.Contains(err.Error(), "试图释放") { t.Errorf("错误信息应说明串扰,实际: %v", err) } if l.Owner() != "A" { t.Errorf("A 应仍持锁,实际 owner=%q", l.Owner()) } } func TestStageLock_ReleaseWithoutHoldRejected(t *testing.T) { l := newStageLock() if err := l.Release("A"); err == nil { t.Fatal("未持锁时释放应报错") } } // handler 内嵌套加锁会死锁,应显式拒绝而不是让插件挂死到超时。 func TestStageLock_ReentrantAcquireRejected(t *testing.T) { l := newStageLock() if err := l.Acquire("A"); err != nil { t.Fatalf("Acquire: %v", err) } defer l.Release("A") err := l.Acquire("A") if err == nil { t.Fatal("同一插件重复加锁应被拒绝(否则死锁 30s)") } if !strings.Contains(err.Error(), "重复申请") { t.Errorf("错误信息应说明重复加锁,实际: %v", err) } } // 实验 9 的核心:持锁进程崩溃后内核代为释放,后续插件不死锁。 // 这条彻底排除了 robust pthread_mutex 的必要性 —— 整个架构零 cgo。 func TestStageLock_ForceReleaseOnPluginCrash(t *testing.T) { l := newStageLock() // 插件 X 拿锁后"崩溃"(不调用 Release) if err := l.Acquire("X"); err != nil { t.Fatalf("X Acquire: %v", err) } if !l.ForceRelease("X") { t.Fatal("内核应能强制释放崩溃插件持有的锁") } if l.Owner() != "" { t.Errorf("强制释放后应无持有者,实际 %q", l.Owner()) } // 插件 Y 随后必须能正常拿到锁(无死锁) done := make(chan error, 1) go func() { done <- l.Acquire("Y") }() select { case err := <-done: if err != nil { t.Fatalf("Y 应能获得锁: %v", err) } case <-time.After(2 * time.Second): t.Fatal("X 崩溃后 Y 无法获得锁 —— 出现死锁") } if err := l.Release("Y"); err != nil { t.Fatalf("Y 释放失败: %v", err) } } // ForceRelease 对非持有者/未持锁应为 no-op,不能误放他人的锁。 func TestStageLock_ForceReleaseIsTargeted(t *testing.T) { l := newStageLock() if err := l.Acquire("A"); err != nil { t.Fatalf("Acquire: %v", err) } defer l.Release("A") if l.ForceRelease("B") { t.Error("强制释放不该动 A 持有的锁") } if l.Owner() != "A" { t.Errorf("A 应仍持锁,实际 %q", l.Owner()) } } // 高并发下锁的串行化保证:临界区不重叠。 func TestStageLock_SerializesCriticalSection(t *testing.T) { l := newStageLock() var ( mu sync.Mutex inside int maxSeen int ) const workers = 8 const iters = 50 var wg sync.WaitGroup for i := 0; i < workers; i++ { wg.Add(1) go func(id int) { defer wg.Done() name := string(rune('A' + id)) for j := 0; j < iters; j++ { if err := l.Acquire(name); err != nil { t.Errorf("Acquire: %v", err) return } mu.Lock() inside++ if inside > maxSeen { maxSeen = inside } mu.Unlock() mu.Lock() inside-- mu.Unlock() if err := l.Release(name); err != nil { t.Errorf("Release: %v", err) return } } }(i) } wg.Wait() if maxSeen > 1 { t.Fatalf("临界区出现并发:同时 %d 个持有者", maxSeen) } }