62 lines
1.7 KiB
Go
62 lines
1.7 KiB
Go
package pi
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
func TestAdvisoryLockRejectsAConcurrentOwner(t *testing.T) {
|
|
statePath := filepath.Join(t.TempDir(), "update-state.json")
|
|
first, err := acquireLock(statePath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer first.Release()
|
|
second, err := acquireLock(statePath)
|
|
if second != nil {
|
|
second.Release()
|
|
}
|
|
if !errors.Is(err, ErrLockHeld) {
|
|
t.Fatalf("second acquireLock() error = %v, want ErrLockHeld", err)
|
|
}
|
|
}
|
|
|
|
func TestAdvisoryLockCrashReleasesAndReacquires(t *testing.T) {
|
|
statePath := filepath.Join(t.TempDir(), "update-state.json")
|
|
if os.Getenv("THOTHCTL_LOCK_CRASH_HELPER") == "1" {
|
|
lock, err := acquireLock(os.Getenv("THOTHCTL_LOCK_STATE"))
|
|
if err != nil || lock == nil {
|
|
os.Exit(23)
|
|
}
|
|
os.Exit(0) // Deliberately bypass Release: the OS must release ownership.
|
|
}
|
|
command := exec.Command(os.Args[0], "-test.run=^TestAdvisoryLockCrashReleasesAndReacquires$")
|
|
command.Env = append(os.Environ(), "THOTHCTL_LOCK_CRASH_HELPER=1", "THOTHCTL_LOCK_STATE="+statePath)
|
|
if output, err := command.CombinedOutput(); err != nil {
|
|
t.Fatalf("crash helper failed: %v: %s", err, output)
|
|
}
|
|
lock, err := acquireLock(statePath)
|
|
if err != nil {
|
|
t.Fatalf("acquireLock() after owner crash = %v", err)
|
|
}
|
|
lock.Release()
|
|
}
|
|
|
|
func TestAdvisoryLockIgnoresPartialDiagnosticMetadata(t *testing.T) {
|
|
statePath := filepath.Join(t.TempDir(), "update-state.json")
|
|
if err := os.WriteFile(statePath+".lock", nil, 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(statePath+".lock.owner.json", []byte("{partial"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
lock, err := acquireLock(statePath)
|
|
if err != nil {
|
|
t.Fatalf("acquireLock() with partial diagnostics = %v", err)
|
|
}
|
|
lock.Release()
|
|
}
|