Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit aa070c4

Browse files
committed
feat(coderd/database/dbtestutil): set a random timezone in the db
1 parent 3dc1e22 commit aa070c4

File tree

1 file changed

+79
-1
lines changed
  • coderd/database/dbtestutil

1 file changed

+79
-1
lines changed

coderd/database/dbtestutil/db.go

+79-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ package dbtestutil
33
import (
44
"context"
55
"database/sql"
6+
"fmt"
7+
"net/url"
68
"os"
9+
"strings"
710
"testing"
811

912
"github.com/stretchr/testify/require"
@@ -19,9 +22,29 @@ func WillUsePostgres() bool {
1922
return os.Getenv("DB") != ""
2023
}
2124

22-
func NewDB(t testing.TB) (database.Store, pubsub.Pubsub) {
25+
type options struct {
26+
fixedTimezone bool
27+
}
28+
29+
type Option func(*options)
30+
31+
// WithFixedTimezone disables the random timezone setting for the database.
32+
//
33+
// DEPRECATED: If you need to use this, you may have a timezone-related bug.
34+
func WithFixedTimezone() Option {
35+
return func(o *options) {
36+
o.fixedTimezone = true
37+
}
38+
}
39+
40+
func NewDB(t testing.TB, opts ...Option) (database.Store, pubsub.Pubsub) {
2341
t.Helper()
2442

43+
var o options
44+
for _, opt := range opts {
45+
opt(&o)
46+
}
47+
2548
db := dbfake.New()
2649
ps := pubsub.NewInMemory()
2750
if WillUsePostgres() {
@@ -35,6 +58,13 @@ func NewDB(t testing.TB) (database.Store, pubsub.Pubsub) {
3558
require.NoError(t, err)
3659
t.Cleanup(closePg)
3760
}
61+
62+
if !o.fixedTimezone {
63+
// To make sure we find timezone-related issues, we set the timezone of the database to a random one.
64+
dbName := dbNameFromConnectionURL(t, connectionURL)
65+
setRandDBTimezone(t, connectionURL, dbName)
66+
}
67+
3868
sqlDB, err := sql.Open("postgres", connectionURL)
3969
require.NoError(t, err)
4070
t.Cleanup(func() {
@@ -51,3 +81,51 @@ func NewDB(t testing.TB) (database.Store, pubsub.Pubsub) {
5181

5282
return db, ps
5383
}
84+
85+
// setRandDBTimezone sets the timezone of the database to the given timezone.
86+
// The timezone change does not take effect until the next session, so
87+
// we do this in our own connection
88+
func setRandDBTimezone(t testing.TB, dbURL, dbname string) {
89+
t.Helper()
90+
91+
sqlDB, err := sql.Open("postgres", dbURL)
92+
require.NoError(t, err)
93+
defer func() {
94+
_ = sqlDB.Close()
95+
}()
96+
97+
// Pick a random timezone. We can simply pick from pg_timezone_names.
98+
var tz string
99+
err = sqlDB.QueryRow("SELECT name FROM pg_timezone_names ORDER BY RANDOM() LIMIT 1").Scan(&tz)
100+
require.NoError(t, err)
101+
102+
// Set the timezone for the database.
103+
t.Logf("setting timezone of database %q to %q", dbname, tz)
104+
// We apparently can't use placeholders here, sadly.
105+
// nolint: gosec // This is not user input and this is only executed in tests
106+
_, err = sqlDB.Exec(fmt.Sprintf("ALTER DATABASE %s SET TIMEZONE TO %q", dbname, tz))
107+
require.NoError(t, err, "failed to set timezone for database")
108+
109+
// Ensure the timezone was set.
110+
// We need to reconnect for this.
111+
_ = sqlDB.Close()
112+
113+
sqlDB, err = sql.Open("postgres", dbURL)
114+
defer func() {
115+
_ = sqlDB.Close()
116+
}()
117+
require.NoError(t, err, "failed to reconnect to database")
118+
var dbTz string
119+
err = sqlDB.QueryRow("SHOW TIMEZONE").Scan(&dbTz)
120+
require.NoError(t, err, "failed to get timezone from database")
121+
require.Equal(t, tz, dbTz, "database timezone was not set correctly")
122+
}
123+
124+
// dbNameFromConnectionURL returns the database name from the given connection URL.
125+
func dbNameFromConnectionURL(t testing.TB, connectionURL string) string {
126+
// connectionURL is of the form postgres://user:pass@host:port/dbname
127+
// We want to extract the dbname part.
128+
u, err := url.Parse(connectionURL)
129+
require.NoError(t, err)
130+
return strings.TrimPrefix(u.Path, "/")
131+
}

0 commit comments

Comments
 (0)