codegen: test fixture factories now use randomness to generate unique column values
All checks were successful
CI / build-docker (push) Successful in 2s
CI / build-docker-bootstrap (push) Has been skipped
CI / release-test (push) Successful in 10s

This commit is contained in:
2026-09-19 21:36:31 -07:00
parent 1592c7d1fc
commit f98f8416e8

View File

@@ -101,6 +101,22 @@ func GenerateModelTestAST(tbl pkgschema.Table, schema pkgschema.Schema, gomodNam
hasCreatedAt, hasUpdatedAt := tbl.HasAutoTimestamps() hasCreatedAt, hasUpdatedAt := tbl.HasAutoTimestamps()
updateTestFields := UpdateTestFields(tbl) updateTestFields := UpdateTestFields(tbl)
uniqueColumns := map[string]bool{}
for _, index := range schema.Indexes {
if index.TableName != tbl.TableName || !index.IsUnique {
continue
}
for _, columnName := range index.Columns {
uniqueColumns[columnName] = true
}
}
hasRandomUniqueField := false
for _, c := range updateTestFields {
if uniqueColumns[c.Name] {
hasRandomUniqueField = true
break
}
}
requiredForeignKeys := []pkgschema.Column{} requiredForeignKeys := []pkgschema.Column{}
for _, c := range tbl.Columns { for _, c := range tbl.Columns {
// Only ordinary object foreign keys use a distinct TargetObjectID Go type; // Only ordinary object foreign keys use a distinct TargetObjectID Go type;
@@ -141,31 +157,71 @@ func GenerateModelTestAST(tbl pkgschema.Table, schema pkgschema.Schema, gomodNam
}, },
}, },
Body: &ast.BlockStmt{ Body: &ast.BlockStmt{
List: []ast.Stmt{ List: append(
&ast.ReturnStmt{ func() []ast.Stmt {
Results: []ast.Expr{ if !hasRandomUniqueField {
&ast.CompositeLit{ return nil
Type: ast.NewIdent(tbl.GoTypeName), }
Elts: func() (ret []ast.Expr) { return []ast.Stmt{&ast.AssignStmt{
// `UpdateTestFields()` skips foreign keys, so this will not cause duplicates Lhs: []ast.Expr{ast.NewIdent("id")},
for i, c := range requiredForeignKeys { Tok: token.DEFINE,
ret = append(ret, &ast.KeyValueExpr{ Rhs: []ast.Expr{&ast.CallExpr{Fun: &ast.SelectorExpr{X: ast.NewIdent("rand"), Sel: ast.NewIdent("Int")}}},
Key: ast.NewIdent(c.GoFieldName()), }}
Value: ast.NewIdent(requiredForeignKeyParamNames[i]), }(),
}) []ast.Stmt{
} &ast.ReturnStmt{
for _, c := range updateTestFields { Results: []ast.Expr{
ret = append(ret, &ast.KeyValueExpr{ &ast.CompositeLit{
Key: ast.NewIdent(c.GoFieldName()), Type: ast.NewIdent(tbl.GoTypeName),
Value: SampleValue(c, 0), Elts: func() (ret []ast.Expr) {
}) // `UpdateTestFields()` skips foreign keys, so this will not cause duplicates
} for i, c := range requiredForeignKeys {
return ret = append(ret, &ast.KeyValueExpr{
}(), Key: ast.NewIdent(c.GoFieldName()),
Value: ast.NewIdent(requiredForeignKeyParamNames[i]),
})
}
for _, c := range updateTestFields {
value := SampleValue(c, 0)
if uniqueColumns[c.Name] {
switch c.Type {
case "integer", "int":
value = ast.NewIdent("id")
case "text":
value = &ast.CallExpr{
Fun: &ast.SelectorExpr{X: ast.NewIdent("fmt"), Sel: ast.NewIdent("Sprintf")},
Args: []ast.Expr{
&ast.BasicLit{Kind: token.STRING, Value: `"%s-%d"`},
SampleValue(c, 0),
ast.NewIdent("id"),
},
}
case "blob":
value = &ast.CallExpr{
Fun: &ast.ArrayType{Elt: ast.NewIdent("byte")},
Args: []ast.Expr{&ast.CallExpr{
Fun: &ast.SelectorExpr{X: ast.NewIdent("fmt"), Sel: ast.NewIdent("Sprintf")},
Args: []ast.Expr{
&ast.BasicLit{Kind: token.STRING, Value: `"%s-%d"`},
&ast.CallExpr{Fun: ast.NewIdent("string"), Args: []ast.Expr{SampleValue(c, 0)}},
ast.NewIdent("id"),
},
}},
}
}
}
ret = append(ret, &ast.KeyValueExpr{
Key: ast.NewIdent(c.GoFieldName()),
Value: value,
})
}
return
}(),
},
}, },
}, },
}, }...,
}, ),
}, },
} }
@@ -595,23 +651,33 @@ func GenerateModelTestAST(tbl pkgschema.Table, schema pkgschema.Schema, gomodNam
Decls: append([]ast.Decl{ Decls: append([]ast.Decl{
&ast.GenDecl{ &ast.GenDecl{
Tok: token.IMPORT, Tok: token.IMPORT,
Specs: []ast.Spec{ Specs: func() []ast.Spec {
&ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"testing"`}}, specs := []ast.Spec{}
&ast.ImportSpec{ if hasRandomUniqueField {
Path: &ast.BasicLit{Kind: token.STRING, Value: `"git.offline-twitter.com/offline-labs/gas-stack/pkg/db"`}, specs = append(specs,
Name: ast.NewIdent("."), &ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"fmt"`}},
}, &ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"math/rand"`}},
&ast.ImportSpec{ )
Path: &ast.BasicLit{Kind: token.STRING, Value: `"git.offline-twitter.com/offline-labs/gas-stack/pkg/must"`}, }
}, specs = append(specs, []ast.Spec{
&ast.ImportSpec{ &ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"testing"`}},
Path: &ast.BasicLit{Kind: token.STRING, Value: fmt.Sprintf(`"%s/pkg/%s"`, gomodName, packageName)}, &ast.ImportSpec{
Name: ast.NewIdent("."), Path: &ast.BasicLit{Kind: token.STRING, Value: `"git.offline-twitter.com/offline-labs/gas-stack/pkg/db"`},
}, Name: ast.NewIdent("."),
&ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"github.com/go-test/deep"`}}, },
&ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"github.com/stretchr/testify/assert"`}}, &ast.ImportSpec{
&ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"github.com/stretchr/testify/require"`}}, Path: &ast.BasicLit{Kind: token.STRING, Value: `"git.offline-twitter.com/offline-labs/gas-stack/pkg/must"`},
}, },
&ast.ImportSpec{
Path: &ast.BasicLit{Kind: token.STRING, Value: fmt.Sprintf(`"%s/pkg/%s"`, gomodName, packageName)},
Name: ast.NewIdent("."),
},
&ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"github.com/go-test/deep"`}},
&ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"github.com/stretchr/testify/assert"`}},
&ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"github.com/stretchr/testify/require"`}},
}...)
return specs
}(),
}, },
}, testList...), }, testList...),
} }