test: H-02 补充 migrations 测试
- 验证迁移文件正确嵌入 embed.FS - 测试所有迁移文件可读且非空 - 验证迁移文件命名规范(NNNN_前缀) - 测试迁移文件排序一致性 - 验证初始迁移文件包含预期 SQL 内容
This commit is contained in:
171
internal/store/migrations/embed_test.go
Normal file
171
internal/store/migrations/embed_test.go
Normal file
@@ -0,0 +1,171 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFilesEmbedded(t *testing.T) {
|
||||
// Test that migration files are properly embedded
|
||||
entries, err := Files.ReadDir(".")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read embedded migrations: %v", err)
|
||||
}
|
||||
|
||||
if len(entries) == 0 {
|
||||
t.Fatal("No migration files embedded")
|
||||
}
|
||||
|
||||
// Verify we have SQL files
|
||||
hasSQL := false
|
||||
for _, entry := range entries {
|
||||
if !entry.IsDir() && len(entry.Name()) > 4 && entry.Name()[len(entry.Name())-4:] == ".sql" {
|
||||
hasSQL = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !hasSQL {
|
||||
t.Fatal("No .sql files found in embedded migrations")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMigrationFilesReadable(t *testing.T) {
|
||||
// Test that all embedded migration files can be read
|
||||
entries, err := Files.ReadDir(".")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read embedded migrations: %v", err)
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
// Skip non-SQL files
|
||||
name := entry.Name()
|
||||
if len(name) < 4 || name[len(name)-4:] != ".sql" {
|
||||
continue
|
||||
}
|
||||
|
||||
content, err := Files.ReadFile(name)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to read migration file %s: %v", name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if len(content) == 0 {
|
||||
t.Errorf("Migration file %s is empty", name)
|
||||
}
|
||||
|
||||
// Verify content looks like SQL
|
||||
contentStr := string(content)
|
||||
if len(contentStr) < 10 {
|
||||
t.Errorf("Migration file %s content too short", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMigrationFileNaming(t *testing.T) {
|
||||
// Test that migration files follow naming convention (NNNN_description.sql)
|
||||
entries, err := Files.ReadDir(".")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read embedded migrations: %v", err)
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
name := entry.Name()
|
||||
if len(name) < 4 || name[len(name)-4:] != ".sql" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check naming pattern: should start with digits followed by underscore
|
||||
if len(name) < 5 {
|
||||
t.Errorf("Migration file %s name too short", name)
|
||||
continue
|
||||
}
|
||||
|
||||
// Should start with at least 4 digits
|
||||
hasPrefix := false
|
||||
for i := 0; i < 4 && i < len(name); i++ {
|
||||
if name[i] >= '0' && name[i] <= '9' {
|
||||
if i == 3 {
|
||||
hasPrefix = true
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !hasPrefix {
|
||||
t.Errorf("Migration file %s does not follow naming convention (should start with 4 digits)", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMigrationFilesSorted(t *testing.T) {
|
||||
// Test that migration files can be sorted consistently
|
||||
entries, err := Files.ReadDir(".")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read embedded migrations: %v", err)
|
||||
}
|
||||
|
||||
var sqlFiles []string
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
name := entry.Name()
|
||||
if len(name) > 4 && name[len(name)-4:] == ".sql" {
|
||||
sqlFiles = append(sqlFiles, name)
|
||||
}
|
||||
}
|
||||
|
||||
if len(sqlFiles) < 2 {
|
||||
t.Skip("Not enough SQL files to test sorting")
|
||||
}
|
||||
|
||||
// Verify files can be compared
|
||||
for i := 1; i < len(sqlFiles); i++ {
|
||||
if sqlFiles[i] < sqlFiles[i-1] {
|
||||
t.Errorf("Files not sorted: %s should come before %s", sqlFiles[i-1], sqlFiles[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitialMigrationContent(t *testing.T) {
|
||||
// Test that the initial migration file exists and has expected content
|
||||
content, err := Files.ReadFile("0001_init.sql")
|
||||
if err != nil {
|
||||
t.Skipf("0001_init.sql not found: %v", err)
|
||||
}
|
||||
|
||||
contentStr := string(content)
|
||||
|
||||
// Initial migration should contain CREATE TABLE statements
|
||||
if len(contentStr) < 50 {
|
||||
t.Error("Initial migration file seems too short")
|
||||
}
|
||||
|
||||
// Should contain typical SQL keywords
|
||||
hasCreate := containsAny(contentStr, []string{"CREATE", "create"})
|
||||
hasTable := containsAny(contentStr, []string{"TABLE", "table"})
|
||||
|
||||
if !hasCreate || !hasTable {
|
||||
t.Error("Initial migration should contain CREATE TABLE statements")
|
||||
}
|
||||
}
|
||||
|
||||
func containsAny(s string, substrs []string) bool {
|
||||
for _, substr := range substrs {
|
||||
for i := 0; i <= len(s)-len(substr); i++ {
|
||||
if s[i:i+len(substr)] == substr {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user