From 5956e9916eb946a3e0d3e260184a4c78eaf8322f Mon Sep 17 00:00:00 2001 From: Talha Abbasi Date: Thu, 17 Oct 2024 17:28:12 +0500 Subject: [PATCH 1/6] feat: add support for FSync :muscle: --- config.go | 7 +++++++ pgtest.go | 6 +++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/config.go b/config.go index 66d7178..278217a 100644 --- a/config.go +++ b/config.go @@ -5,6 +5,7 @@ type PGConfig struct { Dir string // Directory for storing database files, removed for non-persistent configs IsPersistent bool // Whether to make the current configuraton persistent or not AdditionalArgs []string // Additional arguments to pass to the postgres command + FSync bool // To set -F flag } func New() *PGConfig { @@ -12,6 +13,7 @@ func New() *PGConfig { BinDir: "", Dir: "", IsPersistent: false, + FSync: false, } } @@ -40,6 +42,11 @@ func (c *PGConfig) WithAdditionalArgs(args ...string) *PGConfig { return c } +func (c *PGConfig) EnableFSync() *PGConfig { + c.FSync = true + return c +} + func (c *PGConfig) Start() (*PG, error) { return start(c) } diff --git a/pgtest.go b/pgtest.go index 903a12c..1a3660b 100644 --- a/pgtest.go +++ b/pgtest.go @@ -157,8 +157,12 @@ func start(config *PGConfig) (*PG, error) { "-D", dataDir, // Data directory "-k", sockDir, // Location for the UNIX socket "-h", "", // Disable TCP listening - "-F", // No fsync, just go fast } + + if config.FSync == false { + args = append(args, "-F") + } + if len(config.AdditionalArgs) > 0 { args = append(args, config.AdditionalArgs...) } From c7a4289e4a1f7245a410a63c1d731e6741ebdb02 Mon Sep 17 00:00:00 2001 From: Talha Abbasi Date: Thu, 17 Oct 2024 17:40:28 +0500 Subject: [PATCH 2/6] patch: update owner :gun: --- config_test.go | 5 +++-- go.mod | 2 +- pgtest_test.go | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/config_test.go b/config_test.go index 6cad64a..5becfcb 100644 --- a/config_test.go +++ b/config_test.go @@ -3,17 +3,18 @@ package pgtest_test import ( "testing" - "github.com/rubenv/pgtest" + "github.com/Apollo-group-io/pgtest" "github.com/stretchr/testify/assert" ) func TestPGConfig(t *testing.T) { assert := assert.New(t) - config := pgtest.New().From("/usr/bin").DataDir("/tmp/data").Persistent().WithAdditionalArgs("-c", "log_statement=all") + config := pgtest.New().From("/usr/bin").DataDir("/tmp/data").Persistent().EnableFSync().WithAdditionalArgs("-c", "log_statement=all") assert.True(config.IsPersistent) assert.EqualValues("/tmp/data", config.Dir) assert.EqualValues("/usr/bin", config.BinDir) assert.EqualValues([]string{"-c", "log_statement=all"}, config.AdditionalArgs) + assert.EqualValues(true, config.FSync) } diff --git a/go.mod b/go.mod index b651f22..c33b03d 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/rubenv/pgtest +module github.com/Apollo-group-io/pgtest go 1.16 diff --git a/pgtest_test.go b/pgtest_test.go index 11c89b9..5b4fd0d 100644 --- a/pgtest_test.go +++ b/pgtest_test.go @@ -4,7 +4,7 @@ import ( "os" "testing" - "github.com/rubenv/pgtest" + "github.com/Apollo-group-io/pgtest" "github.com/stretchr/testify/assert" ) From 5d7aa1d433949a11a2101dc9b1a30b56b271ac8b Mon Sep 17 00:00:00 2001 From: TheSalarKhan Date: Mon, 21 Oct 2024 19:24:43 +0500 Subject: [PATCH 3/6] point back to the original repo --- config_test.go | 2 +- go.mod | 2 +- pgtest_test.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config_test.go b/config_test.go index 5becfcb..c669ac9 100644 --- a/config_test.go +++ b/config_test.go @@ -3,7 +3,7 @@ package pgtest_test import ( "testing" - "github.com/Apollo-group-io/pgtest" + "github.com/rubenv/pgtest" "github.com/stretchr/testify/assert" ) diff --git a/go.mod b/go.mod index c33b03d..b651f22 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/Apollo-group-io/pgtest +module github.com/rubenv/pgtest go 1.16 diff --git a/pgtest_test.go b/pgtest_test.go index 5b4fd0d..11c89b9 100644 --- a/pgtest_test.go +++ b/pgtest_test.go @@ -4,7 +4,7 @@ import ( "os" "testing" - "github.com/Apollo-group-io/pgtest" + "github.com/rubenv/pgtest" "github.com/stretchr/testify/assert" ) From a6f9a664aae8f880a894b26a5087e80fb02c2bfb Mon Sep 17 00:00:00 2001 From: TheSalarKhan Date: Mon, 21 Oct 2024 23:20:25 +0500 Subject: [PATCH 4/6] WIP: add options for dbname and password --- config.go | 14 ++++++++++++ config_test.go | 4 +++- pgtest.go | 60 +++++++++++++++++++++++++++++++++++--------------- pgtest_test.go | 13 +++++++++++ 4 files changed, 72 insertions(+), 19 deletions(-) diff --git a/config.go b/config.go index 278217a..49a542a 100644 --- a/config.go +++ b/config.go @@ -6,6 +6,8 @@ type PGConfig struct { IsPersistent bool // Whether to make the current configuraton persistent or not AdditionalArgs []string // Additional arguments to pass to the postgres command FSync bool // To set -F flag + DbName string + Password string } func New() *PGConfig { @@ -14,6 +16,8 @@ func New() *PGConfig { Dir: "", IsPersistent: false, FSync: false, + DbName: "test", + Password: "", } } @@ -47,6 +51,16 @@ func (c *PGConfig) EnableFSync() *PGConfig { return c } +func (c *PGConfig) SetPassword(password string) *PGConfig { + c.Password = password + return c +} + +func (c *PGConfig) SetDbName(dbName string) *PGConfig { + c.DbName = dbName + return c +} + func (c *PGConfig) Start() (*PG, error) { return start(c) } diff --git a/config_test.go b/config_test.go index c669ac9..5156052 100644 --- a/config_test.go +++ b/config_test.go @@ -10,11 +10,13 @@ import ( func TestPGConfig(t *testing.T) { assert := assert.New(t) - config := pgtest.New().From("/usr/bin").DataDir("/tmp/data").Persistent().EnableFSync().WithAdditionalArgs("-c", "log_statement=all") + config := pgtest.New().From("/usr/bin").DataDir("/tmp/data").Persistent().EnableFSync().SetDbName("mydb").SetPassword("mypassword").WithAdditionalArgs("-c", "log_statement=all") assert.True(config.IsPersistent) assert.EqualValues("/tmp/data", config.Dir) assert.EqualValues("/usr/bin", config.BinDir) assert.EqualValues([]string{"-c", "log_statement=all"}, config.AdditionalArgs) assert.EqualValues(true, config.FSync) + assert.EqualValues("mydb", config.DbName) + assert.EqualValues("mypassword", config.Password) } diff --git a/pgtest.go b/pgtest.go index 1a3660b..33b2a2b 100644 --- a/pgtest.go +++ b/pgtest.go @@ -159,7 +159,7 @@ func start(config *PGConfig) (*PG, error) { "-h", "", // Disable TCP listening } - if config.FSync == false { + if !config.FSync { args = append(args, "-F") } @@ -185,22 +185,36 @@ func start(config *PGConfig) (*PG, error) { return nil, abort("Failed to start PostgreSQL", cmd, stderr, stdout, err) } - // Connect to DB - dsn := makeDSN(sockDir, "postgres", isRoot) + // Connect to DB "postgres" with no password + dsn := makeDSN(sockDir, "postgres", "") db, err := sql.Open("postgres", dsn) if err != nil { return nil, abort("Failed to connect to DB", cmd, stderr, stdout, err) } - // Prepare test database + // Prepare database with password err = retry(func() error { + // Ensure db exists var exists bool - err = db.QueryRow("SELECT 1 FROM pg_database WHERE datname = 'test'").Scan(&exists) - if exists { - return nil + err = db.QueryRow(fmt.Sprintf("SELECT 1 FROM pg_database WHERE datname = '%s'", config.DbName)).Scan(&exists) + if !exists { + _, err := db.Exec(fmt.Sprintf("CREATE DATABASE %s", config.DbName)) + return err } - _, err := db.Exec("CREATE DATABASE test") + // Ensure the password and the user are configured + user := pgUser() + if isRoot { + // Set password for postgres user + _, err = db.Exec(fmt.Sprintf("ALTER USER postgres WITH PASSWORD '%s'", config.Password)) + } else { + // Create a new user with the password + _, err = db.Exec(fmt.Sprintf("CREATE USER %s WITH PASSWORD '%s'", user, config.Password)) + if err != nil { + return err + } + _, err = db.Exec(fmt.Sprintf("GRANT ALL PRIVILEGES ON DATABASE %s TO %s", config.DbName, user)) + } return err }, 1000, 10*time.Millisecond) if err != nil { @@ -212,8 +226,8 @@ func start(config *PGConfig) (*PG, error) { return nil, abort("Failed to disconnect", cmd, stderr, stdout, err) } - // Connect to it properly - dsn = makeDSN(sockDir, "test", isRoot) + // Connect to db with password + dsn = makeDSN(sockDir, config.DbName, config.Password) db, err = sql.Open("postgres", dsn) if err != nil { return nil, abort("Failed to connect to test DB", cmd, stderr, stdout, err) @@ -226,7 +240,7 @@ func start(config *PGConfig) (*PG, error) { DB: db, Host: sockDir, - User: pgUser(isRoot), + User: pgUser(), Name: "test", persistent: config.IsPersistent, @@ -330,21 +344,31 @@ func findBinPath(binDir string) (string, error) { return "", fmt.Errorf("Did not find PostgreSQL executables installed") } -func pgUser(isRoot bool) string { - user := "" +func pgUser() string { + currentUser, err := user.Current() + isRoot := currentUser.Username == "root" if isRoot { - user = "postgres" + return "postgres" } - return user + if err != nil { + return "postgres" // fallback to postgres if we can't get the current user + } + return currentUser.Username } -func makeDSN(sockDir, dbname string, isRoot bool) string { +func makeDSN(sockDir, dbname, password string) string { dsnUser := "" - user := pgUser(isRoot) + dsnPassword := "" + user := pgUser() + // add user if defined if user != "" { dsnUser = fmt.Sprintf("user=%s", user) } - return fmt.Sprintf("host=%s dbname=%s %s", sockDir, dbname, dsnUser) + // add password if defined + if password != "" { + dsnPassword = fmt.Sprintf("password=%s", password) + } + return fmt.Sprintf("host=%s dbname=%s %s %s", sockDir, dbname, dsnUser, dsnPassword) } func retry(fn func() error, attempts int, interval time.Duration) error { diff --git a/pgtest_test.go b/pgtest_test.go index 11c89b9..7307909 100644 --- a/pgtest_test.go +++ b/pgtest_test.go @@ -96,3 +96,16 @@ func TestAdditionalArgs(t *testing.T) { err = pg.Stop() assert.NoError(err) } + +func TestDbNameAndPassword(t *testing.T) { + t.Parallel() + + assert := assert.New(t) + + pg, err := pgtest.New().SetDbName("mydbname").SetPassword("mypassword123").Start() + assert.NoError(err) + assert.NotNil(pg) + + err = pg.Stop() + assert.NoError(err) +} From b6908ca050cb21d14fb16a771e4e0b39ddb504ef Mon Sep 17 00:00:00 2001 From: TheSalarKhan Date: Tue, 22 Oct 2024 05:05:36 +0500 Subject: [PATCH 5/6] make dbName and password work with tests --- pgtest.go | 87 +++++++++++++++++++++++++++++++++++++++----------- pgtest_test.go | 83 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 150 insertions(+), 20 deletions(-) diff --git a/pgtest.go b/pgtest.go index 33b2a2b..2cb5c06 100644 --- a/pgtest.go +++ b/pgtest.go @@ -56,6 +56,45 @@ func StartPersistent(folder string) (*PG, error) { return start(New().DataDir(folder).Persistent()) } +// When the password is provided this function write the password +// to a temp file, and returns its path. +func createTempPasswordFile(password string, pgUID, pgGID int) (string, error) { + // Create a temporary file + tempFile, err := os.CreateTemp("", "pg_pwd_*") + if err != nil { + return "", fmt.Errorf("failed to create temp file: %w", err) + } + tempFilePath := tempFile.Name() + + // Set file permissions to 0600 (read/write for owner only) + if err := tempFile.Chmod(0600); err != nil { + tempFile.Close() + os.Remove(tempFilePath) + return "", fmt.Errorf("failed to set file permissions: %w", err) + } + + // Write the password to the file + if _, err := tempFile.WriteString(password); err != nil { + tempFile.Close() + os.Remove(tempFilePath) + return "", fmt.Errorf("failed to write password to file: %w", err) + } + + // Close the file + if err := tempFile.Close(); err != nil { + os.Remove(tempFilePath) + return "", fmt.Errorf("failed to close temp file: %w", err) + } + + // Change the owner + err = os.Chown(tempFilePath, pgUID, pgGID) + if err != nil { + return "", fmt.Errorf("failed to set permissions on the temp file: %w", err) + } + + return tempFilePath, nil +} + // start Starts a new PostgreSQL database // // Will listen on a unix socket and initialize the database in the given @@ -142,9 +181,34 @@ func start(config *PGConfig) (*PG, error) { // Initialize PostgreSQL data directory _, err = os.Stat(filepath.Join(dataDir, "postgresql.conf")) if os.IsNotExist(err) { - init := prepareCommand(isRoot, filepath.Join(binPath, "initdb"), + args := []string{ "-D", dataDir, - "--no-sync", + } + + // setup password if specified + if config.Password != "" { + passwordFile, err := createTempPasswordFile(config.Password, pgUID, pgGID) + if err != nil { + return nil, fmt.Errorf("failed to create password file: %w", err) + } + // for more info on how this is being done + // https://www.postgresql.org/docs/current/app-initdb.html#APP-INITDB-OPTION-AUTH + // https://www.postgresql.org/docs/current/app-initdb.html#APP-INITDB-OPTION-PWFILE + args = append(args, "-A", "scram-sha-256", fmt.Sprintf("--pwfile=%s", passwordFile)) + defer (func() { + err := os.Remove(passwordFile) + if err != nil { + fmt.Println("error while removing pwdfile: %w", err) + } + })() + } else { + // don't wait for creation of files if password not specified + args = append(args, "--no-sync") + } + + // execute the command + init := prepareCommand(isRoot, filepath.Join(binPath, "initdb"), + args..., ) out, err := init.CombinedOutput() if err != nil { @@ -185,8 +249,7 @@ func start(config *PGConfig) (*PG, error) { return nil, abort("Failed to start PostgreSQL", cmd, stderr, stdout, err) } - // Connect to DB "postgres" with no password - dsn := makeDSN(sockDir, "postgres", "") + dsn := makeDSN(sockDir, "postgres", config.Password) db, err := sql.Open("postgres", dsn) if err != nil { return nil, abort("Failed to connect to DB", cmd, stderr, stdout, err) @@ -199,23 +262,11 @@ func start(config *PGConfig) (*PG, error) { err = db.QueryRow(fmt.Sprintf("SELECT 1 FROM pg_database WHERE datname = '%s'", config.DbName)).Scan(&exists) if !exists { _, err := db.Exec(fmt.Sprintf("CREATE DATABASE %s", config.DbName)) - return err - } - - // Ensure the password and the user are configured - user := pgUser() - if isRoot { - // Set password for postgres user - _, err = db.Exec(fmt.Sprintf("ALTER USER postgres WITH PASSWORD '%s'", config.Password)) - } else { - // Create a new user with the password - _, err = db.Exec(fmt.Sprintf("CREATE USER %s WITH PASSWORD '%s'", user, config.Password)) if err != nil { return err } - _, err = db.Exec(fmt.Sprintf("GRANT ALL PRIVILEGES ON DATABASE %s TO %s", config.DbName, user)) } - return err + return nil }, 1000, 10*time.Millisecond) if err != nil { return nil, abort("Failed to prepare test DB", cmd, stderr, stdout, err) @@ -241,7 +292,7 @@ func start(config *PGConfig) (*PG, error) { Host: sockDir, User: pgUser(), - Name: "test", + Name: config.DbName, persistent: config.IsPersistent, diff --git a/pgtest_test.go b/pgtest_test.go index 7307909..2554661 100644 --- a/pgtest_test.go +++ b/pgtest_test.go @@ -1,7 +1,12 @@ package pgtest_test import ( + "database/sql" + "fmt" "os" + "os/user" + "path/filepath" + "reflect" "testing" "github.com/rubenv/pgtest" @@ -97,15 +102,89 @@ func TestAdditionalArgs(t *testing.T) { assert.NoError(err) } -func TestDbNameAndPassword(t *testing.T) { +func TestWrongDbNameAndPassword(t *testing.T) { + testDbWithUserNameAndPassword(t, "wrongdbName", "wrongPassword", false) +} + +func TestWrongDbName(t *testing.T) { + testDbWithUserNameAndPassword(t, "wrongdbName", "correctpassword", false) +} + +func TestWrongDbPassword(t *testing.T) { + testDbWithUserNameAndPassword(t, "correctdbname", "wrongpassword", false) +} + +func TestCorrectCredentials(t *testing.T) { + testDbWithUserNameAndPassword(t, "correctdbname", "correctpassword", true) +} + +// util functions for the dbname/password tests +func testDbWithUserNameAndPassword(t *testing.T, databaseName, password string, assertErrorNil bool) { t.Parallel() assert := assert.New(t) - pg, err := pgtest.New().SetDbName("mydbname").SetPassword("mypassword123").Start() + pg, err := pgtest.New().SetDbName("correctdbname").SetPassword("correctpassword").Start() assert.NoError(err) assert.NotNil(pg) + // connect using username and password via a different connection + // using the sockDir. + dsn := makeDsn(getSockDir(pg, t), databaseName, password) + // not testing the error returned by Open, because + // sometimes it returns without connecting. + // so we use .Ping to get the actual error. + connection, _ := sql.Open("postgres", dsn) + err = connection.Ping() + if assertErrorNil { + assert.NoError(err) + } else { + assert.Error(err) + } + + err = connection.Close() + assert.NoError(err) + err = pg.Stop() assert.NoError(err) } + +func pgUser() string { + currentUser, err := user.Current() + isRoot := currentUser.Username == "root" + if isRoot { + return "postgres" + } + if err != nil { + return "postgres" // fallback to postgres if we can't get the current user + } + return currentUser.Username +} + +func makeDsn(sockDir, dbname, password string) string { + dsnUser := "" + dsnPassword := "" + user := pgUser() + // add user if defined + if user != "" { + dsnUser = fmt.Sprintf("user=%s", user) + } + // add password if defined + if password != "" { + dsnPassword = fmt.Sprintf("password=%s", password) + } + return fmt.Sprintf("host=%s dbname=%s %s %s", sockDir, dbname, dsnUser, dsnPassword) +} + +func getSockDir(pg *pgtest.PG, t *testing.T) string { + // Use reflection to access the private 'dir' field + pgValue := reflect.ValueOf(pg).Elem() + dirField := pgValue.FieldByName("dir") + if !dirField.IsValid() { + t.Fatal("Unable to find 'dir' field in PostgreSQL struct") + } + + dbRoot := dirField.String() + + return filepath.Join(dbRoot, "sock") +} From 2b3953def25e2b30c22ed647598e427fddfe93ae Mon Sep 17 00:00:00 2001 From: TheSalarKhan Date: Tue, 22 Oct 2024 05:23:14 +0500 Subject: [PATCH 6/6] post self-review changes --- config.go | 4 ++-- pgtest.go | 58 ++++++++++++++++++++++++++++++------------------------- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/config.go b/config.go index 49a542a..a04c5af 100644 --- a/config.go +++ b/config.go @@ -5,7 +5,7 @@ type PGConfig struct { Dir string // Directory for storing database files, removed for non-persistent configs IsPersistent bool // Whether to make the current configuraton persistent or not AdditionalArgs []string // Additional arguments to pass to the postgres command - FSync bool // To set -F flag + FSync bool // Sets -F flag when false DbName string Password string } @@ -15,7 +15,7 @@ func New() *PGConfig { BinDir: "", Dir: "", IsPersistent: false, - FSync: false, + FSync: false, // disable fsync by default - just go fast. DbName: "test", Password: "", } diff --git a/pgtest.go b/pgtest.go index 2cb5c06..81426e3 100644 --- a/pgtest.go +++ b/pgtest.go @@ -56,43 +56,50 @@ func StartPersistent(folder string) (*PG, error) { return start(New().DataDir(folder).Persistent()) } -// When the password is provided this function write the password +// When the password is provided this function writes the password // to a temp file, and returns its path. -func createTempPasswordFile(password string, pgUID, pgGID int) (string, error) { +func createTempPasswordFile(password string, pgUID, pgGID int) (string, func(), error) { // Create a temporary file - tempFile, err := os.CreateTemp("", "pg_pwd_*") + pwdTempFile, err := os.CreateTemp("", "pg_pwd_*") if err != nil { - return "", fmt.Errorf("failed to create temp file: %w", err) + return "", nil, fmt.Errorf("failed to create temp file: %w", err) } - tempFilePath := tempFile.Name() + tempFilePath := pwdTempFile.Name() // Set file permissions to 0600 (read/write for owner only) - if err := tempFile.Chmod(0600); err != nil { - tempFile.Close() + if err := pwdTempFile.Chmod(0600); err != nil { + pwdTempFile.Close() os.Remove(tempFilePath) - return "", fmt.Errorf("failed to set file permissions: %w", err) + return "", nil, fmt.Errorf("failed to set file permissions: %w", err) } // Write the password to the file - if _, err := tempFile.WriteString(password); err != nil { - tempFile.Close() + if _, err := pwdTempFile.WriteString(password); err != nil { + pwdTempFile.Close() os.Remove(tempFilePath) - return "", fmt.Errorf("failed to write password to file: %w", err) + return "", nil, fmt.Errorf("failed to write password to file: %w", err) } // Close the file - if err := tempFile.Close(); err != nil { + if err := pwdTempFile.Close(); err != nil { os.Remove(tempFilePath) - return "", fmt.Errorf("failed to close temp file: %w", err) + return "", nil, fmt.Errorf("failed to close temp file: %w", err) } // Change the owner err = os.Chown(tempFilePath, pgUID, pgGID) if err != nil { - return "", fmt.Errorf("failed to set permissions on the temp file: %w", err) + return "", nil, fmt.Errorf("failed to set permissions on the temp file: %w", err) } - return tempFilePath, nil + cleanupPwdFile := func() { + err := os.Remove(tempFilePath) + if err != nil { + fmt.Println("error while removing pwdfile: %w", err) + } + } + + return tempFilePath, cleanupPwdFile, nil } // start Starts a new PostgreSQL database @@ -183,27 +190,21 @@ func start(config *PGConfig) (*PG, error) { if os.IsNotExist(err) { args := []string{ "-D", dataDir, + "--no-sync", } // setup password if specified if config.Password != "" { - passwordFile, err := createTempPasswordFile(config.Password, pgUID, pgGID) + pwdFile, cleanupPwdFile, err := createTempPasswordFile(config.Password, pgUID, pgGID) if err != nil { return nil, fmt.Errorf("failed to create password file: %w", err) } // for more info on how this is being done // https://www.postgresql.org/docs/current/app-initdb.html#APP-INITDB-OPTION-AUTH // https://www.postgresql.org/docs/current/app-initdb.html#APP-INITDB-OPTION-PWFILE - args = append(args, "-A", "scram-sha-256", fmt.Sprintf("--pwfile=%s", passwordFile)) - defer (func() { - err := os.Remove(passwordFile) - if err != nil { - fmt.Println("error while removing pwdfile: %w", err) - } - })() - } else { - // don't wait for creation of files if password not specified - args = append(args, "--no-sync") + args = append(args, "-A", "scram-sha-256", fmt.Sprintf("--pwfile=%s", pwdFile)) + // remove the password file, when we return from start() + defer cleanupPwdFile() } // execute the command @@ -223,7 +224,12 @@ func start(config *PGConfig) (*PG, error) { "-h", "", // Disable TCP listening } + // by default config.Fsync is false, + // so fsync is disabled, unless it is set + // true by the user, in which case we + // skip the -F flag if !config.FSync { + // no fsync, just go fast args = append(args, "-F") }