github.com/quay/claircore@v1.5.28/test/integration/engine.go (about) 1 package integration 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "os/exec" 8 "path/filepath" 9 "strconv" 10 "strings" 11 "testing" 12 ) 13 14 // Engine is a helper for managing a postgres engine. 15 type Engine struct { 16 DSN string 17 binroot string 18 port string 19 dataDir string 20 } 21 22 func (e *Engine) init(t testing.TB) { 23 embedDB.FetchArchive(t) 24 d := embedDB.Realpath(t) 25 if _, err := os.Stat(d); err != nil { 26 t.Error(err) 27 } 28 e.binroot = filepath.Join(d, "bin") 29 t.Logf("using binaries at %q", e.binroot) 30 31 e.port = strconv.Itoa((os.Getpid() % 10000) + 30000) 32 var dsn strings.Builder 33 dsn.WriteString("host=localhost user=postgres password=securepassword sslmode=disable port=") 34 dsn.WriteString(e.port) 35 e.DSN = dsn.String() 36 t.Logf("using port %q", e.port) 37 38 e.dataDir = filepath.Join(PackageCacheDir(t), "pg"+embedDB.RealVersion) 39 if _, err := os.Stat(e.dataDir); err == nil { 40 t.Log("data directory exists, skipping initdb") 41 // Should be set up already. 42 return 43 } 44 t.Logf("using data directory %q", e.dataDir) 45 pwfile := filepath.Join(t.TempDir(), "passwd") 46 if err := os.WriteFile(pwfile, []byte(`securepassword`), 0o644); err != nil { 47 t.Fatal(err) 48 } 49 if err := os.MkdirAll(filepath.Dir(e.dataDir), 0o755); err != nil { 50 t.Fatal(err) 51 } 52 log, err := os.Create(e.dataDir + ".initdb") 53 if err != nil { 54 t.Fatal(err) 55 } 56 defer log.Close() 57 t.Logf("log at %q", log.Name()) 58 59 cmd := exec.Command(filepath.Join(e.binroot, "initdb"), 60 "--encoding=UTF8", 61 "--auth=password", 62 "--username=postgres", 63 "--pgdata="+e.dataDir, 64 "--pwfile="+pwfile, 65 ) 66 cmd.Stdout = log 67 cmd.Stderr = log 68 t.Logf("running %v", cmd.Args) 69 if err := cmd.Run(); err != nil { 70 t.Fatal(err) 71 } 72 } 73 74 // Start configures and starts the database engine. 75 // 76 // This should not be called multiple times. 77 func (e *Engine) Start(t testing.TB) error { 78 e.init(t) 79 logfile := filepath.Join(e.dataDir, "log") 80 if err := os.Truncate(logfile, 0); err != nil && !errors.Is(err, os.ErrNotExist) { 81 return err 82 } 83 opts := []string{ 84 "-w", 85 "-s", 86 "-D", e.dataDir, 87 "-l", logfile, 88 "-o", fmt.Sprintf("-F -p %s", e.port), 89 } 90 if testing.Verbose() { 91 t.Logf("enabling EXPLAIN output to: %s", logfile) 92 opts = append(opts, 93 "-o", "-c session_preload_libraries=auto_explain", 94 "-o", "-c auto_explain.log_min_duration=0", 95 "-o", "-c auto_explain.log_analyze=true", 96 "-o", "-c auto_explain.log_buffers=true", 97 "-o", "-c auto_explain.log_wal=true", 98 "-o", "-c auto_explain.log_verbose=true", 99 "-o", "-c auto_explain.log_nested_statements=true", 100 ) 101 if f := os.Getenv("PGEXPLAIN_FORMAT"); f != "" { 102 opts = append(opts, "-o", fmt.Sprintf("-c auto_explain.log_format=%s", f)) 103 } 104 } 105 opts = append(opts, "start") 106 cmd := exec.Command(filepath.Join(e.binroot, "pg_ctl"), opts...) 107 t.Logf("starting database engine: %v", cmd.Args) 108 return cmd.Run() 109 } 110 111 // Stop stops the database engine. 112 // 113 // It's an error to call Stop before a successful Start. 114 func (e *Engine) Stop() error { 115 cmd := exec.Command(filepath.Join(e.binroot, "pg_ctl"), 116 "-w", 117 "-s", 118 "-D", e.dataDir, 119 "-m", "fast", 120 "stop", 121 ) 122 return cmd.Run() 123 }