diff --git a/modules/clipmenu/cmd/clipmenu-tools/manifest_test.go b/modules/clipmenu/cmd/clipmenu-tools/manifest_test.go index 4e769c4c..fea70036 100644 --- a/modules/clipmenu/cmd/clipmenu-tools/manifest_test.go +++ b/modules/clipmenu/cmd/clipmenu-tools/manifest_test.go @@ -1,6 +1,7 @@ package main import ( + "bufio" "context" "net" "os" @@ -170,20 +171,33 @@ func TestTheLauncherWaitsQuietlyWhileAnotherClipmenudHoldsTheLock(t *testing.T) store := dir + "/cm/clipmenu.6.op" os.MkdirAll(store, 0o700) lock := store + "/session_lock" - // the older clipmenud: it holds the lock the way clipmenud does, until it is killed - holder := exec.Command("flock", "-x", "-n", lock, "sleep", "60") + // the older clipmenud: it holds the lock the way clipmenud does, until it is killed. It says "held" once it has the + // lock, so the test goes on only when the lock is held for certain: a holder that is slow to start (the checker + // runs thousands of tests at once) must not let the launcher find the lock free (issue 1814). + holder := exec.Command("flock", "-x", "-n", lock, "sh", "-c", "echo held; exec sleep 60") holder.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} + held, err := holder.StdoutPipe() + if err != nil { + t.Fatal(err) + } if err := holder.Start(); err != nil { t.Fatal(err) } // flock's child shares the lock, so the whole group goes release := func() { syscall.Kill(-holder.Process.Pid, syscall.SIGKILL); holder.Wait() } defer release() - for i := 0; i < 50; i++ { - if probe := exec.Command("flock", "-n", lock, "true"); probe.Run() != nil { - break + said := make(chan string, 1) + go func() { + line, _ := bufio.NewReader(held).ReadString('\n') + said <- strings.TrimSpace(line) + }() + select { + case line := <-said: + if line != "held" { + t.Fatalf("the older clipmenud did not take the lock: %q", line) } - time.Sleep(50 * time.Millisecond) + case <-time.After(30 * time.Second): + t.Fatal("the older clipmenud did not take the lock within 30 s") } var out syncBuffer cmd := exec.Command("sh", file)