package service import ( "context" "errors" "testing" "time" "gorm.io/driver/sqlite" "gorm.io/gorm" "go-admin/app/jobs/models" ) func executionLogTestDB(t *testing.T) *gorm.DB { t.Helper() db, err := gorm.Open(sqlite.Open("file:"+t.Name()+"?mode=memory&cache=shared"), &gorm.Config{}) if err != nil { t.Fatal(err) } if err := db.AutoMigrate(&models.SysJob{}, &models.SysJobExecutionLog{}); err != nil { t.Fatal(err) } return db } func TestExecutionLogListFiltersPaginatesAndKeepsDeletedJob(t *testing.T) { db := executionLogTestDB(t) job := models.SysJob{JobName: "测试任务", InvokeTarget: "TestTarget"} if err := db.Create(&job).Error; err != nil { t.Fatal(err) } base := time.Date(2026, 9, 2, 10, 0, 0, 0, time.UTC) records := []models.SysJobExecutionLog{ {ExecutionID: "00000000-0000-4000-8000-000000000001", JobID: job.JobId, JobNameSnapshot: job.JobName, InvokeTargetSnapshot: job.InvokeTarget, TriggerType: models.JobTriggerScheduled, Status: models.JobExecutionSucceeded, StartedAt: base}, {ExecutionID: "00000000-0000-4000-8000-000000000002", JobID: job.JobId, JobNameSnapshot: job.JobName, InvokeTargetSnapshot: job.InvokeTarget, TriggerType: models.JobTriggerScheduled, Status: models.JobExecutionFailed, StartedAt: base.Add(time.Hour)}, {ExecutionID: "00000000-0000-4000-8000-000000000003", JobID: job.JobId, JobNameSnapshot: job.JobName, InvokeTargetSnapshot: job.InvokeTarget, TriggerType: models.JobTriggerScheduled, Status: models.JobExecutionFailed, StartedAt: base.Add(2 * time.Hour)}, } if err := db.Create(&records).Error; err != nil { t.Fatal(err) } from, to := base.Add(30*time.Minute), base.Add(3*time.Hour) result, err := NewExecutionLogService(db).List(context.Background(), job.JobId, ExecutionLogListRequest{ Page: 1, PageSize: 1, Status: models.JobExecutionFailed, StartedFrom: &from, StartedTo: &to, }) if err != nil { t.Fatal(err) } if result.Total != 2 || len(result.Items) != 1 || result.Items[0].ExecutionID != records[2].ExecutionID { t.Fatalf("unexpected filtered page: %+v", result) } if err := db.Delete(&job).Error; err != nil { t.Fatal(err) } deleted, err := NewExecutionLogService(db).List(context.Background(), job.JobId, ExecutionLogListRequest{Page: 1, PageSize: 20}) if err != nil { t.Fatal(err) } if !deleted.Job.Deleted || deleted.Job.JobName != job.JobName || deleted.Total != 3 { t.Fatalf("deleted job history unavailable: %+v", deleted) } } func TestExecutionLogListValidationAndNotFound(t *testing.T) { db := executionLogTestDB(t) service := NewExecutionLogService(db) if _, err := service.List(context.Background(), 0, ExecutionLogListRequest{}); !errors.Is(err, ErrExecutionLogInvalidRequest) { t.Fatalf("invalid job id error = %v", err) } if _, err := service.List(context.Background(), 1, ExecutionLogListRequest{PageSize: 101}); !errors.Is(err, ErrExecutionLogInvalidRequest) { t.Fatalf("invalid page size error = %v", err) } job := models.SysJob{JobName: "测试任务", InvokeTarget: "TestTarget"} if err := db.Create(&job).Error; err != nil { t.Fatal(err) } if _, err := service.List(context.Background(), job.JobId, ExecutionLogListRequest{Status: "unknown"}); !errors.Is(err, ErrExecutionLogInvalidRequest) { t.Fatalf("invalid status error = %v", err) } from, to := time.Now(), time.Now().Add(-time.Hour) if _, err := service.List(context.Background(), job.JobId, ExecutionLogListRequest{StartedFrom: &from, StartedTo: &to}); !errors.Is(err, ErrExecutionLogInvalidRequest) { t.Fatalf("invalid range error = %v", err) } if _, err := service.List(context.Background(), 999, ExecutionLogListRequest{}); !errors.Is(err, ErrExecutionLogJobNotFound) { t.Fatalf("not found error = %v", err) } }