Skip to content

feat(examples): Use hosted MySQL databases for tests #2982

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Nov 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 0 additions & 14 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,6 @@ jobs:
name: test
runs-on: ubuntu-latest

services:
mysql:
image: "mysql/mysql-server:8.0"
env:
MYSQL_DATABASE: mysql
MYSQL_ROOT_HOST: '%'
MYSQL_ROOT_PASSWORD: mysecretpassword
ports:
- 3306:3306

steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v4
Expand All @@ -64,10 +54,6 @@ jobs:
- name: test ./...
run: gotestsum --junitfile junit.xml -- --tags=examples -timeout 20m ./...
env:
MYSQL_DATABASE: mysql
MYSQL_HOST: localhost
MYSQL_PORT: ${{ job.services.mysql.ports['3306'] }}
MYSQL_ROOT_PASSWORD: mysecretpassword
CI_SQLC_PROJECT_ID: ${{ secrets.CI_SQLC_PROJECT_ID }}
CI_SQLC_AUTH_TOKEN: ${{ secrets.CI_SQLC_AUTH_TOKEN }}
SQLC_AUTH_TOKEN: ${{ secrets.CI_SQLC_AUTH_TOKEN }}
Expand Down
14 changes: 10 additions & 4 deletions examples/authors/mysql/db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,20 @@ import (
"database/sql"
"testing"

"github.com/sqlc-dev/sqlc/internal/sqltest"
_ "github.com/go-sql-driver/mysql"

"github.com/sqlc-dev/sqlc/internal/sqltest/hosted"
)

func TestAuthors(t *testing.T) {
sdb, cleanup := sqltest.MySQL(t, []string{"schema.sql"})
defer cleanup()

ctx := context.Background()
uri := hosted.MySQL(t, []string{"schema.sql"})
sdb, err := sql.Open("mysql", uri)
if err != nil {
t.Fatal(err)
}
defer sdb.Close()

db := New(sdb)

// list all authors
Expand Down
11 changes: 7 additions & 4 deletions examples/authors/sqlc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ version: '2'
cloud:
project: "01HAQMMECEYQYKFJN8MP16QC41"
sql:
- schema: postgresql/schema.sql
- name: postgresql
schema: postgresql/schema.sql
queries: postgresql/query.sql
engine: postgresql
database:
Expand All @@ -17,19 +18,21 @@ sql:
package: authors
sql_package: pgx/v5
out: postgresql
- schema: mysql/schema.sql
- name: mysql
schema: mysql/schema.sql
queries: mysql/query.sql
engine: mysql
database:
uri: root:${MYSQL_ROOT_PASSWORD}@tcp(${MYSQL_HOST}:${MYSQL_PORT})/authors?multiStatements=true&parseTime=true
managed: true
rules:
- sqlc/db-prepare
# - mysql-query-too-costly
gen:
go:
package: authors
out: mysql
- schema: sqlite/schema.sql
- name: sqlite
schema: sqlite/schema.sql
queries: sqlite/query.sql
engine: sqlite
database:
Expand Down
15 changes: 11 additions & 4 deletions examples/booktest/mysql/db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,24 @@ package booktest

import (
"context"
"database/sql"
"testing"
"time"

"github.com/sqlc-dev/sqlc/internal/sqltest"
_ "github.com/go-sql-driver/mysql"

"github.com/sqlc-dev/sqlc/internal/sqltest/hosted"
)

func TestBooks(t *testing.T) {
db, cleanup := sqltest.MySQL(t, []string{"schema.sql"})
defer cleanup()

ctx := context.Background()
uri := hosted.MySQL(t, []string{"schema.sql"})
db, err := sql.Open("mysql", uri)
if err != nil {
t.Fatal(err)
}
defer db.Close()

dq := New(db)

// create an author
Expand Down
2 changes: 1 addition & 1 deletion examples/booktest/sqlc.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"queries": "mysql/query.sql",
"engine": "mysql",
"database": {
"uri": "root:${MYSQL_ROOT_PASSWORD}@tcp(${MYSQL_HOST}:${MYSQL_PORT})/booktest?multiStatements=true&parseTime=true"
"managed": true
},
"rules": [
"sqlc/db-prepare"
Expand Down
25 changes: 17 additions & 8 deletions examples/ondeck/mysql/db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import (
"strings"
"testing"

"github.com/sqlc-dev/sqlc/internal/sqltest"

_ "github.com/go-sql-driver/mysql"
"github.com/google/go-cmp/cmp"

"github.com/sqlc-dev/sqlc/internal/sqltest/hosted"
)

func join(vals ...string) sql.NullString {
Expand Down Expand Up @@ -143,10 +144,14 @@ func runOnDeckQueries(t *testing.T, q *Queries) {
func TestPrepared(t *testing.T) {
t.Parallel()

sdb, cleanup := sqltest.MySQL(t, []string{"schema"})
defer cleanup()
uri := hosted.MySQL(t, []string{"schema"})
db, err := sql.Open("mysql", uri)
if err != nil {
t.Fatal(err)
}
defer db.Close()

q, err := Prepare(context.Background(), sdb)
q, err := Prepare(context.Background(), db)
if err != nil {
t.Fatal(err)
}
Expand All @@ -157,8 +162,12 @@ func TestPrepared(t *testing.T) {
func TestQueries(t *testing.T) {
t.Parallel()

sdb, cleanup := sqltest.MySQL(t, []string{"schema"})
defer cleanup()
uri := hosted.MySQL(t, []string{"schema"})
db, err := sql.Open("mysql", uri)
if err != nil {
t.Fatal(err)
}
defer db.Close()

runOnDeckQueries(t, New(sdb))
runOnDeckQueries(t, New(db))
}
2 changes: 1 addition & 1 deletion examples/ondeck/sqlc.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"queries": "mysql/query",
"engine": "mysql",
"database": {
"uri": "root:${MYSQL_ROOT_PASSWORD}@tcp(${MYSQL_HOST}:${MYSQL_PORT})/ondeck?multiStatements=true&parseTime=true"
"managed": true
},
"rules": [
"sqlc/db-prepare"
Expand Down
20 changes: 14 additions & 6 deletions internal/cmd/vet.go
Original file line number Diff line number Diff line change
Expand Up @@ -404,10 +404,6 @@ func (c *checker) fetchDatabaseUri(ctx context.Context, s config.SQL) (string, f
return uri, cleanup, err
}

if s.Engine != config.EnginePostgreSQL {
return "", cleanup, fmt.Errorf("managed: only PostgreSQL currently")
}
Comment on lines -407 to -409
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might still want to bail early if the engine is sqlite?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to let the client make the request and fail so that it's easier to add engine support at the server without a client change.


if c.Client == nil {
// FIXME: Eventual race condition
client, err := quickdb.NewClientFromConfig(c.Conf.Cloud)
Expand All @@ -431,7 +427,7 @@ func (c *checker) fetchDatabaseUri(ctx context.Context, s config.SQL) (string, f
}

resp, err := c.Client.CreateEphemeralDatabase(ctx, &pb.CreateEphemeralDatabaseRequest{
Engine: "postgresql",
Engine: string(s.Engine),
Region: quickdb.GetClosestRegion(),
Migrations: ddl,
})
Expand All @@ -446,7 +442,19 @@ func (c *checker) fetchDatabaseUri(ctx context.Context, s config.SQL) (string, f
return err
}

return resp.Uri, cleanup, nil
var uri string
switch s.Engine {
case config.EngineMySQL:
dburi, err := quickdb.MySQLReformatURI(resp.Uri)
if err != nil {
return "", cleanup, fmt.Errorf("reformat uri: %w", err)
}
uri = dburi
default:
uri = resp.Uri
}

return uri, cleanup, nil
}

func (c *checker) DSN(dsn string) (string, error) {
Expand Down
5 changes: 0 additions & 5 deletions internal/endtoend/vet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,6 @@ func TestExamplesVet(t *testing.T) {
path := filepath.Join(examples, tc)

if tc != "kotlin" && tc != "python" {
if s, found := findSchema(t, filepath.Join(path, "mysql")); found {
db, cleanup := sqltest.CreateMySQLDatabase(t, tc, []string{s})
defer db.Close()
defer cleanup()
}
if s, found := findSchema(t, filepath.Join(path, "sqlite")); found {
dsn := fmt.Sprintf("file:%s?mode=memory&cache=shared", tc)
db, cleanup := sqltest.CreateSQLiteDatabase(t, dsn, []string{s})
Expand Down
16 changes: 16 additions & 0 deletions internal/quickdb/mysql.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package quickdb

import (
"fmt"
"net/url"
)

// The database URI returned by the QuickDB service isn't understood by the
// go-mysql-driver
func MySQLReformatURI(original string) (string, error) {
u, err := url.Parse(original)
if err != nil {
return "", err
}
return fmt.Sprintf("%s@tcp(%s)%s?multiStatements=true&parseTime=true&tls=true", u.User, u.Host, u.Path), nil
}
27 changes: 27 additions & 0 deletions internal/sqltest/hosted/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package hosted

import (
"fmt"
"os"
"sync"

"github.com/sqlc-dev/sqlc/internal/quickdb"
pb "github.com/sqlc-dev/sqlc/internal/quickdb/v1"
)

var client pb.QuickClient
var once sync.Once

func initClient() error {
projectID := os.Getenv("CI_SQLC_PROJECT_ID")
authToken := os.Getenv("CI_SQLC_AUTH_TOKEN")
if projectID == "" || authToken == "" {
return fmt.Errorf("missing project id or auth token")
}
c, err := quickdb.NewClient(projectID, authToken)
if err != nil {
return err
}
client = c
return nil
}
64 changes: 64 additions & 0 deletions internal/sqltest/hosted/mysql.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package hosted

import (
"context"
"os"
"testing"

"github.com/sqlc-dev/sqlc/internal/quickdb"
pb "github.com/sqlc-dev/sqlc/internal/quickdb/v1"
"github.com/sqlc-dev/sqlc/internal/sql/sqlpath"
)

func MySQL(t *testing.T, migrations []string) string {
ctx := context.Background()
t.Helper()

once.Do(func() {
if err := initClient(); err != nil {
t.Log(err)
}
})

if client == nil {
t.Skip("client init failed")
}

var seed []string
files, err := sqlpath.Glob(migrations)
if err != nil {
t.Fatal(err)
}
for _, f := range files {
blob, err := os.ReadFile(f)
if err != nil {
t.Fatal(err)
}
seed = append(seed, string(blob))
}

resp, err := client.CreateEphemeralDatabase(ctx, &pb.CreateEphemeralDatabaseRequest{
Engine: "mysql",
Region: quickdb.GetClosestRegion(),
Migrations: seed,
})
if err != nil {
t.Fatalf("region %s: %s", quickdb.GetClosestRegion(), err)
}

t.Cleanup(func() {
_, err = client.DropEphemeralDatabase(ctx, &pb.DropEphemeralDatabaseRequest{
DatabaseId: resp.DatabaseId,
})
if err != nil {
t.Fatal(err)
}
})

uri, err := quickdb.MySQLReformatURI(resp.Uri)
if err != nil {
t.Fatalf("uri error: %s", err)
}

return uri
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,14 @@ package hosted

import (
"context"
"fmt"
"os"
"sync"
"testing"

"github.com/sqlc-dev/sqlc/internal/quickdb"
pb "github.com/sqlc-dev/sqlc/internal/quickdb/v1"
"github.com/sqlc-dev/sqlc/internal/sql/sqlpath"
)

var client pb.QuickClient
var once sync.Once

func initClient() error {
projectID := os.Getenv("CI_SQLC_PROJECT_ID")
authToken := os.Getenv("CI_SQLC_AUTH_TOKEN")
if projectID == "" || authToken == "" {
return fmt.Errorf("missing project id or auth token")
}
c, err := quickdb.NewClient(projectID, authToken)
if err != nil {
return err
}
client = c
return nil
}

func PostgreSQL(t *testing.T, migrations []string) string {
ctx := context.Background()
t.Helper()
Expand Down
4 changes: 2 additions & 2 deletions internal/sqltest/mysql.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import (
"path/filepath"
"testing"

"github.com/sqlc-dev/sqlc/internal/sql/sqlpath"

_ "github.com/go-sql-driver/mysql"

"github.com/sqlc-dev/sqlc/internal/sql/sqlpath"
)

func MySQL(t *testing.T, migrations []string) (*sql.DB, func()) {
Expand Down