- model: JobTemplate、SubmitJobRequest、JobHistoryQuery 等模型定义 - store: NewGormDB MySQL 连接池,使用 zap 日志替代 GORM 默认日志 - store: TemplateStore CRUD 操作,支持 GORM AutoMigrate - NewGormDB 接受 gormLevel 参数,由上层传入配置值 - 完整 TDD 测试覆盖 Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
206 lines
4.9 KiB
Go
206 lines
4.9 KiB
Go
package store
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"gorm.io/driver/sqlite"
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/logger"
|
|
|
|
"gcy_hpc_server/internal/model"
|
|
)
|
|
|
|
func newTestDB(t *testing.T) *gorm.DB {
|
|
t.Helper()
|
|
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{
|
|
Logger: logger.Default.LogMode(logger.Silent),
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("open sqlite: %v", err)
|
|
}
|
|
if err := db.AutoMigrate(&model.JobTemplate{}); err != nil {
|
|
t.Fatalf("auto migrate: %v", err)
|
|
}
|
|
return db
|
|
}
|
|
|
|
func TestTemplateStore_List(t *testing.T) {
|
|
db := newTestDB(t)
|
|
s := NewTemplateStore(db)
|
|
|
|
s.Create(context.Background(), &model.CreateTemplateRequest{Name: "job-1", Script: "echo 1"})
|
|
s.Create(context.Background(), &model.CreateTemplateRequest{Name: "job-2", Script: "echo 2"})
|
|
|
|
templates, total, err := s.List(context.Background(), 1, 10)
|
|
if err != nil {
|
|
t.Fatalf("List() error = %v", err)
|
|
}
|
|
if total != 2 {
|
|
t.Errorf("total = %d, want 2", total)
|
|
}
|
|
if len(templates) != 2 {
|
|
t.Fatalf("len(templates) = %d, want 2", len(templates))
|
|
}
|
|
// DESC order, so job-2 is first
|
|
if templates[0].Name != "job-2" {
|
|
t.Errorf("templates[0].Name = %q, want %q", templates[0].Name, "job-2")
|
|
}
|
|
}
|
|
|
|
func TestTemplateStore_List_Page2(t *testing.T) {
|
|
db := newTestDB(t)
|
|
s := NewTemplateStore(db)
|
|
|
|
for i := 0; i < 15; i++ {
|
|
s.Create(context.Background(), &model.CreateTemplateRequest{
|
|
Name: "job-" + string(rune('A'+i)), Script: "echo",
|
|
})
|
|
}
|
|
|
|
templates, total, err := s.List(context.Background(), 2, 10)
|
|
if err != nil {
|
|
t.Fatalf("List() error = %v", err)
|
|
}
|
|
if total != 15 {
|
|
t.Errorf("total = %d, want 15", total)
|
|
}
|
|
if len(templates) != 5 {
|
|
t.Fatalf("len(templates) = %d, want 5", len(templates))
|
|
}
|
|
}
|
|
|
|
func TestTemplateStore_GetByID(t *testing.T) {
|
|
db := newTestDB(t)
|
|
s := NewTemplateStore(db)
|
|
|
|
id, _ := s.Create(context.Background(), &model.CreateTemplateRequest{
|
|
Name: "test-job", Script: "echo hi", Partition: "batch", QOS: "normal", CPUs: 2, Memory: "4G",
|
|
})
|
|
|
|
tpl, err := s.GetByID(context.Background(), id)
|
|
if err != nil {
|
|
t.Fatalf("GetByID() error = %v", err)
|
|
}
|
|
if tpl == nil {
|
|
t.Fatal("GetByID() returned nil")
|
|
}
|
|
if tpl.Name != "test-job" {
|
|
t.Errorf("Name = %q, want %q", tpl.Name, "test-job")
|
|
}
|
|
if tpl.CPUs != 2 {
|
|
t.Errorf("CPUs = %d, want 2", tpl.CPUs)
|
|
}
|
|
}
|
|
|
|
func TestTemplateStore_GetByID_NotFound(t *testing.T) {
|
|
db := newTestDB(t)
|
|
s := NewTemplateStore(db)
|
|
|
|
tpl, err := s.GetByID(context.Background(), 999)
|
|
if err != nil {
|
|
t.Fatalf("GetByID() error = %v, want nil", err)
|
|
}
|
|
if tpl != nil {
|
|
t.Fatal("GetByID() should return nil for not found")
|
|
}
|
|
}
|
|
|
|
func TestTemplateStore_Create(t *testing.T) {
|
|
db := newTestDB(t)
|
|
s := NewTemplateStore(db)
|
|
|
|
id, err := s.Create(context.Background(), &model.CreateTemplateRequest{
|
|
Name: "new-job", Script: "echo", Partition: "gpu",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Create() error = %v", err)
|
|
}
|
|
if id == 0 {
|
|
t.Fatal("Create() returned id=0")
|
|
}
|
|
}
|
|
|
|
func TestTemplateStore_Update(t *testing.T) {
|
|
db := newTestDB(t)
|
|
s := NewTemplateStore(db)
|
|
|
|
id, _ := s.Create(context.Background(), &model.CreateTemplateRequest{
|
|
Name: "old", Script: "echo",
|
|
})
|
|
|
|
err := s.Update(context.Background(), id, &model.UpdateTemplateRequest{
|
|
Name: "updated",
|
|
Script: "echo new",
|
|
CPUs: 8,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Update() error = %v", err)
|
|
}
|
|
|
|
tpl, _ := s.GetByID(context.Background(), id)
|
|
if tpl.Name != "updated" {
|
|
t.Errorf("Name = %q, want %q", tpl.Name, "updated")
|
|
}
|
|
if tpl.CPUs != 8 {
|
|
t.Errorf("CPUs = %d, want 8", tpl.CPUs)
|
|
}
|
|
}
|
|
|
|
func TestTemplateStore_Update_Partial(t *testing.T) {
|
|
db := newTestDB(t)
|
|
s := NewTemplateStore(db)
|
|
|
|
id, _ := s.Create(context.Background(), &model.CreateTemplateRequest{
|
|
Name: "original", Script: "echo orig", Partition: "batch",
|
|
})
|
|
|
|
err := s.Update(context.Background(), id, &model.UpdateTemplateRequest{
|
|
Name: "renamed",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Update() error = %v", err)
|
|
}
|
|
|
|
tpl, _ := s.GetByID(context.Background(), id)
|
|
if tpl.Name != "renamed" {
|
|
t.Errorf("Name = %q, want %q", tpl.Name, "renamed")
|
|
}
|
|
// Script and Partition should be unchanged
|
|
if tpl.Script != "echo orig" {
|
|
t.Errorf("Script = %q, want %q", tpl.Script, "echo orig")
|
|
}
|
|
if tpl.Partition != "batch" {
|
|
t.Errorf("Partition = %q, want %q", tpl.Partition, "batch")
|
|
}
|
|
}
|
|
|
|
func TestTemplateStore_Delete(t *testing.T) {
|
|
db := newTestDB(t)
|
|
s := NewTemplateStore(db)
|
|
|
|
id, _ := s.Create(context.Background(), &model.CreateTemplateRequest{
|
|
Name: "to-delete", Script: "echo",
|
|
})
|
|
|
|
err := s.Delete(context.Background(), id)
|
|
if err != nil {
|
|
t.Fatalf("Delete() error = %v", err)
|
|
}
|
|
|
|
tpl, _ := s.GetByID(context.Background(), id)
|
|
if tpl != nil {
|
|
t.Fatal("Delete() did not remove the record")
|
|
}
|
|
}
|
|
|
|
func TestTemplateStore_Delete_NotFound(t *testing.T) {
|
|
db := newTestDB(t)
|
|
s := NewTemplateStore(db)
|
|
|
|
err := s.Delete(context.Background(), 999)
|
|
if err != nil {
|
|
t.Fatalf("Delete() should not error for non-existent record, got: %v", err)
|
|
}
|
|
}
|