//go:build linux package operator import ( "context" "crypto/sha256" "database/sql" "encoding/hex" "encoding/json" "os" "os/exec" "path/filepath" "testing" "time" "golang.org/x/sys/unix" ) func TestCheckerReadOnlyObservation(t *testing.T) { path := os.Getenv("OFICINA_CHECKER_PROBE_PATH") mode := os.Getenv("OFICINA_CHECKER_PROBE_MODE") if mode == "seed-hot" { db, err := sql.Open("sqlite", "file:"+path); if err != nil { t.Fatal(err) } if _,err = db.Exec("PRAGMA journal_mode=WAL; PRAGMA wal_autocheckpoint=0; CREATE TABLE changes(value INTEGER); INSERT INTO changes VALUES(42)"); err != nil { t.Fatal(err) } os.Exit(0) } if mode == "read" { var st unix.Stat_t if err := unix.Stat(path,&st); err != nil { t.Fatal(err) } b,err:=newBoundDatabase(path,uint64(st.Dev),st.Ino,time.Now().Add(time.Minute)); if err != nil { t.Fatal(err) } ctx:=context.Background() if _,err=b.db.ExecContext(ctx,"PRAGMA query_only=ON");err!=nil {t.Fatal(err)} var count int if err=b.db.QueryRowContext(ctx,"SELECT count(*) FROM changes").Scan(&count);err!=nil {t.Fatal(err)} if count!=1 {t.Fatal("wrong count",count)} if err=b.close();err!=nil {t.Fatal(err)} return } snapshot:=func(path string) map[string]string { out:=map[string]string{} for _,suffix:=range []string{"","-wal","-shm"} { raw,err:=os.ReadFile(path+suffix) if os.IsNotExist(err) {out[suffix]="absent";continue}; if err!=nil {t.Fatal(err)} sum:=sha256.Sum256(raw);out[suffix]=hex.EncodeToString(sum[:]) };return out } path=filepath.Join(t.TempDir(),"home.db") for _,childMode:=range []string{"seed-hot","read"} { if childMode=="read" {raw,_:=json.Marshal(snapshot(path));t.Log("before",string(raw))} cmd:=exec.Command(os.Args[0],"-test.run=^TestCheckerReadOnlyObservation$","-test.v") cmd.Env=append(os.Environ(),"OFICINA_CHECKER_PROBE_MODE="+childMode,"OFICINA_CHECKER_PROBE_PATH="+path) if raw,err:=cmd.CombinedOutput();err!=nil {t.Fatalf("%s: %v: %s",childMode,err,raw)} } raw,_:=json.Marshal(snapshot(path));t.Log("after",string(raw)) }