From 9dbebbacf0f84eb0f9215bec48848d55f01a9aa0 Mon Sep 17 00:00:00 2001 From: Josh Giles Date: Tue, 21 Feb 2023 22:23:40 -0500 Subject: [PATCH 1/2] Fix #94: Support custom start parameters. Add a StartParameters config taking configuration settings. These run-time configuration parameters override those set in the default postgres.conf, and are passed to the postgres process via the options flag of pg_ctl. --- README.md | 1 + config.go | 10 ++++++++++ embedded_postgres.go | 11 ++++++++++- embedded_postgres_test.go | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 56 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d13bc05..f8fe234 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,7 @@ RuntimePath("/tmp"). BinaryRepositoryURL("https://repo.local/central.proxy"). Port(9876). StartTimeout(45 * time.Second). +StartParameters(map[string]string{"max_connections": "200"}). Logger(logger)) err := postgres.Start() diff --git a/config.go b/config.go index fd789fe..ff21e73 100644 --- a/config.go +++ b/config.go @@ -17,6 +17,7 @@ type Config struct { dataPath string binariesPath string locale string + startParameters map[string]string binaryRepositoryURL string startTimeout time.Duration logger io.Writer @@ -100,6 +101,15 @@ func (c Config) Locale(locale string) Config { return c } +// StartParameters sets run-time parameters when starting Postgres (passed to Postgres via "-c"). +// +// These parameters can be used to override the default configuration values in postgres.conf such +// as max_connections=100. See https://www.postgresql.org/docs/current/runtime-config.html +func (c Config) StartParameters(parameters map[string]string) Config { + c.startParameters = parameters + return c +} + // StartTimeout sets the max timeout that will be used when starting the Postgres process and creating the initial database. func (c Config) StartTimeout(timeout time.Duration) Config { c.startTimeout = timeout diff --git a/embedded_postgres.go b/embedded_postgres.go index a72a3cb..0b3e858 100644 --- a/embedded_postgres.go +++ b/embedded_postgres.go @@ -179,11 +179,20 @@ func (ep *EmbeddedPostgres) Stop() error { return nil } +func encodeOptions(port uint32, parameters map[string]string) string { + options := []string{fmt.Sprintf("-p %d", port)} + for k, v := range parameters { + // Single-quote parameter values - they may have spaces. + options = append(options, fmt.Sprintf("-c %s='%s'", k, v)) + } + return strings.Join(options, " ") +} + func startPostgres(ep *EmbeddedPostgres) error { postgresBinary := filepath.Join(ep.config.binariesPath, "bin/pg_ctl") postgresProcess := exec.Command(postgresBinary, "start", "-w", "-D", ep.config.dataPath, - "-o", fmt.Sprintf(`"-p %d"`, ep.config.port)) + "-o", encodeOptions(ep.config.port, ep.config.startParameters)) postgresProcess.Stdout = ep.syncedLogger.file postgresProcess.Stderr = ep.syncedLogger.file diff --git a/embedded_postgres_test.go b/embedded_postgres_test.go index de25204..9c407c2 100644 --- a/embedded_postgres_test.go +++ b/embedded_postgres_test.go @@ -354,6 +354,41 @@ func Test_CustomLocaleConfig(t *testing.T) { } } +func Test_CustomStartParameters(t *testing.T) { + //database := NewDatabase(DefaultConfig()) + database := NewDatabase(DefaultConfig().StartParameters(map[string]string{ + "max_connections": "101", + "shared_buffers": "16 MB", // Ensure a parameter with spaces encodes correctly. + })) + if err := database.Start(); err != nil { + shutdownDBAndFail(t, err, database) + } + + db, err := sql.Open("postgres", "host=localhost port=5432 user=postgres password=postgres dbname=postgres sslmode=disable") + if err != nil { + shutdownDBAndFail(t, err, database) + } + + if err := db.Ping(); err != nil { + shutdownDBAndFail(t, err, database) + } + + row := db.QueryRow("SHOW max_connections") + var res string + if err := row.Scan(&res); err != nil { + shutdownDBAndFail(t, err, database) + } + assert.Equal(t, "101", res) + + if err := db.Close(); err != nil { + shutdownDBAndFail(t, err, database) + } + + if err := database.Stop(); err != nil { + shutdownDBAndFail(t, err, database) + } +} + func Test_CanStartAndStopTwice(t *testing.T) { database := NewDatabase() From 61524db132a85134717fe12dcc75ffb1756b1af0 Mon Sep 17 00:00:00 2001 From: Josh Giles Date: Tue, 21 Feb 2023 22:45:34 -0500 Subject: [PATCH 2/2] Fix error quoting expectations. --- embedded_postgres_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embedded_postgres_test.go b/embedded_postgres_test.go index 9c407c2..2d930a4 100644 --- a/embedded_postgres_test.go +++ b/embedded_postgres_test.go @@ -231,7 +231,7 @@ func Test_ErrorWhenCannotStartPostgresProcess(t *testing.T) { err = database.Start() - assert.EqualError(t, err, fmt.Sprintf(`could not start postgres using %s/bin/pg_ctl start -w -D %s/data -o "-p 5432"`, extractPath, extractPath)) + assert.EqualError(t, err, fmt.Sprintf(`could not start postgres using %s/bin/pg_ctl start -w -D %s/data -o -p 5432`, extractPath, extractPath)) } func Test_CustomConfig(t *testing.T) {