//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))
}
