package opencode import ( "path/filepath" "testing" "time" ) func TestPool_EnsureRoot_NoSpawn(t *testing.T) { // без spawn: пул без Bin — EnsureRoot должен упасть (нет бинаря), // но НЕ упасть на пустой карте. Проверяем, что повтор вызова не паникует. dir := t.TempDir() p := NewPool(dir) // не запускаем — просто проверяем кэш p.mu.Lock() p.segs[dir] = &Server{URL: "http://127.0.0.1:1", PollInterval: time.Millisecond} p.mu.Unlock() s, ok := p.ServerFor(dir) if !ok || s == nil { t.Fatal("ServerFor должен найти закэшированный сервер") } } func TestPool_ServerFor_ReleaseTask(t *testing.T) { dir := t.TempDir() a := filepath.Join(dir, "a") b := filepath.Join(dir, "b") p := NewPool(dir) p.Bin = fakeServeBin(t, dir) // root не запускаем; добавляем серверы в карту напрямую (как после Ensure). p.mu.Lock() p.segs[a] = &Server{URL: "http://127.0.0.1:1", PollInterval: time.Nanosecond} p.segs[b] = &Server{URL: "http://127.0.0.1:1", PollInterval: time.Nanosecond} p.mu.Unlock() // ReleaseTask: rootDir в карте НЕ занят, значит оба закрываются. p.ReleaseTask() if _, ok := p.ServerFor(a); ok { t.Error("каталог a должен быть снят после ReleaseTask") } if _, ok := p.ServerFor(b); ok { t.Error("каталог b должен быть снят после ReleaseTask") } } func TestPool_AllocPort_Unique(t *testing.T) { p := NewPool("/tmp/x") p.Host = "127.0.0.1" seen := map[int]bool{} var ports []int for i := 0; i < 5; i++ { port, err := p.allocPort() if err != nil { t.Fatalf("allocPort err: %v", err) } if seen[port] { t.Fatalf("дубль порта %d", port) } seen[port] = true ports = append(ports, port) } // освобождаем и убеждаемся, что порт можно переиспользовать p.releasePort(ports[0]) if !p.free(ports[0]) { t.Errorf("порт %d должен быть свободен после releasePort", ports[0]) } } func (p *Pool) free(port int) bool { p.mu.Lock() defer p.mu.Unlock() return !p.used[port] }