| 1 | //go:build linux |
| 2 | package operator |
| 3 | |
| 4 | import ( |
| 5 | "context" |
| 6 | "crypto/sha256" |
| 7 | "database/sql" |
| 8 | "encoding/hex" |
| 9 | "encoding/json" |
| 10 | "os" |
| 11 | "os/exec" |
| 12 | "path/filepath" |
| 13 | "testing" |
| 14 | "time" |
| 15 | "golang.org/x/sys/unix" |
| 16 | ) |
| 17 | |
| 18 | func TestCheckerReadOnlyObservation(t *testing.T) { |
| 19 | path := os.Getenv("OFICINA_CHECKER_PROBE_PATH") |
| 20 | mode := os.Getenv("OFICINA_CHECKER_PROBE_MODE") |
| 21 | if mode == "seed-hot" { |
| 22 | db, err := sql.Open("sqlite", "file:"+path); if err != nil { t.Fatal(err) } |
| 23 | 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) } |
| 24 | os.Exit(0) |
| 25 | } |
| 26 | if mode == "read" { |
| 27 | var st unix.Stat_t |
| 28 | if err := unix.Stat(path,&st); err != nil { t.Fatal(err) } |
| 29 | b,err:=newBoundDatabase(path,uint64(st.Dev),st.Ino,time.Now().Add(time.Minute)); if err != nil { t.Fatal(err) } |
| 30 | ctx:=context.Background() |
| 31 | if _,err=b.db.ExecContext(ctx,"PRAGMA query_only=ON");err!=nil {t.Fatal(err)} |
| 32 | var count int |
| 33 | if err=b.db.QueryRowContext(ctx,"SELECT count(*) FROM changes").Scan(&count);err!=nil {t.Fatal(err)} |
| 34 | if count!=1 {t.Fatal("wrong count",count)} |
| 35 | if err=b.close();err!=nil {t.Fatal(err)} |
| 36 | return |
| 37 | } |
| 38 | snapshot:=func(path string) map[string]string { |
| 39 | out:=map[string]string{} |
| 40 | for _,suffix:=range []string{"","-wal","-shm"} { |
| 41 | raw,err:=os.ReadFile(path+suffix) |
| 42 | if os.IsNotExist(err) {out[suffix]="absent";continue}; if err!=nil {t.Fatal(err)} |
| 43 | sum:=sha256.Sum256(raw);out[suffix]=hex.EncodeToString(sum[:]) |
| 44 | };return out |
| 45 | } |
| 46 | path=filepath.Join(t.TempDir(),"home.db") |
| 47 | for _,childMode:=range []string{"seed-hot","read"} { |
| 48 | if childMode=="read" {raw,_:=json.Marshal(snapshot(path));t.Log("before",string(raw))} |
| 49 | cmd:=exec.Command(os.Args[0],"-test.run=^TestCheckerReadOnlyObservation$","-test.v") |
| 50 | cmd.Env=append(os.Environ(),"OFICINA_CHECKER_PROBE_MODE="+childMode,"OFICINA_CHECKER_PROBE_PATH="+path) |
| 51 | if raw,err:=cmd.CombinedOutput();err!=nil {t.Fatalf("%s: %v: %s",childMode,err,raw)} |
| 52 | } |
| 53 | raw,_:=json.Marshal(snapshot(path));t.Log("after",string(raw)) |
| 54 | } |
| 55 | |