feat(04-01): generate jobs and admin controllers, reject model imports
Scaffold pact.Job and pact.AdminController stubs with Winter YAML assets, and fail summer build when models imports a sibling package. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
@@ -557,6 +558,169 @@ func TestScaffoldCoreArtifacts(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestScaffoldAllArtifacts(t *testing.T) {
|
||||
dir := copyHelloApp(t)
|
||||
ctx := t.Context()
|
||||
pluginDir, err := MakePlugin(ctx, dir, "golem15.demo")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pluginBefore, err := os.ReadFile(filepath.Join(pluginDir, "plugin.go"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := MakeModel(ctx, dir, "golem15.demo", "Album", false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := MakeMigration(ctx, dir, "golem15.demo", "AddAlbumIndex"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := MakeCommand(ctx, dir, "golem15.demo", "Purge"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
job, err := MakeJob(ctx, dir, "golem15.demo", "Reindex")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(job.Files) != 1 {
|
||||
t.Fatalf("make:job files = %v", job.Files)
|
||||
}
|
||||
jobSrc, err := os.ReadFile(job.Files[0])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, want := range []string{
|
||||
"func (ReindexArgs) Kind()",
|
||||
"func (reindexJob) Work(",
|
||||
"unexpected args type",
|
||||
} {
|
||||
if !bytes.Contains(jobSrc, []byte(want)) {
|
||||
t.Fatalf("job.go missing %s:\n%s", want, jobSrc)
|
||||
}
|
||||
}
|
||||
if bytes.Contains(bytes.ToLower(jobSrc), []byte("river")) {
|
||||
t.Fatal("job stub imports River")
|
||||
}
|
||||
|
||||
admin, err := MakeAdminController(ctx, dir, "golem15.demo", "Albums")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(admin.Files) != 3 {
|
||||
t.Fatalf("make:admin-controller files = %v", admin.Files)
|
||||
}
|
||||
adminSrc, err := os.ReadFile(filepath.Join(pluginDir, "controllers", "albums.go"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, want := range []string{
|
||||
`ID() string { return "golem15.demo.albums" }`,
|
||||
`ModelName() string { return "Albums" }`,
|
||||
`ConfigDir() string { return "controllers/albums" }`,
|
||||
} {
|
||||
if !bytes.Contains(adminSrc, []byte(want)) {
|
||||
t.Fatalf("albums.go missing %s:\n%s", want, adminSrc)
|
||||
}
|
||||
}
|
||||
for _, rel := range []string{
|
||||
filepath.Join("controllers", "albums", "fields.yaml"),
|
||||
filepath.Join("controllers", "albums", "columns.yaml"),
|
||||
} {
|
||||
body, err := os.ReadFile(filepath.Join(pluginDir, rel))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
key := "fields:"
|
||||
if strings.Contains(rel, "columns") {
|
||||
key = "columns:"
|
||||
}
|
||||
if !bytes.Contains(body, []byte(key)) {
|
||||
t.Fatalf("%s missing %s:\n%s", rel, key, body)
|
||||
}
|
||||
}
|
||||
|
||||
reg1, err := os.ReadFile(filepath.Join(pluginDir, "registry.gen.go"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, want := range []string{
|
||||
"&models.Album{}",
|
||||
"updates.CreateAlbums()",
|
||||
"updates.AddAlbumIndex()",
|
||||
"console.PurgeCommand()",
|
||||
"jobs.ReindexJob()",
|
||||
"controllers.AlbumsController()",
|
||||
} {
|
||||
if !bytes.Contains(reg1, []byte(want)) {
|
||||
t.Fatalf("registry.gen.go missing %s:\n%s", want, reg1)
|
||||
}
|
||||
}
|
||||
if _, err := MakeJob(ctx, dir, "golem15.demo", "Reindex"); err == nil {
|
||||
t.Fatal("duplicate make:job want error")
|
||||
}
|
||||
if err := refreshRegistry(pluginDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
reg2, err := os.ReadFile(filepath.Join(pluginDir, "registry.gen.go"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(reg1, reg2) {
|
||||
t.Fatal("repeated generation changed registry.gen.go")
|
||||
}
|
||||
pluginAfter, err := os.ReadFile(filepath.Join(pluginDir, "plugin.go"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(pluginBefore, pluginAfter) {
|
||||
t.Fatal("handwritten plugin.go was rewritten")
|
||||
}
|
||||
|
||||
if err := AddPlugin(ctx, dir, filepath.Join("plugins", "demo")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
if err := App(ctx, dir, &buf); err != nil {
|
||||
t.Fatalf("app build: %v\n%s", err, buf.String())
|
||||
}
|
||||
vet := execGo(t, pluginDir, "vet", "./...")
|
||||
if out, err := vet.CombinedOutput(); err != nil {
|
||||
t.Fatalf("plugin go vet: %v\n%s", err, out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestModelsLeaf(t *testing.T) {
|
||||
dir := copyHelloApp(t)
|
||||
ctx := t.Context()
|
||||
pluginDir, err := MakePlugin(ctx, dir, "golem15.demo")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := AddPlugin(ctx, dir, filepath.Join("plugins", "demo")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
modPath, err := readModulePath(filepath.Join(pluginDir, "go.mod"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
bad := "package models\n\nimport " + strconv.Quote(modPath+"/classes") + "\n"
|
||||
if err := os.WriteFile(filepath.Join(pluginDir, "models", "bad.go"), []byte(bad), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
err = App(ctx, dir, &buf)
|
||||
if err == nil {
|
||||
t.Fatal("want models leaf import error")
|
||||
}
|
||||
msg := err.Error()
|
||||
for _, want := range []string{"golem15.demo", "models/bad.go", modPath + "/classes"} {
|
||||
if !strings.Contains(msg, want) {
|
||||
t.Fatalf("leaf error %q missing %s", msg, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func assertScaffoldFiles(t *testing.T, pluginDir string) {
|
||||
t.Helper()
|
||||
assertWinterPluginShape(t, pluginDir)
|
||||
|
||||
Reference in New Issue
Block a user