177 lines
6.2 KiB
Go
177 lines
6.2 KiB
Go
package scaffold
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"runtime/debug"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestGenerateCreatesServiceLayout(t *testing.T) {
|
|
directory := t.TempDir()
|
|
project := filepath.Join(directory, "billing")
|
|
if err := Generate(Options{Dir: project, Module: "example.com/billing", FrameworkDir: frameworkRoot(t)}); err != nil {
|
|
t.Fatalf("generate project: %v", err)
|
|
}
|
|
for _, path := range []string{
|
|
"go.mod",
|
|
"cmd/server/main.go",
|
|
"internal/model/user.go",
|
|
"internal/repository/memory.go",
|
|
"internal/servicecontext/context.go",
|
|
"internal/service/user.go",
|
|
"internal/handler/user.go",
|
|
} {
|
|
if _, err := os.Stat(filepath.Join(project, filepath.FromSlash(path))); err != nil {
|
|
t.Fatalf("expected generated file %s: %v", path, err)
|
|
}
|
|
}
|
|
content, err := os.ReadFile(filepath.Join(project, "go.mod"))
|
|
if err != nil {
|
|
t.Fatalf("read generated go.mod: %v", err)
|
|
}
|
|
if !strings.Contains(string(content), "replace git.yuntuo.hk/k2safe/go-omni =>") {
|
|
t.Fatalf("expected local framework replace directive: %s", content)
|
|
}
|
|
mainContent, err := os.ReadFile(filepath.Join(project, "cmd/server/main.go"))
|
|
if err != nil {
|
|
t.Fatalf("read generated server: %v", err)
|
|
}
|
|
for _, expected := range []string{"config.LoadFromEnv(\"\")", "logx.SetDefault(logger)", "omni.WithConfig(settings)", "servicecontext.New(ctx, logger)", "services.Health.ReadinessHandler()", "application.RunContext(ctx, settings.Address)"} {
|
|
if !strings.Contains(string(mainContent), expected) {
|
|
t.Fatalf("generated server missing %q: %s", expected, mainContent)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGenerateRejectsNonEmptyDirectory(t *testing.T) {
|
|
directory := t.TempDir()
|
|
if err := os.WriteFile(filepath.Join(directory, "existing.txt"), []byte("keep"), 0o644); err != nil {
|
|
t.Fatalf("seed directory: %v", err)
|
|
}
|
|
if err := Generate(Options{Dir: directory, Module: "example.com/demo"}); err == nil {
|
|
t.Fatal("expected non-empty directory error")
|
|
}
|
|
}
|
|
|
|
func TestGenerateMySQLLayout(t *testing.T) {
|
|
project := filepath.Join(t.TempDir(), "billing")
|
|
if err := Generate(Options{Dir: project, Module: "example.com/billing", Database: "mysql", FrameworkDir: frameworkRoot(t)}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, path := range []string{"schema.sql", "internal/repository/mysql.go", "internal/repository/users.go", "internal/model/errors.go", "internal/servicecontext/databaseIntegration_test.go"} {
|
|
if _, err := os.Stat(filepath.Join(project, path)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
content, err := os.ReadFile(filepath.Join(project, "go.mod"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(string(content), "github.com/go-sql-driver/mysql v1.9.3") {
|
|
t.Fatal("mysql driver version is not pinned")
|
|
}
|
|
}
|
|
|
|
func TestGenerateRejectsUnknownDatabaseBeforeWriting(t *testing.T) {
|
|
project := filepath.Join(t.TempDir(), "billing")
|
|
if err := Generate(Options{Dir: project, Module: "example.com/billing", Database: "unknown"}); err == nil {
|
|
t.Fatal("accepted unknown backend")
|
|
}
|
|
if _, err := os.Stat(project); !os.IsNotExist(err) {
|
|
t.Fatalf("invalid backend created files: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestFrameworkReplaceUsesCanonicalPaths(t *testing.T) {
|
|
root := frameworkRoot(t)
|
|
project := filepath.Join(t.TempDir(), "generated")
|
|
if err := os.MkdirAll(project, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
replace := frameworkReplace(project, root)
|
|
resolvedProject, err := filepath.EvalSymlinks(project)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
resolvedRoot, err := filepath.EvalSymlinks(root)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
expected, err := filepath.Rel(resolvedProject, resolvedRoot)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if replace != strconv.Quote(filepath.ToSlash(expected)) {
|
|
t.Fatalf("expected canonical replace %q, got %q", filepath.ToSlash(expected), replace)
|
|
}
|
|
}
|
|
|
|
func TestGenerateRemoteProjectPinsVersion(t *testing.T) {
|
|
for _, version := range []string{"v0.1.0", "v1.2.3-rc.1", "v0.0.0-20260920140624-8b19aa79eea0"} {
|
|
t.Run(version, func(t *testing.T) {
|
|
project := filepath.Join(t.TempDir(), "billing")
|
|
if err := Generate(Options{Dir: project, Module: "example.com/billing", FrameworkVersion: version}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
content, err := os.ReadFile(filepath.Join(project, "go.mod"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(string(content), "require "+frameworkModule+" "+version+"\n") || strings.Contains(string(content), "replace ") {
|
|
t.Fatalf("expected pinned remote dependency without replace: %s", content)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGenerateRejectsInvalidVersionBeforeWriting(t *testing.T) {
|
|
for _, version := range []string{"main", "latest", "v1.2", "v01.2.3", "v2.0.0", "v0.1.0-01", "v0.1.0\nreplace bad => ./bad"} {
|
|
project := filepath.Join(t.TempDir(), "billing")
|
|
if err := Generate(Options{Dir: project, Module: "example.com/billing", FrameworkVersion: version}); err == nil {
|
|
t.Fatalf("accepted invalid version %q", version)
|
|
}
|
|
if _, err := os.Stat(project); !os.IsNotExist(err) {
|
|
t.Fatalf("invalid version %q created a project: %v", version, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFrameworkVersionUsesInstalledModuleMetadata(t *testing.T) {
|
|
for _, test := range []struct {
|
|
info *debug.BuildInfo
|
|
want string
|
|
}{
|
|
{nil, defaultFrameworkVersion},
|
|
{&debug.BuildInfo{Main: debug.Module{Path: frameworkModule, Version: "(devel)"}}, defaultFrameworkVersion},
|
|
{&debug.BuildInfo{Main: debug.Module{Path: frameworkModule, Version: "v0.1.0+dirty"}}, defaultFrameworkVersion},
|
|
{&debug.BuildInfo{Main: debug.Module{Path: "example.com/unrelated", Version: "v1.2.3"}}, defaultFrameworkVersion},
|
|
{&debug.BuildInfo{Main: debug.Module{Path: frameworkModule, Version: "v0.9.2", Sum: "h1:test"}}, "v0.9.2"},
|
|
{&debug.BuildInfo{Main: debug.Module{Path: frameworkModule, Version: "v0.0.0-20260920140624-8b19aa79eea0", Sum: "h1:test"}}, "v0.0.0-20260920140624-8b19aa79eea0"},
|
|
} {
|
|
if got := frameworkVersion(test.info); got != test.want {
|
|
t.Fatalf("version = %q, want %q", got, test.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func frameworkRoot(t *testing.T) string {
|
|
t.Helper()
|
|
directory, err := os.Getwd()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for {
|
|
if _, err := os.Stat(filepath.Join(directory, "go.mod")); err == nil {
|
|
return directory
|
|
}
|
|
parent := filepath.Dir(directory)
|
|
if parent == directory {
|
|
t.Fatal("framework root not found")
|
|
}
|
|
directory = parent
|
|
}
|
|
}
|