约 93 个结构体覆盖 JobInfo、JobDescMsg、SlurmDBD Job/Step/QOS/Account/User 等类型。JobsService 提供 GetJobs、GetJob、PostJob、DeleteJob、SubmitJob 5 个方法,并定义 JobFlag* 和 JobSignalFlag* 常量。 Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
287 lines
8.0 KiB
Go
287 lines
8.0 KiB
Go
package slurm
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func testMethod(t *testing.T, r *http.Request, expected string) {
|
|
t.Helper()
|
|
if r.Method != expected {
|
|
t.Errorf("expected method %s, got %s", expected, r.Method)
|
|
}
|
|
}
|
|
|
|
func TestJobsService_GetJobs(t *testing.T) {
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("/slurm/v0.0.40/jobs", func(w http.ResponseWriter, r *http.Request) {
|
|
testMethod(t, r, "GET")
|
|
fmt.Fprint(w, `{"jobs": [], "last_backfill": {}, "last_update": {}}`)
|
|
})
|
|
server := httptest.NewServer(mux)
|
|
defer server.Close()
|
|
|
|
client, _ := NewClient(server.URL, nil)
|
|
resp, _, err := client.Jobs.GetJobs(context.Background(), nil)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if resp == nil {
|
|
t.Fatal("expected non-nil response")
|
|
}
|
|
if len(resp.Jobs) != 0 {
|
|
t.Errorf("expected empty jobs, got %d", len(resp.Jobs))
|
|
}
|
|
}
|
|
|
|
func TestJobsService_GetJobs_WithOptions(t *testing.T) {
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("/slurm/v0.0.40/jobs", func(w http.ResponseWriter, r *http.Request) {
|
|
testMethod(t, r, "GET")
|
|
q := r.URL.Query()
|
|
if q.Get("update_time") != "12345" {
|
|
t.Errorf("expected update_time=12345, got %s", q.Get("update_time"))
|
|
}
|
|
if q.Get("flags") != JobFlagDetail {
|
|
t.Errorf("expected flags=%s, got %s", JobFlagDetail, q.Get("flags"))
|
|
}
|
|
fmt.Fprint(w, `{"jobs": [], "last_update": {}}`)
|
|
})
|
|
server := httptest.NewServer(mux)
|
|
defer server.Close()
|
|
|
|
client, _ := NewClient(server.URL, nil)
|
|
opts := &GetJobsOptions{
|
|
UpdateTime: Ptr("12345"),
|
|
Flags: Ptr(JobFlagDetail),
|
|
}
|
|
resp, _, err := client.Jobs.GetJobs(context.Background(), opts)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if resp == nil {
|
|
t.Fatal("expected non-nil response")
|
|
}
|
|
}
|
|
|
|
func TestJobsService_GetJob(t *testing.T) {
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("/slurm/v0.0.40/job/42", func(w http.ResponseWriter, r *http.Request) {
|
|
testMethod(t, r, "GET")
|
|
fmt.Fprint(w, `{"jobs": [{"job_id": 42, "name": "test-job"}], "last_update": {}}`)
|
|
})
|
|
server := httptest.NewServer(mux)
|
|
defer server.Close()
|
|
|
|
client, _ := NewClient(server.URL, nil)
|
|
resp, _, err := client.Jobs.GetJob(context.Background(), "42", nil)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if resp == nil {
|
|
t.Fatal("expected non-nil response")
|
|
}
|
|
if len(resp.Jobs) != 1 {
|
|
t.Fatalf("expected 1 job, got %d", len(resp.Jobs))
|
|
}
|
|
if resp.Jobs[0].JobID == nil || *resp.Jobs[0].JobID != 42 {
|
|
t.Errorf("expected job_id=42, got %v", resp.Jobs[0].JobID)
|
|
}
|
|
}
|
|
|
|
func TestJobsService_PostJob(t *testing.T) {
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("/slurm/v0.0.40/job/42", func(w http.ResponseWriter, r *http.Request) {
|
|
testMethod(t, r, "POST")
|
|
if ct := r.Header.Get("Content-Type"); ct != "application/json" {
|
|
t.Errorf("expected Content-Type application/json, got %s", ct)
|
|
}
|
|
fmt.Fprint(w, `{"job_id": "42", "step_id": "0", "results": []}`)
|
|
})
|
|
server := httptest.NewServer(mux)
|
|
defer server.Close()
|
|
|
|
client, _ := NewClient(server.URL, nil)
|
|
desc := &JobDescMsg{
|
|
Name: Ptr("updated-job"),
|
|
}
|
|
resp, _, err := client.Jobs.PostJob(context.Background(), "42", desc)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if resp == nil {
|
|
t.Fatal("expected non-nil response")
|
|
}
|
|
if resp.JobID == nil || *resp.JobID != "42" {
|
|
t.Errorf("expected job_id=42, got %v", resp.JobID)
|
|
}
|
|
}
|
|
|
|
func TestJobsService_DeleteJob(t *testing.T) {
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("/slurm/v0.0.40/job/42", func(w http.ResponseWriter, r *http.Request) {
|
|
testMethod(t, r, "DELETE")
|
|
q := r.URL.Query()
|
|
if q.Get("signal") != "SIGTERM" {
|
|
t.Errorf("expected signal=SIGTERM, got %s", q.Get("signal"))
|
|
}
|
|
fmt.Fprint(w, `{}`)
|
|
})
|
|
server := httptest.NewServer(mux)
|
|
defer server.Close()
|
|
|
|
client, _ := NewClient(server.URL, nil)
|
|
opts := &DeleteJobOptions{
|
|
Signal: Ptr("SIGTERM"),
|
|
}
|
|
resp, _, err := client.Jobs.DeleteJob(context.Background(), "42", opts)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if resp == nil {
|
|
t.Fatal("expected non-nil response")
|
|
}
|
|
}
|
|
|
|
func TestJobsService_SubmitJob(t *testing.T) {
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("/slurm/v0.0.40/job/submit", func(w http.ResponseWriter, r *http.Request) {
|
|
testMethod(t, r, "POST")
|
|
if ct := r.Header.Get("Content-Type"); ct != "application/json" {
|
|
t.Errorf("expected Content-Type application/json, got %s", ct)
|
|
}
|
|
fmt.Fprint(w, `{"job_id": 100, "step_id": "0", "result": {"job_id": 100, "step_id": "0"}}`)
|
|
})
|
|
server := httptest.NewServer(mux)
|
|
defer server.Close()
|
|
|
|
client, _ := NewClient(server.URL, nil)
|
|
reqBody := &JobSubmitReq{
|
|
Script: Ptr("#!/bin/bash\necho hello"),
|
|
Job: &JobDescMsg{
|
|
Name: Ptr("test-submit"),
|
|
},
|
|
}
|
|
resp, _, err := client.Jobs.SubmitJob(context.Background(), reqBody)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if resp == nil {
|
|
t.Fatal("expected non-nil response")
|
|
}
|
|
if resp.JobID == nil || *resp.JobID != 100 {
|
|
t.Errorf("expected job_id=100, got %v", resp.JobID)
|
|
}
|
|
}
|
|
|
|
func TestJobsService_GetJobs_Error(t *testing.T) {
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("/slurm/v0.0.40/jobs", func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
fmt.Fprint(w, `{"errors": [{"error": "internal error"}]}`)
|
|
})
|
|
server := httptest.NewServer(mux)
|
|
defer server.Close()
|
|
|
|
client, _ := NewClient(server.URL, nil)
|
|
_, _, err := client.Jobs.GetJobs(context.Background(), nil)
|
|
if err == nil {
|
|
t.Fatal("expected error for 500 response")
|
|
}
|
|
if !strings.Contains(err.Error(), "500") {
|
|
t.Errorf("expected error to contain 500, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestJobsService_GetJob_Error(t *testing.T) {
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("/slurm/v0.0.40/job/999", func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
fmt.Fprint(w, `{"errors": [{"error": "job not found"}]}`)
|
|
})
|
|
server := httptest.NewServer(mux)
|
|
defer server.Close()
|
|
|
|
client, _ := NewClient(server.URL, nil)
|
|
_, _, err := client.Jobs.GetJob(context.Background(), "999", nil)
|
|
if err == nil {
|
|
t.Fatal("expected error for 404 response")
|
|
}
|
|
}
|
|
|
|
func TestJobsService_DeleteJob_NoOptions(t *testing.T) {
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("/slurm/v0.0.40/job/42", func(w http.ResponseWriter, r *http.Request) {
|
|
testMethod(t, r, "DELETE")
|
|
q := r.URL.Query()
|
|
if len(q) != 0 {
|
|
t.Errorf("expected no query params, got %v", q)
|
|
}
|
|
fmt.Fprint(w, `{}`)
|
|
})
|
|
server := httptest.NewServer(mux)
|
|
defer server.Close()
|
|
|
|
client, _ := NewClient(server.URL, nil)
|
|
resp, _, err := client.Jobs.DeleteJob(context.Background(), "42", nil)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if resp == nil {
|
|
t.Fatal("expected non-nil response")
|
|
}
|
|
}
|
|
|
|
func TestJobsService_GetJobPathEscaping(t *testing.T) {
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("/slurm/v0.0.40/job/", func(w http.ResponseWriter, r *http.Request) {
|
|
testMethod(t, r, "GET")
|
|
parts := strings.Split(r.URL.Path, "/")
|
|
jobID := parts[len(parts)-1]
|
|
if jobID != "123" {
|
|
t.Errorf("expected job ID 123, got %s", jobID)
|
|
}
|
|
fmt.Fprint(w, `{"jobs": [{"job_id": 123}]}`)
|
|
})
|
|
server := httptest.NewServer(mux)
|
|
defer server.Close()
|
|
|
|
client, _ := NewClient(server.URL, nil)
|
|
resp, _, err := client.Jobs.GetJob(context.Background(), "123", nil)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if resp == nil {
|
|
t.Fatal("expected non-nil response")
|
|
}
|
|
}
|
|
|
|
func TestJobsService_GetJobsWithURLQuery(t *testing.T) {
|
|
var capturedQuery url.Values
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("/slurm/v0.0.40/jobs", func(w http.ResponseWriter, r *http.Request) {
|
|
capturedQuery = r.URL.Query()
|
|
testMethod(t, r, "GET")
|
|
fmt.Fprint(w, `{"jobs": []}`)
|
|
})
|
|
server := httptest.NewServer(mux)
|
|
defer server.Close()
|
|
|
|
client, _ := NewClient(server.URL, nil)
|
|
opts := &GetJobsOptions{
|
|
UpdateTime: Ptr("1700000000"),
|
|
}
|
|
_, _, err := client.Jobs.GetJobs(context.Background(), opts)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if capturedQuery.Get("update_time") != "1700000000" {
|
|
t.Errorf("expected update_time=1700000000, got %s", capturedQuery.Get("update_time"))
|
|
}
|
|
}
|