feat(migrate): add lifecycle commands and standalone authoring
This commit is contained in:
1 parent
3cd3f49c11
commit
2727ac83db
12 files changed
+1553
-31
No files matched your search
@@ -0,0 +1,123 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGeneratedConsumerAndArtifactBoundary(t *testing.T) {
|
||||
root, err := filepath.Abs("../..")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dir, err := filepath.EvalSymlinks(t.TempDir())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
execute := func(cwd, name string, args ...string) []byte {
|
||||
t.Helper()
|
||||
cmd := exec.CommandContext(t.Context(), name, args...)
|
||||
cmd.Dir = cwd
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("%s %v: %v\n%s", name, args, err, out)
|
||||
}
|
||||
return out
|
||||
}
|
||||
tool := filepath.Join(dir, "corestack-goose")
|
||||
execute(root, "go", "build", "-o", tool, "./cmd/corestack-goose")
|
||||
migrations := filepath.Join(dir, "migrations")
|
||||
if err := os.Mkdir(migrations, 0o700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
osName := "windows"
|
||||
if runtime.GOOS == "windows" {
|
||||
osName = "linux"
|
||||
}
|
||||
for _, tc := range []struct{ name, kind string }{{"initial", "sql"}, {"test", "go"}, {"create_test", "go"}, {osName, "go"}} {
|
||||
execute(dir, tool, "create", "--dir", migrations, tc.name, tc.kind)
|
||||
execute(dir, tool, "fix", "--dir", migrations)
|
||||
}
|
||||
execute(dir, tool, "fix", "--dir", migrations)
|
||||
source, err := os.ReadFile("testdata/consumer/main.go")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(dir, "main.go"), source, 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
module := fmt.Sprintf("module example.com/consumer\n\ngo 1.27.1\n\nrequire go.auvem.com/corestack v0.0.0\nreplace go.auvem.com/corestack => %s\n", filepath.ToSlash(root))
|
||||
if err := os.WriteFile(filepath.Join(dir, "go.mod"), []byte(module), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
binary := filepath.Join(dir, "consumer")
|
||||
execute(dir, "go", "build", "-mod=mod", "-o", binary, ".")
|
||||
out := execute(dir, binary, filepath.Join(dir, "consumer.db"))
|
||||
if !strings.Contains(string(out), "version=4 pending=false versions=1,2,3,4 fresh=true isolated-pending=true") {
|
||||
t.Fatal(string(out))
|
||||
}
|
||||
// Decode package identities rather than guessing from substring matches in go list.
|
||||
deps := execute(dir, "go", "list", "-deps", "-json", ".")
|
||||
decoder := json.NewDecoder(bytes.NewReader(deps))
|
||||
adapterFound := false
|
||||
for decoder.More() {
|
||||
var dep struct{ ImportPath string }
|
||||
if err := decoder.Decode(&dep); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if dep.ImportPath == "go.auvem.com/corestack/migrate/lifecycle" {
|
||||
adapterFound = true
|
||||
}
|
||||
if dep.ImportPath == "go.auvem.com/corestack/cmd/corestack-goose" || strings.HasPrefix(dep.ImportPath, "go.auvem.com/corestack/cmd/corestack-goose/") {
|
||||
t.Fatalf("production imports authoring: %s", dep.ImportPath)
|
||||
}
|
||||
}
|
||||
if !adapterFound {
|
||||
t.Fatal("production fixture did not import runtime adapter")
|
||||
}
|
||||
toolSymbols := execute(dir, "go", "tool", "nm", tool)
|
||||
toolEntries := map[string]bool{}
|
||||
for _, line := range strings.Split(string(toolSymbols), "\n") {
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) >= 3 {
|
||||
toolEntries[fields[len(fields)-1]] = true
|
||||
}
|
||||
}
|
||||
for _, entry := range []string{"github.com/pressly/goose/v3.CreateWithTemplate", "go.auvem.com/corestack/cmd/corestack-goose/internal/authoring.Create", "go.auvem.com/corestack/cmd/corestack-goose/internal/authoring.Fix"} {
|
||||
if !toolEntries[entry] {
|
||||
t.Fatalf("standalone authoring entrypoint missing: %s", entry)
|
||||
}
|
||||
}
|
||||
runtimeFound := false
|
||||
symbols := execute(dir, "go", "tool", "nm", binary)
|
||||
for _, line := range strings.Split(string(symbols), "\n") {
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) < 3 {
|
||||
continue
|
||||
}
|
||||
symbol := fields[len(fields)-1]
|
||||
if symbol == "go.auvem.com/corestack/migrate/lifecycle.Commands" {
|
||||
runtimeFound = true
|
||||
}
|
||||
if strings.HasPrefix(symbol, "go.auvem.com/corestack/cmd/corestack-goose/") {
|
||||
t.Fatalf("authoring symbol linked: %s", symbol)
|
||||
}
|
||||
for _, entry := range []string{"Create", "CreateWithTemplate", "Fix", "SetSequential"} {
|
||||
full := "github.com/pressly/goose/v3." + entry
|
||||
if symbol == full || strings.HasPrefix(symbol, full+".") {
|
||||
t.Fatalf("upstream authoring entrypoint linked: %s", symbol)
|
||||
}
|
||||
}
|
||||
}
|
||||
if !runtimeFound {
|
||||
t.Fatal("runtime command symbol missing from production executable")
|
||||
}
|
||||
t.Log("standalone create/fix; unchanged generated SQL+safe-suffix Go compiled and applied; runtime dependency identities and linker symbols verified")
|
||||
}
|
||||
Reference in new issue
Block a user