dcbot/internal/adapter/bun_test.go

127 lines
2.8 KiB
Go

package adapter_test
import (
"context"
"database/sql"
"errors"
"os"
"strings"
"testing"
"time"
"unicode"
"gitea.dwysokinski.me/twhelp/dcbot/internal/adapter/internal/bunmodel"
"gitea.dwysokinski.me/twhelp/dcbot/internal/domain"
"github.com/cenkalti/backoff/v4"
"github.com/google/uuid"
"github.com/pressly/goose/v3"
"github.com/stretchr/testify/require"
"github.com/uptrace/bun"
"github.com/uptrace/bun/dbfixture"
"github.com/uptrace/bun/dialect/pgdialect"
"github.com/uptrace/bun/driver/pgdriver"
)
func newBunDB(tb testing.TB) *bun.DB {
tb.Helper()
schema := generateSchema()
sqldb := sql.OpenDB(
pgdriver.NewConnector(
pgdriver.WithDSN(os.Getenv(envDBDSN)),
pgdriver.WithConnParams(map[string]any{
"search_path": schema,
}),
),
)
bunDB := bun.NewDB(sqldb, pgdialect.New())
tb.Cleanup(func() {
_ = bunDB.Close()
})
require.NoError(tb, retry(bunDB.Ping), "couldn't ping DB")
_, err := bunDB.Exec("CREATE SCHEMA ?", bun.Safe(schema))
require.NoError(tb, err, "couldn't create schema")
runMigrations(tb, sqldb)
return bunDB
}
func runMigrations(tb testing.TB, db *sql.DB) {
tb.Helper()
require.NoError(tb, goose.Up(db, ""))
}
type bunfixture struct {
*dbfixture.Fixture
}
func loadFixtures(tb testing.TB, bunDB *bun.DB) *bunfixture {
tb.Helper()
// ensure that models are registered
bunDB.RegisterModel(&bunmodel.Group{}, &bunmodel.Monitor{})
fixture := dbfixture.New(bunDB)
err := fixture.Load(context.Background(), os.DirFS("testdata"), "fixture.yml")
require.NoError(tb, err, "couldn't load fixtures")
return &bunfixture{fixture}
}
func (f *bunfixture) group(tb testing.TB, id string) domain.GroupWithMonitors {
tb.Helper()
row, err := f.Row("Group." + id)
require.NoError(tb, err)
g, ok := row.(*bunmodel.Group)
require.True(tb, ok)
return g.ToDomain()
}
func (f *bunfixture) groups(tb testing.TB) []domain.GroupWithMonitors {
tb.Helper()
//nolint:lll
ids := []string{"group-1-server-1", "group-2-server-1", "group-1-server-2", "group-2-server-2", "group-3-server-1", "group-3-server-2"}
groups := make([]domain.GroupWithMonitors, 0, len(ids))
for _, id := range ids {
groups = append(groups, f.group(tb, id))
}
return groups
}
func (f *bunfixture) monitor(tb testing.TB, id string) domain.Monitor {
tb.Helper()
row, err := f.Row("Monitor." + id)
require.NoError(tb, err)
m, ok := row.(*bunmodel.Monitor)
require.True(tb, ok)
return m.ToDomain()
}
func generateSchema() string {
return strings.TrimFunc(strings.ReplaceAll(uuid.NewString(), "-", "_"), unicode.IsNumber)
}
func retry(op func() error) error {
bo := backoff.NewExponentialBackOff()
bo.MaxInterval = time.Second * 5
bo.MaxElapsedTime = 30 * time.Second
if err := backoff.Retry(op, bo); err != nil {
if bo.NextBackOff() == backoff.Stop {
return errors.New("reached retry deadline")
}
return err
}
return nil
}