Skip to content

Commit

Permalink
Merge pull request #1 from dogmatiq/mysql
Browse files Browse the repository at this point in the history
Add support for MySQL and MariaDB.
  • Loading branch information
jmalloc authored Dec 4, 2020
2 parents ab07f60 + 065c328 commit 91d4d6f
Show file tree
Hide file tree
Showing 12 changed files with 742 additions and 3 deletions.
40 changes: 40 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,47 @@ jobs:
uses: actions/checkout@v1
- name: Make
run: make ci
env:
DOGMATIQ_TEST_MYSQL_MYSQL_DSN: "root:rootpass@tcp(127.0.0.1:${{ job.services.mysql.ports['3306'] }})/dogmatiq"
DOGMATIQ_TEST_MARIADB_MYSQL_DSN: "root:rootpass@tcp(127.0.0.1:${{ job.services.mariadb.ports['3306'] }})/dogmatiq"
DOGMATIQ_TEST_POSTGRES_PGX_DSN: "database=dogmatiq user=postgres password=rootpass sslmode=disable port=${{ job.services.postgres.ports['5432'] }}"
- name: Upload Coverage Reports
if: success()
run: |
[[ -z "${{ secrets.CODECOV_TOKEN }}" ]] || bash <(curl -s https://codecov.io/bash) -t "${{ secrets.CODECOV_TOKEN }}" -B "${{ github.ref }}"
services:
mariadb:
image: mysql:8
options: >-
--mount type=tmpfs,destination=/var/lib/mysql
--health-cmd="mysqladmin ping --host 127.0.0.1 --port 3306 --user root --password=rootpass"
--health-interval 2s
--health-timeout 10s
--health-retries 10
ports:
- 3306/tcp
env:
MYSQL_ROOT_PASSWORD: rootpass
mariadb:
image: mariadb:10
options: >-
--mount type=tmpfs,destination=/var/lib/mysql
--health-cmd="mysqladmin ping --host 127.0.0.1 --port 3306 --user root --password=rootpass"
--health-interval 2s
--health-timeout 10s
--health-retries 10
ports:
- 3306/tcp
env:
MYSQL_ROOT_PASSWORD: rootpass
postgres:
image: postgres:13
options: >-
--health-cmd pg_isready
--health-interval 2s
--health-timeout 10s
--health-retries 10
env:
POSTGRES_PASSWORD: rootpass
ports:
- 5432/tcp
34 changes: 31 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,38 @@
# sqltest
# SQL Testing Utilities

[![Build Status](https://github.com/dogmatiq/sqltest/workflows/CI/badge.svg)](https://github.com/dogmatiq/sqltest/actions?workflow=CI)
[![Code Coverage](https://img.shields.io/codecov/c/github/dogmatiq/sqltest/main.svg)](https://codecov.io/github/dogmatiq/sqltest)
[![Latest Version](https://img.shields.io/github/tag/dogmatiq/sqltest.svg?label=semver)](https://semver.org)
[![Documentation](https://img.shields.io/badge/go.dev-reference-007d9c)](https://pkg.go.dev/github.com/dogmatiq/sqltest)
[![Go Report Card](https://goreportcard.com/badge/github.com/dogmatiq/sqltest)](https://goreportcard.com/report/github.com/dogmatiq/sqltest)

This repository contains utilities for testing Dogma projects that use SQL
databases.
This is a Go library containing utilities that help when writing tests that use
real SQL database servers.

It is only intended for use as a test dependencies for projects within the
Dogmatiq organization.

The primary feature is the `OpenTemporary()` function which creates a temporary
database that can be discarded at the end of each test.

## Database Products

The database products in the table below are currently supported. Some products
are supported via multiple different Go SQL drivers.

Each of these databases can be started using the provided [Docker stack](docker-stack.yml),
and/or started within each project's Github Actions workflow. This project's
[CI workflow](.github/workflows.ci.yml) serves as an example of how to start
each product under Github Actions.

Product | Supported Drivers | Notes
------------|-------------------------------|-----------------------------------
MySQL | [mysql] |
MariaDB | [mysql] |
PostgreSQL | [pgx] (preferred), [postgres] |
SQLite | [sqlite3] | Embedded database, requires CGO

[mysql]: https://github.com/go-sql-driver/mysql
[pgx]: https://github.com/jackc/pgx
[postgres]: https://github.com/lib/pq
[sqlite3]: https://github.com/mattn/go-sqlite3
34 changes: 34 additions & 0 deletions docker-stack.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
version: "3.8"

services:
mysql:
image: mysql:8
environment:
MYSQL_ROOT_PASSWORD: rootpass
ports:
- "23306:3306/tcp"
volumes:
- mysql:/var/lib/mysql

mariadb:
image: mariadb:10
environment:
MYSQL_ROOT_PASSWORD: rootpass
ports:
- "23307:3307/tcp"
volumes:
- mariadb:/var/lib/mysql

postgres:
image: postgres:13-alpine
environment:
POSTGRES_PASSWORD: rootpass
ports:
- "25432:5432/tcp"
volumes:
- postgres:/var/lib/postgresql/data

volumes:
mysql:
mariadb:
postgres:
40 changes: 40 additions & 0 deletions driver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package sqltest

import (
_ "github.com/go-sql-driver/mysql" // ensure all drivers are imported
_ "github.com/jackc/pgx/v4/stdlib" // ensure all drivers are imported
_ "github.com/lib/pq" // ensure all drivers are imported
_ "github.com/mattn/go-sqlite3" // ensure all drivers are imported
)

// Driver is an interface for using a specific SQL driver with multiple database
// products.
type Driver interface {
// Name returns the name of the driver, as passed to sql.Open().
Name() string

// DatabaseNameFromDSN returns the database name in the given DSN.
DatabaseNameFromDSN(dsn string) (string, error)

// DSNForSchemaManipulation returns a DSN that can be used to connect to a
// database in order to create and drop other databases.
DSNForSchemaManipulation(templateDSN string) (string, error)

// DSNForTesting returns a DSN that connects to a specific database for
// running tests.
DSNForTesting(templateDSN, database string) (string, error)
}

var (
// MySQLDriver is the "mysql" driver (https://github.com/go-sql-driver/mysql).
MySQLDriver Driver = mysqlDriver{}

// // PGXDriver is the "pgx" driver (https://github.com/jackc/pgx).
// PGXDriver Driver = pgxDriver{}

// // PostgresDriver is "postgres" (https://github.com/lib/pq).
// PostgresDriver Driver = postgresDriver{}

// // SQLite3Driver is the "sqlite3" driver (https://github.com/mattn/go-sqlite3).
// SQLite3Driver Driver = sqlite3Driver{}
)
47 changes: 47 additions & 0 deletions drivermysql.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package sqltest

import (
"github.com/go-sql-driver/mysql"
)

type mysqlDriver struct{}

func (mysqlDriver) Name() string {
return "mysql"
}

func (mysqlDriver) DatabaseNameFromDSN(dsn string) (string, error) {
cfg, err := mysql.ParseDSN(dsn)
if err != nil {
return "", err
}

return cfg.DBName, nil
}

func (mysqlDriver) DSNForSchemaManipulation(templateDSN string) (string, error) {
// Mangle the database name in the parsed DSN so that we can connect to the
// server using the "mysql" database.
//
// This is necessary simply because the Go MySQL driver can not connect
// without choosing a particular database, and the "mysql" database is
// guaranteed to exist.
cfg, err := mysql.ParseDSN(templateDSN)
if err != nil {
return "", err
}
cfg.DBName = "mysql"

return cfg.FormatDSN(), nil
}

func (mysqlDriver) DSNForTesting(templateDSN, database string) (string, error) {
cfg, err := mysql.ParseDSN(templateDSN)
if err != nil {
return "", err
}

cfg.DBName = database

return cfg.FormatDSN(), nil
}
15 changes: 15 additions & 0 deletions ginkgo_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package sqltest_test

import (
"reflect"
"testing"

"github.com/onsi/ginkgo"
"github.com/onsi/gomega"
)

func TestSuite(t *testing.T) {
type tag struct{}
gomega.RegisterFailHandler(ginkgo.Fail)
ginkgo.RunSpecs(t, reflect.TypeOf(tag{}).PkgPath())
}
10 changes: 10 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
module github.com/dogmatiq/sqltest

go 1.15

require (
github.com/go-sql-driver/mysql v1.5.0
github.com/jackc/pgx/v4 v4.10.0
github.com/lib/pq v1.3.0
github.com/mattn/go-sqlite3 v1.14.5
github.com/onsi/ginkgo v1.14.2
github.com/onsi/gomega v1.10.3
go.uber.org/multierr v1.5.0
)
Loading

0 comments on commit 91d4d6f

Please sign in to comment.