From bd731be58d03c72e8a57d299168a4e5f40176119 Mon Sep 17 00:00:00 2001 From: Jonathan Hess Date: Wed, 17 Jul 2024 14:43:58 -0600 Subject: [PATCH] test: Add e2e test to access instance using DNS SRV record. part of #842 WIP: e2e test changes --- e2e_mysql_test.go | 56 +++++++++++++++++++++++++++--------- e2e_postgres_test.go | 67 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 13 deletions(-) diff --git a/e2e_mysql_test.go b/e2e_mysql_test.go index 91f197ca..bfc9bdfd 100644 --- a/e2e_mysql_test.go +++ b/e2e_mysql_test.go @@ -15,12 +15,15 @@ package cloudsqlconn_test import ( + "context" "database/sql" + "fmt" "os" "testing" "time" "cloud.google.com/go/cloudsqlconn" + "cloud.google.com/go/cloudsqlconn/instance" "cloud.google.com/go/cloudsqlconn/mysql/mysql" gomysql "github.com/go-sql-driver/mysql" ) @@ -54,25 +57,52 @@ func requireMySQLVars(t *testing.T) { } } +type mockResolver struct { +} + +func (r *mockResolver) Resolve(_ context.Context, name string) (instanceName instance.ConnName, err error) { + if name == "mysql.example.com" { + return instance.ParseConnNameWithDomainName(mysqlConnName, "mysql.example.com") + } + return instance.ConnName{}, fmt.Errorf("no resolution for %v", name) +} + func TestMySQLDriver(t *testing.T) { if testing.Short() { t.Skip("skipping MySQL integration tests") } tcs := []struct { - desc string - driverName string - opts []cloudsqlconn.Option + desc string + driverName string + instanceName string + user string + password string + opts []cloudsqlconn.Option }{ { - desc: "default options", - driverName: "cloudsql-mysql", - opts: nil, + desc: "default options", + driverName: "cloudsql-mysql", + opts: nil, + instanceName: mysqlConnName, + user: mysqlUser, + password: mysqlPass, + }, + { + desc: "auto IAM authn", + driverName: "cloudsql-mysql-iam", + opts: []cloudsqlconn.Option{cloudsqlconn.WithIAMAuthN()}, + instanceName: mysqlIAMConnName, + user: mysqlIAMUser, + password: "password", }, { - desc: "auto IAM authn", - driverName: "cloudsql-mysql-iam", - opts: []cloudsqlconn.Option{cloudsqlconn.WithIAMAuthN()}, + desc: "with dns", + driverName: "cloudsql-mysql-dns", + opts: []cloudsqlconn.Option{cloudsqlconn.WithResolver(&mockResolver{})}, + instanceName: "mysql.example.com", + user: mysqlUser, + password: mysqlPass, }, } @@ -85,18 +115,18 @@ func TestMySQLDriver(t *testing.T) { } t.Log(now) } - cleanup, err := mysql.RegisterDriver(tc.driverName) + cleanup, err := mysql.RegisterDriver(tc.driverName, tc.opts...) if err != nil { t.Fatalf("failed to register driver: %v", err) } defer cleanup() cfg := gomysql.NewConfig() cfg.CheckConnLiveness = true - cfg.User = mysqlUser - cfg.Passwd = mysqlPass + cfg.User = tc.user + cfg.Passwd = tc.password cfg.DBName = mysqlDB cfg.Net = tc.driverName - cfg.Addr = mysqlConnName + cfg.Addr = tc.instanceName cfg.Params = map[string]string{"parseTime": "true"} db, err := sql.Open("mysql", cfg.FormatDSN()) diff --git a/e2e_postgres_test.go b/e2e_postgres_test.go index 79800b60..74866183 100644 --- a/e2e_postgres_test.go +++ b/e2e_postgres_test.go @@ -28,6 +28,7 @@ import ( "time" "cloud.google.com/go/cloudsqlconn" + "cloud.google.com/go/cloudsqlconn/instance" "github.com/jackc/pgx/v5/pgxpool" "golang.org/x/oauth2" "golang.org/x/oauth2/google" @@ -161,6 +162,62 @@ func TestPostgresCASConnect(t *testing.T) { t.Log(now) } +type pgMockResolver struct { +} + +func (r *pgMockResolver) Resolve(_ context.Context, name string) (instanceName instance.ConnName, err error) { + if name == "pg.example.com" { + return instance.ParseConnNameWithDomainName(postgresConnName, "pg.example.com") + } + return instance.ConnName{}, fmt.Errorf("no resolution for %v", name) +} + +func TestPostgresPgxPoolConnectDomainName(t *testing.T) { + if testing.Short() { + t.Skip("skipping Postgres integration tests") + } + requirePostgresVars(t) + pgxv5.RegisterDriver("pgxpool-connect") + + ctx := context.Background() + + // Configure the driver to connect to the database + dsn := fmt.Sprintf("user=%s password=%s dbname=%s sslmode=disable", postgresUser, postgresPass, postgresDB) + config, err := pgxpool.ParseConfig(dsn) + if err != nil { + t.Fatalf("failed to parse pgx config: %v", err) + } + + // Create a new dialer with any options + d, err := cloudsqlconn.NewDialer(ctx, cloudsqlconn.WithResolver(&pgMockResolver{})) + if err != nil { + t.Fatalf("failed to init Dialer: %v", err) + } + + // call cleanup when you're done with the database connection to close dialer + cleanup := func() { d.Close() } + t.Cleanup(cleanup) + + // Tell the driver to use the Cloud SQL Go Connector to create connections + // postgresConnName takes the form of 'project:region:instance'. + config.ConnConfig.DialFunc = func(ctx context.Context, _ string, _ string) (net.Conn, error) { + return d.Dial(ctx, "pg.example.com") //TODO: Replace this with a real DNS instance. + } + + pool, err := pgxpool.NewWithConfig(ctx, config) + if err != nil { + t.Fatalf("failed to create pool: %s", err) + } + defer pool.Close() + + var now time.Time + err = pool.QueryRow(context.Background(), "SELECT NOW()").Scan(&now) + if err != nil { + t.Fatalf("QueryRow failed: %s", err) + } + t.Log(now) +} + func TestPostgresConnectWithIAMUser(t *testing.T) { if testing.Short() { t.Skip("skipping Postgres integration tests") @@ -264,6 +321,7 @@ func TestPostgresV5Hook(t *testing.T) { driver string source string IAMAuthN bool + resolver bool }{ { driver: "cloudsql-postgres-v5", @@ -277,6 +335,13 @@ func TestPostgresV5Hook(t *testing.T) { postgresConnName, postgresUserIAM, postgresDB), IAMAuthN: true, }, + { + driver: "cloudsql-postgres-v5-dns", + source: fmt.Sprintf("host=%s user=%s password=%s dbname=%s sslmode=disable", + "pg.example.com", postgresUser, postgresPass, postgresDB), + IAMAuthN: false, + resolver: true, + }, } if testing.Short() { @@ -293,6 +358,8 @@ func TestPostgresV5Hook(t *testing.T) { for _, tc := range tests { if tc.IAMAuthN { pgxv5.RegisterDriver(tc.driver, cloudsqlconn.WithIAMAuthN()) + } else if tc.resolver { + pgxv5.RegisterDriver(tc.driver, cloudsqlconn.WithResolver(&pgMockResolver{})) } else { pgxv5.RegisterDriver(tc.driver) }