179 lines
5.8 KiB
Go
179 lines
5.8 KiB
Go
package utils
|
|
|
|
import (
|
|
"context"
|
|
"net"
|
|
"net/http"
|
|
"testing"
|
|
|
|
"github.com/go-errors/errors"
|
|
"github.com/h2non/gock"
|
|
"github.com/jackc/pgconn"
|
|
"github.com/spf13/viper"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/supabase/cli/internal/testing/apitest"
|
|
"github.com/supabase/cli/internal/utils/cloudflare"
|
|
"github.com/supabase/cli/pkg/pgtest"
|
|
)
|
|
|
|
var dbConfig = pgconn.Config{
|
|
Host: GetSupabaseDbHost(apitest.RandomProjectRef()),
|
|
Port: 6543,
|
|
User: "admin",
|
|
Password: "password",
|
|
Database: "postgres",
|
|
}
|
|
|
|
const (
|
|
PG13_POOLER_URL = "postgres://postgres:[YOUR-PASSWORD]@aws-0-ap-southeast-1.pooler.supabase.com:6543/postgres?options=reference%3Dzupyfdrjfhbeevcogohz"
|
|
PG15_POOLER_URL = "postgres://postgres.zupyfdrjfhbeevcogohz:[YOUR-PASSWORD]@fly-0-sin.pooler.supabase.com:6543/postgres"
|
|
)
|
|
|
|
func TestConnectByConfig(t *testing.T) {
|
|
t.Run("connects to remote postgres with DoH", func(t *testing.T) {
|
|
Config.Db.Pooler.ConnectionString = ""
|
|
DNSResolver.Value = DNS_OVER_HTTPS
|
|
// Setup http mock
|
|
defer gock.OffAll()
|
|
// pgx makes 2 calls to resolve ip for each connect request
|
|
gock.New("https://1.1.1.1").
|
|
Get("/dns-query").
|
|
MatchParam("name", dbConfig.Host).
|
|
MatchHeader("accept", "application/dns-json").
|
|
Reply(http.StatusOK).
|
|
JSON(&cloudflare.DNSResponse{Answer: []cloudflare.DNSAnswer{
|
|
{Type: cloudflare.TypeA, Data: "127.0.0.1"},
|
|
}})
|
|
gock.New("https://1.1.1.1").
|
|
Get("/dns-query").
|
|
MatchParam("name", dbConfig.Host).
|
|
MatchHeader("accept", "application/dns-json").
|
|
Reply(http.StatusOK).
|
|
JSON(&cloudflare.DNSResponse{Answer: []cloudflare.DNSAnswer{
|
|
{Type: cloudflare.TypeA, Data: "127.0.0.1"},
|
|
}})
|
|
// Setup mock postgres
|
|
conn := pgtest.NewConn()
|
|
defer conn.Close(t)
|
|
// Run test
|
|
c, err := ConnectByConfig(context.Background(), dbConfig, conn.Intercept)
|
|
require.NoError(t, err)
|
|
defer c.Close(context.Background())
|
|
assert.NoError(t, err)
|
|
})
|
|
|
|
t.Run("connects with unescaped db password", func(t *testing.T) {
|
|
DNSResolver.Value = DNS_GO_NATIVE
|
|
// Setup mock postgres
|
|
conn := pgtest.NewConn()
|
|
defer conn.Close(t)
|
|
// Run test
|
|
config := *dbConfig.Copy()
|
|
config.Host = "localhost"
|
|
config.Password = "pass word"
|
|
c, err := ConnectByConfig(context.Background(), config, conn.Intercept)
|
|
require.NoError(t, err)
|
|
defer c.Close(context.Background())
|
|
assert.Equal(t, config.Password, c.Config().Password)
|
|
})
|
|
|
|
t.Run("no retry on connecting successfully with pooler", func(t *testing.T) {
|
|
Config.Db.Pooler.ConnectionString = PG15_POOLER_URL
|
|
DNSResolver.Value = DNS_GO_NATIVE
|
|
// Setup mock postgres
|
|
conn := pgtest.NewConn()
|
|
defer conn.Close(t)
|
|
// Run test
|
|
c, err := ConnectByConfig(context.Background(), dbConfig, conn.Intercept)
|
|
// Check error
|
|
require.NoError(t, err)
|
|
defer c.Close(context.Background())
|
|
assert.Empty(t, apitest.ListUnmatchedRequests())
|
|
})
|
|
|
|
t.Run("fallback to postgres port on dial error", func(t *testing.T) {
|
|
Config.Db.Pooler.ConnectionString = PG15_POOLER_URL
|
|
DNSResolver.Value = DNS_OVER_HTTPS
|
|
netErr := errors.New("network error")
|
|
// Setup http mock
|
|
defer gock.OffAll()
|
|
gock.New("https://1.1.1.1").
|
|
Get("/dns-query").
|
|
MatchParam("name", dbConfig.Host).
|
|
MatchHeader("accept", "application/dns-json").
|
|
ReplyError(&net.OpError{Op: "dial", Err: netErr})
|
|
gock.New("https://1.1.1.1").
|
|
Get("/dns-query").
|
|
MatchParam("name", "fly-0-sin.pooler.supabase.com").
|
|
MatchHeader("accept", "application/dns-json").
|
|
ReplyError(&net.OpError{Op: "dial", Err: netErr})
|
|
// Run test
|
|
_, err := ConnectByConfig(context.Background(), dbConfig)
|
|
// Check error
|
|
require.ErrorIs(t, err, netErr)
|
|
assert.Empty(t, apitest.ListUnmatchedRequests())
|
|
})
|
|
}
|
|
|
|
func TestConnectLocal(t *testing.T) {
|
|
t.Run("connects with debug log", func(t *testing.T) {
|
|
viper.Set("DEBUG", true)
|
|
_, err := ConnectLocalPostgres(context.Background(), pgconn.Config{Host: "0", Port: 6543})
|
|
assert.ErrorContains(t, err, "failed to connect to postgres")
|
|
})
|
|
|
|
t.Run("throws error on invalid port", func(t *testing.T) {
|
|
Config.Db.Port = 0
|
|
_, err := ConnectLocalPostgres(context.Background(), pgconn.Config{})
|
|
assert.ErrorContains(t, err, "invalid port (outside range)")
|
|
})
|
|
}
|
|
|
|
func TestPoolerConfig(t *testing.T) {
|
|
t.Run("parses options ref", func(t *testing.T) {
|
|
Config.Db.Pooler.ConnectionString = PG13_POOLER_URL
|
|
assert.NotNil(t, GetPoolerConfig("zupyfdrjfhbeevcogohz"))
|
|
})
|
|
|
|
t.Run("parses username ref", func(t *testing.T) {
|
|
Config.Db.Pooler.ConnectionString = PG15_POOLER_URL
|
|
assert.NotNil(t, GetPoolerConfig("zupyfdrjfhbeevcogohz"))
|
|
})
|
|
|
|
t.Run("returns nil on missing url", func(t *testing.T) {
|
|
Config.Db.Pooler.ConnectionString = ""
|
|
assert.Nil(t, GetPoolerConfig("zupyfdrjfhbeevcogohz"))
|
|
})
|
|
|
|
t.Run("returns nil on malformed url", func(t *testing.T) {
|
|
Config.Db.Pooler.ConnectionString = "malformed"
|
|
assert.Nil(t, GetPoolerConfig("zupyfdrjfhbeevcogohz"))
|
|
})
|
|
|
|
t.Run("returns nil on mismatched project", func(t *testing.T) {
|
|
Config.Db.Pooler.ConnectionString = PG13_POOLER_URL
|
|
assert.Nil(t, GetPoolerConfig("nlhaskwsizylhnffaqkd"))
|
|
Config.Db.Pooler.ConnectionString = PG15_POOLER_URL
|
|
assert.Nil(t, GetPoolerConfig("nlhaskwsizylhnffaqkd"))
|
|
})
|
|
|
|
t.Run("returns nil on invalid host", func(t *testing.T) {
|
|
Config.Db.Pooler.ConnectionString = "postgres://postgres.zupyfdrjfhbeevcogohz:[YOUR-PASSWORD]@localhost:6543/postgres"
|
|
assert.Nil(t, GetPoolerConfig("zupyfdrjfhbeevcogohz"))
|
|
})
|
|
}
|
|
|
|
func TestPostgresURL(t *testing.T) {
|
|
url := ToPostgresURL(pgconn.Config{
|
|
Host: "2406:da18:4fd:9b0d:80ec:9812:3e65:450b",
|
|
Port: 5432,
|
|
User: "postgres",
|
|
Password: "!@#$%^&*()",
|
|
RuntimeParams: map[string]string{
|
|
"options": "test",
|
|
},
|
|
})
|
|
assert.Equal(t, `postgresql://postgres:%21%40%23$%25%5E&%2A%28%29@[2406:da18:4fd:9b0d:80ec:9812:3e65:450b]:5432/?connect_timeout=10&options=test`, url)
|
|
}
|