Files
tasks/common/persistence/sql/test_sql_persistence.go
zeekay b695fbbfb2 feat: native multi-arch CI build + embedded SQLite deployment
- GitHub Actions: parallel amd64 + arm64 on self-hosted runners
  (lqd-build-amd64/arm64), multi-arch manifest, push to GAR
- Dockerfile: CGO-enabled Go build with sqlite support
- embedded-sqlite.yaml: file-based WAL persistence at /data/
- Build tags on test utility files to fix production builds
- Removed luxfi/zap local replace, using published v0.2.1
2026-04-17 11:22:28 -07:00

209 lines
5.4 KiB
Go

//go:build ignore
package sql
import (
"fmt"
"os"
"path"
"strings"
"time"
"github.com/hanzoai/tasks/common/backoff"
"github.com/hanzoai/tasks/common/config"
"github.com/hanzoai/tasks/common/dynamicconfig"
"github.com/hanzoai/tasks/common/log"
"github.com/hanzoai/tasks/common/log/tag"
"github.com/hanzoai/tasks/common/metrics"
p "github.com/hanzoai/tasks/common/persistence"
"github.com/hanzoai/tasks/common/persistence/sql/sqlplugin"
"github.com/hanzoai/tasks/common/primitives"
"github.com/hanzoai/tasks/common/resolver"
"github.com/hanzoai/tasks/tests/testutils"
)
// TestCluster allows executing cassandra operations in testing.
type TestCluster struct {
dbName string
schemaDir string
cfg config.SQL
faultInjection *config.FaultInjection
logger log.Logger
}
// NewTestCluster returns a new SQL test cluster
func NewTestCluster(
pluginName string,
dbName string,
username string,
password string,
host string,
port int,
connectAttributes map[string]string,
schemaDir string,
faultInjection *config.FaultInjection,
logger log.Logger,
) *TestCluster {
var result TestCluster
result.logger = logger
result.dbName = dbName
result.schemaDir = schemaDir
result.cfg = config.SQL{
User: username,
Password: password,
ConnectAddr: fmt.Sprintf("%v:%v", host, port),
ConnectProtocol: "tcp",
PluginName: pluginName,
DatabaseName: dbName,
TaskScanPartitions: 4,
ConnectAttributes: connectAttributes,
}
result.faultInjection = faultInjection
return &result
}
// DatabaseName from PersistenceTestCluster interface
func (s *TestCluster) DatabaseName() string {
return s.dbName
}
// SetupTestDatabase from PersistenceTestCluster interface
func (s *TestCluster) SetupTestDatabase() {
s.CreateDatabase()
if s.schemaDir == "" {
s.logger.Info("No schema directory provided, skipping schema setup")
return
}
schemaDir := s.schemaDir + "/"
if !strings.HasPrefix(schemaDir, "/") && !strings.HasPrefix(schemaDir, "../") {
temporalPackageDir := testutils.GetRepoRootDirectory()
schemaDir = path.Join(temporalPackageDir, schemaDir)
}
s.LoadSchema(path.Join(schemaDir, "temporal", "schema.sql"))
s.LoadSchema(path.Join(schemaDir, "visibility", "schema.sql"))
}
// Config returns the persistence config for connecting to this test cluster
func (s *TestCluster) Config() config.Persistence {
cfg := s.cfg
return config.Persistence{
DefaultStore: "test",
VisibilityStore: "test",
DataStores: map[string]config.DataStore{
"test": {SQL: &cfg, FaultInjection: s.faultInjection},
},
TransactionSizeLimit: dynamicconfig.GetIntPropertyFn(primitives.DefaultTransactionSizeLimit),
}
}
// TearDownTestDatabase from PersistenceTestCluster interface
func (s *TestCluster) TearDownTestDatabase() {
s.DropDatabase()
}
// CreateDatabase from PersistenceTestCluster interface
func (s *TestCluster) CreateDatabase() {
cfg2 := s.cfg
// NOTE need to connect with empty name to create new database
if cfg2.PluginName != "sqlite" {
cfg2.DatabaseName = ""
}
var db sqlplugin.AdminDB
var err error
err = backoff.ThrottleRetry(
func() error {
db, err = NewSQLAdminDB(sqlplugin.DbKindUnknown, &cfg2, resolver.NewNoopResolver(), log.NewTestLogger(), metrics.NoopMetricsHandler)
return err
},
backoff.NewExponentialRetryPolicy(time.Second).WithExpirationInterval(time.Minute),
nil,
)
if err != nil {
panic(err)
}
defer func() {
err := db.Close()
if err != nil {
panic(err)
}
}()
err = db.CreateDatabase(s.cfg.DatabaseName)
if err != nil {
panic(err)
}
s.logger.Info("created database", tag.String("database", s.cfg.DatabaseName))
}
// DropDatabase from PersistenceTestCluster interface
func (s *TestCluster) DropDatabase() {
cfg2 := s.cfg
if cfg2.PluginName == "sqlite" && cfg2.DatabaseName != ":memory:" && cfg2.ConnectAttributes["mode"] != "memory" {
if len(cfg2.DatabaseName) > 3 { // 3 should mean not ., .., empty, or /
// Remove main database file
_ = os.Remove(cfg2.DatabaseName)
// Remove WAL mode files (may not exist if WAL wasn't used)
_ = os.Remove(cfg2.DatabaseName + "-wal")
_ = os.Remove(cfg2.DatabaseName + "-shm")
}
return
}
// NOTE need to connect with empty name to drop the database
cfg2.DatabaseName = ""
db, err := NewSQLAdminDB(sqlplugin.DbKindUnknown, &cfg2, resolver.NewNoopResolver(), log.NewTestLogger(), metrics.NoopMetricsHandler)
if err != nil {
panic(err)
}
defer func() {
err := db.Close()
if err != nil {
panic(err)
}
}()
err = db.DropDatabase(s.cfg.DatabaseName)
if err != nil {
panic(err)
}
s.logger.Info("dropped database", tag.String("database", s.cfg.DatabaseName))
}
// LoadSchema from PersistenceTestCluster interface
func (s *TestCluster) LoadSchema(schemaFile string) {
statements, err := p.LoadAndSplitQuery([]string{schemaFile})
if err != nil {
s.logger.Fatal("LoadSchema", tag.Error(err))
}
var db sqlplugin.AdminDB
err = backoff.ThrottleRetry(
func() error {
db, err = NewSQLAdminDB(sqlplugin.DbKindUnknown, &s.cfg, resolver.NewNoopResolver(), log.NewTestLogger(), metrics.NoopMetricsHandler)
return err
},
backoff.NewExponentialRetryPolicy(time.Second).WithExpirationInterval(time.Minute),
nil,
)
if err != nil {
panic(err)
}
defer func() {
err := db.Close()
if err != nil {
panic(err)
}
}()
for _, stmt := range statements {
if err = db.Exec(stmt); err != nil {
s.logger.Fatal("LoadSchema", tag.Error(err))
}
}
s.logger.Info("loaded schema")
}