test(model): add tests for task defaults, job queries, and DTOs
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
200
internal/model/job_test.go
Normal file
200
internal/model/job_test.go
Normal file
@@ -0,0 +1,200 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSubmitJobRequest_SchedulingFields(t *testing.T) {
|
||||
payload := `{
|
||||
"script": "#!/bin/bash\necho hello",
|
||||
"work_dir": "/tmp/work",
|
||||
"partition": "gpu",
|
||||
"qos": "high",
|
||||
"cpus": 16,
|
||||
"memory": "4GB",
|
||||
"time_limit": "60",
|
||||
"job_name": "test-job",
|
||||
"environment": {"PATH": "/usr/bin"},
|
||||
"memory_per_node": 32768,
|
||||
"memory_per_cpu": 4096,
|
||||
"nodes": "2",
|
||||
"tasks": 4,
|
||||
"cpus_per_task": 8,
|
||||
"constraints": "gpu&a100",
|
||||
"reservation": "res-001",
|
||||
"account": "project-x",
|
||||
"nice": 100,
|
||||
"mail_type": "END,FAIL",
|
||||
"mail_user": "user@example.com",
|
||||
"standard_output": "/tmp/out_%j.log",
|
||||
"standard_error": "/tmp/err_%j.log",
|
||||
"standard_input": "/tmp/input.txt",
|
||||
"required_nodes": "node[01-03]",
|
||||
"excluded_nodes": "node04",
|
||||
"begin_time": 1700000000,
|
||||
"deadline": 1700086400,
|
||||
"array": "1-100%10",
|
||||
"dependency": "afterok:12345",
|
||||
"requeue": true,
|
||||
"kill_on_node_fail": false
|
||||
}`
|
||||
|
||||
var req SubmitJobRequest
|
||||
if err := json.Unmarshal([]byte(payload), &req); err != nil {
|
||||
t.Fatalf("unmarshal SubmitJobRequest: %v", err)
|
||||
}
|
||||
|
||||
// Existing fields
|
||||
if req.Script != "#!/bin/bash\necho hello" {
|
||||
t.Errorf("Script = %q, want script content", req.Script)
|
||||
}
|
||||
if req.WorkDir != "/tmp/work" {
|
||||
t.Errorf("WorkDir = %q, want /tmp/work", req.WorkDir)
|
||||
}
|
||||
if req.Partition != "gpu" {
|
||||
t.Errorf("Partition = %q, want gpu", req.Partition)
|
||||
}
|
||||
if req.QOS != "high" {
|
||||
t.Errorf("QOS = %q, want high", req.QOS)
|
||||
}
|
||||
if req.CPUs != 16 {
|
||||
t.Errorf("CPUs = %d, want 16", req.CPUs)
|
||||
}
|
||||
if req.Memory != "4GB" {
|
||||
t.Errorf("Memory = %q, want 4GB", req.Memory)
|
||||
}
|
||||
if req.TimeLimit != "60" {
|
||||
t.Errorf("TimeLimit = %q, want 60", req.TimeLimit)
|
||||
}
|
||||
if req.JobName != "test-job" {
|
||||
t.Errorf("JobName = %q, want test-job", req.JobName)
|
||||
}
|
||||
if v, ok := req.Environment["PATH"]; !ok || v != "/usr/bin" {
|
||||
t.Errorf("Environment[PATH] = %q, want /usr/bin", v)
|
||||
}
|
||||
|
||||
// New scheduling fields
|
||||
if req.MemoryPerNode == nil || *req.MemoryPerNode != 32768 {
|
||||
t.Errorf("MemoryPerNode = %v, want 32768", req.MemoryPerNode)
|
||||
}
|
||||
if req.MemoryPerCpu == nil || *req.MemoryPerCpu != 4096 {
|
||||
t.Errorf("MemoryPerCpu = %v, want 4096", req.MemoryPerCpu)
|
||||
}
|
||||
if req.Nodes == nil || *req.Nodes != "2" {
|
||||
t.Errorf("Nodes = %v, want 2", req.Nodes)
|
||||
}
|
||||
if req.Tasks == nil || *req.Tasks != 4 {
|
||||
t.Errorf("Tasks = %v, want 4", req.Tasks)
|
||||
}
|
||||
if req.CpusPerTask == nil || *req.CpusPerTask != 8 {
|
||||
t.Errorf("CpusPerTask = %v, want 8", req.CpusPerTask)
|
||||
}
|
||||
if req.Constraints == nil || *req.Constraints != "gpu&a100" {
|
||||
t.Errorf("Constraints = %v, want gpu&a100", req.Constraints)
|
||||
}
|
||||
if req.Reservation == nil || *req.Reservation != "res-001" {
|
||||
t.Errorf("Reservation = %v, want res-001", req.Reservation)
|
||||
}
|
||||
if req.Account == nil || *req.Account != "project-x" {
|
||||
t.Errorf("Account = %v, want project-x", req.Account)
|
||||
}
|
||||
if req.Nice == nil || *req.Nice != 100 {
|
||||
t.Errorf("Nice = %v, want 100", req.Nice)
|
||||
}
|
||||
if req.MailType == nil || *req.MailType != "END,FAIL" {
|
||||
t.Errorf("MailType = %v, want END,FAIL", req.MailType)
|
||||
}
|
||||
if req.MailUser == nil || *req.MailUser != "user@example.com" {
|
||||
t.Errorf("MailUser = %v, want user@example.com", req.MailUser)
|
||||
}
|
||||
if req.StandardOutput == nil || *req.StandardOutput != "/tmp/out_%j.log" {
|
||||
t.Errorf("StandardOutput = %v, want /tmp/out_%%j.log", req.StandardOutput)
|
||||
}
|
||||
if req.StandardError == nil || *req.StandardError != "/tmp/err_%j.log" {
|
||||
t.Errorf("StandardError = %v, want /tmp/err_%%j.log", req.StandardError)
|
||||
}
|
||||
if req.StandardInput == nil || *req.StandardInput != "/tmp/input.txt" {
|
||||
t.Errorf("StandardInput = %v, want /tmp/input.txt", req.StandardInput)
|
||||
}
|
||||
if req.RequiredNodes == nil || *req.RequiredNodes != "node[01-03]" {
|
||||
t.Errorf("RequiredNodes = %v, want node[01-03]", req.RequiredNodes)
|
||||
}
|
||||
if req.ExcludedNodes == nil || *req.ExcludedNodes != "node04" {
|
||||
t.Errorf("ExcludedNodes = %v, want node04", req.ExcludedNodes)
|
||||
}
|
||||
if req.BeginTime == nil || *req.BeginTime != 1700000000 {
|
||||
t.Errorf("BeginTime = %v, want 1700000000", req.BeginTime)
|
||||
}
|
||||
if req.Deadline == nil || *req.Deadline != 1700086400 {
|
||||
t.Errorf("Deadline = %v, want 1700086400", req.Deadline)
|
||||
}
|
||||
if req.Array == nil || *req.Array != "1-100%10" {
|
||||
t.Errorf("Array = %v, want 1-100%%10", req.Array)
|
||||
}
|
||||
if req.Dependency == nil || *req.Dependency != "afterok:12345" {
|
||||
t.Errorf("Dependency = %v, want afterok:12345", req.Dependency)
|
||||
}
|
||||
if req.Requeue == nil || *req.Requeue != true {
|
||||
t.Errorf("Requeue = %v, want true", req.Requeue)
|
||||
}
|
||||
if req.KillOnNodeFail == nil || *req.KillOnNodeFail != false {
|
||||
t.Errorf("KillOnNodeFail = %v, want false", req.KillOnNodeFail)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubmitJobRequest_BackwardCompat(t *testing.T) {
|
||||
// Minimal JSON — only required fields
|
||||
payload := `{"script": "#!/bin/bash\necho hello", "work_dir": "/tmp"}`
|
||||
|
||||
var req SubmitJobRequest
|
||||
if err := json.Unmarshal([]byte(payload), &req); err != nil {
|
||||
t.Fatalf("unmarshal minimal SubmitJobRequest: %v", err)
|
||||
}
|
||||
|
||||
// Required fields present
|
||||
if req.Script != "#!/bin/bash\necho hello" {
|
||||
t.Errorf("Script = %q, want script content", req.Script)
|
||||
}
|
||||
if req.WorkDir != "/tmp" {
|
||||
t.Errorf("WorkDir = %q, want /tmp", req.WorkDir)
|
||||
}
|
||||
|
||||
// Old fields exist with zero values
|
||||
if req.Memory != "" {
|
||||
t.Errorf("Memory = %q, want empty", req.Memory)
|
||||
}
|
||||
if req.Environment != nil {
|
||||
t.Errorf("Environment = %v, want nil", req.Environment)
|
||||
}
|
||||
|
||||
// All new scheduling fields are nil
|
||||
assertNil := func(name string, val any) {
|
||||
if !reflect.ValueOf(val).IsNil() {
|
||||
t.Errorf("%s = %v, want nil", name, val)
|
||||
}
|
||||
}
|
||||
assertNil("MemoryPerNode", req.MemoryPerNode)
|
||||
assertNil("MemoryPerCpu", req.MemoryPerCpu)
|
||||
assertNil("Nodes", req.Nodes)
|
||||
assertNil("Tasks", req.Tasks)
|
||||
assertNil("CpusPerTask", req.CpusPerTask)
|
||||
assertNil("Constraints", req.Constraints)
|
||||
assertNil("Reservation", req.Reservation)
|
||||
assertNil("Account", req.Account)
|
||||
assertNil("Nice", req.Nice)
|
||||
assertNil("MailType", req.MailType)
|
||||
assertNil("MailUser", req.MailUser)
|
||||
assertNil("StandardOutput", req.StandardOutput)
|
||||
assertNil("StandardError", req.StandardError)
|
||||
assertNil("StandardInput", req.StandardInput)
|
||||
assertNil("RequiredNodes", req.RequiredNodes)
|
||||
assertNil("ExcludedNodes", req.ExcludedNodes)
|
||||
assertNil("BeginTime", req.BeginTime)
|
||||
assertNil("Deadline", req.Deadline)
|
||||
assertNil("Array", req.Array)
|
||||
assertNil("Dependency", req.Dependency)
|
||||
assertNil("Requeue", req.Requeue)
|
||||
assertNil("KillOnNodeFail", req.KillOnNodeFail)
|
||||
}
|
||||
Reference in New Issue
Block a user