💬
ent+dockertest
ent+dockertest
PostgreSQLで、dockertestを実装します。
dockertestは、テストを実行するとコンテナが立ち上がり、終了すると削除されます。
Sample
server_test.go
package dockertestpsql_test
import (
"database/sql"
"example/ent"
"fmt"
"os"
"strings"
"testing"
"time"
_ "github.com/lib/pq"
"github.com/ory/dockertest/v3"
"github.com/ory/dockertest/v3/docker"
log "github.com/sirupsen/logrus"
)
var (
db *sql.DB
client *ent.Client
)
func TestMain(m *testing.M) {
// uses a sensible default on windows (tcp/http) and linux/osx (socket)
pool, err := dockertest.NewPool("")
if err != nil {
log.Fatalf("Could not construct pool: %s", err)
}
err = pool.Client.Ping()
if err != nil {
log.Fatalf("Could not connect to Docker: %s", err)
}
// pulls an image, creates a container based on it and runs it
resource, err := pool.RunWithOptions(&dockertest.RunOptions{
Repository: "postgres",
Tag: "15",
Env: []string{
"POSTGRES_PASSWORD=postgres",
"POSTGRES_USER=postgres",
"POSTGRES_DB=postgres",
"listen_addresses = '*'",
},
}, func(config *docker.HostConfig) {
// set AutoRemove to true so that stopped container goes away by itself
config.AutoRemove = true
config.RestartPolicy = docker.RestartPolicy{Name: "no"}
})
if err != nil {
log.Fatalf("Could not start resource: %s", err)
}
hostAndPort := resource.GetHostPort("5432/tcp")
databaseUrl := fmt.Sprintf("postgres://postgres:postgres@%s/postgres?sslmode=disable", hostAndPort)
parts := strings.Split(hostAndPort, ":")
host := parts[0]
port := parts[1]
entUrl := fmt.Sprintf("host=%s port=%s user=postgres dbname=postgres password=postgres sslmode=disable", host, port)
log.Println("Connecting to database on url: ", databaseUrl)
resource.Expire(120) // Tell docker to hard kill the container in 120 seconds
// exponential backoff-retry, because the application in the container might not be ready to accept connections yet
pool.MaxWait = 120 * time.Second
if err = pool.Retry(func() error {
db, err = sql.Open("postgres", databaseUrl)
if err != nil {
return err
}
return db.Ping()
}); err != nil {
log.Fatalf("Could not connect to docker: %s", err)
}
client, err = ent.Open("postgres", entUrl)
if err != nil {
log.Fatalf("failed opening connection to postgres: %v", err)
}
defer client.Close()
//Run tests
code := m.Run()
// You can't defer this because os.Exit doesn't care for defer
if err := pool.Purge(resource); err != nil {
log.Fatalf("Could not purge resource: %s", err)
}
os.Exit(code)
}
func TestRealbob(t *testing.T) {
// all tests
}
TestMainは、テストの実行のセットアップをします。
CloudBuildで自動テスト
いくつか修正します。
server_test.go
package dockertestpsql_test
import (
"database/sql"
"example/ent"
"fmt"
"os"
"strings"
"testing"
"time"
_ "github.com/lib/pq"
"github.com/ory/dockertest/v3"
"github.com/ory/dockertest/v3/docker"
log "github.com/sirupsen/logrus"
)
var (
db *sql.DB
client *ent.Client
)
func TestMain(m *testing.M) {
// uses a sensible default on windows (tcp/http) and linux/osx (socket)
pool, err := dockertest.NewPool("")
if err != nil {
log.Fatalf("Could not construct pool: %s", err)
}
err = pool.Client.Ping()
if err != nil {
log.Fatalf("Could not connect to Docker: %s", err)
}
+ list, _ := pool.NetworksByName("cloudbuild")
// pulls an image, creates a container based on it and runs it
resource, err := pool.RunWithOptions(&dockertest.RunOptions{
Repository: "postgres",
Tag: "15",
Env: []string{
"POSTGRES_PASSWORD=postgres",
"POSTGRES_USER=postgres",
"POSTGRES_DB=postgres",
"listen_addresses = '*'",
},
+ Networks: []*dockertest.Network{&list[0]},
}, func(config *docker.HostConfig) {
// set AutoRemove to true so that stopped container goes away by itself
config.AutoRemove = true
config.RestartPolicy = docker.RestartPolicy{Name: "no"}
})
if err != nil {
log.Fatalf("Could not start resource: %s", err)
}
- hostAndPort := resource.GetHostPort("5432/tcp")
+ hostAndPort := getPort(resource, "5432")
databaseUrl := fmt.Sprintf("postgres://postgres:postgres@%s/postgres?sslmode=disable", hostAndPort)
parts := strings.Split(hostAndPort, ":")
host := parts[0]
port := parts[1]
entUrl := fmt.Sprintf("host=%s port=%s user=postgres dbname=postgres password=postgres sslmode=disable", host, port)
log.Println("Connecting to database on url: ", databaseUrl)
resource.Expire(120) // Tell docker to hard kill the container in 120 seconds
// exponential backoff-retry, because the application in the container might not be ready to accept connections yet
pool.MaxWait = 120 * time.Second
if err = pool.Retry(func() error {
db, err = sql.Open("postgres", databaseUrl)
if err != nil {
return err
}
return db.Ping()
}); err != nil {
log.Fatalf("Could not connect to docker: %s", err)
}
client, err = ent.Open("postgres", entUrl)
if err != nil {
log.Fatalf("failed opening connection to postgres: %v", err)
}
defer client.Close()
//Run tests
code := m.Run()
// You can't defer this because os.Exit doesn't care for defer
if err := pool.Purge(resource); err != nil {
log.Fatalf("Could not purge resource: %s", err)
}
os.Exit(code)
}
+ func getPort(r *dockertest.Resource, port string) string {
+ n := r.Container.NetworkSettings.Networks["cloudbuild"]
+ return net.JoinHostPort(n.IPAddress, port)
+ }
func TestRealbob(t *testing.T) {
// all tests
}
cloudbuild.yamlに以下のコマンドを追加します。
cloudbuild.yaml
+ steps:
+ # Run tests and save to file
+ - name: golang:1.20
+ entrypoint: /bin/bash
+ args:
+ - -c
+ - |
+ go install github.com/jstemmer/go-junit-report/v2@latest
+ 2>&1 go test -timeout 1m -v ./path/to/testdirectry... | /go/bin/go-junit-report -set-exit-code -iocopy -out ${SHORT_SHA}_test_log.xml
+ # 並列実行
+ waitFor: ['-']
+ options:
+ # 高性能CPU
+ machineType: 'E2_HIGHCPU_32'
Discussion