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  }