From f034b73a4706dd43d93f79ee42c1fafa1f236d09 Mon Sep 17 00:00:00 2001 From: ryan Date: Mon, 1 Jun 2026 10:33:50 +0800 Subject: [PATCH] =?UTF-8?q?[=E6=96=B0=E5=A2=9E]=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93=E8=BF=81=E7=A7=BB=E5=92=8C=20GORM?= =?UTF-8?q?=20=E6=A8=A1=E5=9E=8B=E9=AA=8C=E8=AF=81=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=EF=BC=8C=E7=A1=AE=E4=BF=9D=E6=89=80=E6=9C=89=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E5=9D=87=E5=B7=B2=E6=B3=A8=E5=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openflare_server/model/main_test.go | 76 +++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/openflare_server/model/main_test.go b/openflare_server/model/main_test.go index 5021763d..bad9ec0e 100644 --- a/openflare_server/model/main_test.go +++ b/openflare_server/model/main_test.go @@ -2,7 +2,13 @@ package model import ( "encoding/json" + "go/ast" + "go/parser" + "go/token" + "os" "path/filepath" + "reflect" + "strings" "testing" "time" @@ -515,3 +521,73 @@ func TestEnsureDatabaseSchemaUpToDateAddsNodeIPManualOverride(t *testing.T) { t.Fatalf("unexpected schema version: got %d want %d", version, currentDatabaseSchemaVersion) } } + +func TestAllRegisteredMigrationsHaveValidationDefined(t *testing.T) { + ctx := databaseSchemaMigrationContext{} + for _, migration := range databaseSchemaMigrations() { + err := ctx.ValidateDatabaseSchemaVersion(nil, "sqlite", migration.toVersion) + if err != nil && strings.Contains(err.Error(), "is not defined") { + t.Fatalf("Validation is not defined in migrations.go for registered migration version v%d: %v", migration.toVersion, err) + } + } +} + +func TestAllGORMModelsAreRegistered(t *testing.T) { + // 1. Gather all registered model names + registeredNames := make(map[string]bool) + for _, item := range registeredModels() { + name := reflect.TypeOf(item).Elem().Name() + registeredNames[name] = true + } + for _, item := range schemaMetadataModels() { + name := reflect.TypeOf(item).Elem().Name() + registeredNames[name] = true + } + + // 2. Parse all .go files in model/ package + fset := token.NewFileSet() + pkgs, err := parser.ParseDir(fset, ".", func(info os.FileInfo) bool { + // Only parse .go files, exclude _test.go files and subdirectories + return !info.IsDir() && strings.HasSuffix(info.Name(), ".go") && !strings.HasSuffix(info.Name(), "_test.go") + }, 0) + if err != nil { + t.Fatalf("failed to parse directory: %v", err) + } + + for _, pkg := range pkgs { + for _, file := range pkg.Files { + for _, decl := range file.Decls { + genDecl, ok := decl.(*ast.GenDecl) + if !ok || genDecl.Tok != token.TYPE { + continue + } + for _, spec := range genDecl.Specs { + typeSpec, ok := spec.(*ast.TypeSpec) + if !ok { + continue + } + structType, ok := typeSpec.Type.(*ast.StructType) + if !ok { + continue + } + + // Verify if this struct has any field with a `gorm:"..."` tag + isGORMModel := false + for _, field := range structType.Fields.List { + if field.Tag != nil && strings.Contains(field.Tag.Value, "gorm:") { + isGORMModel = true + break + } + } + + if isGORMModel { + structName := typeSpec.Name.Name + if !registeredNames[structName] { + t.Errorf("Model struct %q is defined with GORM tags but is NOT registered in registeredModels() or schemaMetadataModels() in model/main.go!", structName) + } + } + } + } + } + } +}