feat: 添加 Diag/Ping/Licenses/Reconfigure 类型和对应服务
包含 StatsMsg(含调度和回填统计)、ControllerPing、License 等类型。实现 4 个服务:DiagService.GetDiag、PingService.Ping、LicensesService.GetLicenses、ReconfigureService.Reconfigure。 Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
67
internal/slurm/slurm_diag.go
Normal file
67
internal/slurm/slurm_diag.go
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
package slurm
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
// GetDiag returns slurm diagnostics information.
|
||||||
|
func (s *DiagService) GetDiag(ctx context.Context) (*OpenapiDiagResp, *Response, error) {
|
||||||
|
path := "slurm/v0.0.40/diag"
|
||||||
|
req, err := s.client.NewRequest("GET", path, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result OpenapiDiagResp
|
||||||
|
resp, err := s.client.Do(ctx, req, &result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
return &result, resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ping returns slurm controller ping information.
|
||||||
|
func (s *PingService) Ping(ctx context.Context) (*OpenapiPingArrayResp, *Response, error) {
|
||||||
|
path := "slurm/v0.0.40/ping"
|
||||||
|
req, err := s.client.NewRequest("GET", path, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result OpenapiPingArrayResp
|
||||||
|
resp, err := s.client.Do(ctx, req, &result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
return &result, resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLicenses returns slurm license information.
|
||||||
|
func (s *LicensesService) GetLicenses(ctx context.Context) (*OpenapiLicensesResp, *Response, error) {
|
||||||
|
path := "slurm/v0.0.40/licenses"
|
||||||
|
req, err := s.client.NewRequest("GET", path, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result OpenapiLicensesResp
|
||||||
|
resp, err := s.client.Do(ctx, req, &result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
return &result, resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reconfigure requests slurm reconfigure.
|
||||||
|
func (s *ReconfigureService) Reconfigure(ctx context.Context) (*OpenapiResp, *Response, error) {
|
||||||
|
path := "slurm/v0.0.40/reconfigure"
|
||||||
|
req, err := s.client.NewRequest("GET", path, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result OpenapiResp
|
||||||
|
resp, err := s.client.Do(ctx, req, &result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
return &result, resp, nil
|
||||||
|
}
|
||||||
162
internal/slurm/slurm_diag_test.go
Normal file
162
internal/slurm/slurm_diag_test.go
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
package slurm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDiagService_GetDiag(t *testing.T) {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/slurm/v0.0.40/diag", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
testMethod(t, r, "GET")
|
||||||
|
fmt.Fprint(w, `{"statistics": {"parts": 1}, "meta": {"plugin": {"type": "openapi/slurmctld"}}}`)
|
||||||
|
})
|
||||||
|
server := httptest.NewServer(mux)
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
client, _ := NewClient(server.URL, nil)
|
||||||
|
resp, _, err := client.Diag.GetDiag(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if resp == nil {
|
||||||
|
t.Fatal("expected non-nil response")
|
||||||
|
}
|
||||||
|
if resp.Statistics == nil {
|
||||||
|
t.Fatal("expected non-nil statistics")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDiagService_GetDiag_Error(t *testing.T) {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/slurm/v0.0.40/diag", 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.Diag.GetDiag(context.Background())
|
||||||
|
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 TestPingService_Ping(t *testing.T) {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/slurm/v0.0.40/ping", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
testMethod(t, r, "GET")
|
||||||
|
fmt.Fprint(w, `{"pings": [{"hostname": "slurmctl", "pinged": "UP", "latency": 100, "mode": "primary"}]}`)
|
||||||
|
})
|
||||||
|
server := httptest.NewServer(mux)
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
client, _ := NewClient(server.URL, nil)
|
||||||
|
resp, _, err := client.Ping.Ping(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if resp == nil {
|
||||||
|
t.Fatal("expected non-nil response")
|
||||||
|
}
|
||||||
|
if len(resp.Pings) != 1 {
|
||||||
|
t.Errorf("expected 1 ping, got %d", len(resp.Pings))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPingService_Ping_Error(t *testing.T) {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/slurm/v0.0.40/ping", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusServiceUnavailable)
|
||||||
|
fmt.Fprint(w, `{"errors": [{"error": "service unavailable"}]}`)
|
||||||
|
})
|
||||||
|
server := httptest.NewServer(mux)
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
client, _ := NewClient(server.URL, nil)
|
||||||
|
_, _, err := client.Ping.Ping(context.Background())
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected error for 503 response")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLicensesService_GetLicenses(t *testing.T) {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/slurm/v0.0.40/licenses", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
testMethod(t, r, "GET")
|
||||||
|
fmt.Fprint(w, `{"licenses": [{"LicenseName": "matlab", "Total": 10, "Used": 3, "Free": 7, "Remote": false}]}`)
|
||||||
|
})
|
||||||
|
server := httptest.NewServer(mux)
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
client, _ := NewClient(server.URL, nil)
|
||||||
|
resp, _, err := client.Licenses.GetLicenses(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if resp == nil {
|
||||||
|
t.Fatal("expected non-nil response")
|
||||||
|
}
|
||||||
|
if len(resp.Licenses) != 1 {
|
||||||
|
t.Errorf("expected 1 license, got %d", len(resp.Licenses))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLicensesService_GetLicenses_Error(t *testing.T) {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/slurm/v0.0.40/licenses", 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.Licenses.GetLicenses(context.Background())
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected error for 500 response")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReconfigureService_Reconfigure(t *testing.T) {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/slurm/v0.0.40/reconfigure", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
testMethod(t, r, "GET")
|
||||||
|
fmt.Fprint(w, `{}`)
|
||||||
|
})
|
||||||
|
server := httptest.NewServer(mux)
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
client, _ := NewClient(server.URL, nil)
|
||||||
|
resp, _, err := client.Reconfigure.Reconfigure(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if resp == nil {
|
||||||
|
t.Fatal("expected non-nil response")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReconfigureService_Reconfigure_Error(t *testing.T) {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/slurm/v0.0.40/reconfigure", 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.Reconfigure.Reconfigure(context.Background())
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected error for 500 response")
|
||||||
|
}
|
||||||
|
}
|
||||||
149
internal/slurm/types_diag.go
Normal file
149
internal/slurm/types_diag.go
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
package slurm
|
||||||
|
|
||||||
|
// ScheduleExitFields represents schedule exit fields (v0.0.40_schedule_exit_fields).
|
||||||
|
type ScheduleExitFields struct {
|
||||||
|
EndJobQueue *int32 `json:"end_job_queue,omitempty"`
|
||||||
|
DefaultQueueDepth *int32 `json:"default_queue_depth,omitempty"`
|
||||||
|
MaxJobStart *int32 `json:"max_job_start,omitempty"`
|
||||||
|
MaxRpcCnt *int32 `json:"max_rpc_cnt,omitempty"`
|
||||||
|
MaxSchedTime *int32 `json:"max_sched_time,omitempty"`
|
||||||
|
Licenses *int32 `json:"licenses,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BfExitFields represents backfill exit fields (v0.0.40_bf_exit_fields).
|
||||||
|
type BfExitFields struct {
|
||||||
|
EndJobQueue *int32 `json:"end_job_queue,omitempty"`
|
||||||
|
BfMaxJobStart *int32 `json:"bf_max_job_start,omitempty"`
|
||||||
|
BfMaxJobTest *int32 `json:"bf_max_job_test,omitempty"`
|
||||||
|
BfMaxTime *int32 `json:"bf_max_time,omitempty"`
|
||||||
|
BfNodeSpaceSize *int32 `json:"bf_node_space_size,omitempty"`
|
||||||
|
StateChanged *int32 `json:"state_changed,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// StatsMsgRpcsByTypeItem represents a single RPC stats by message type entry.
|
||||||
|
type StatsMsgRpcsByTypeItem struct {
|
||||||
|
MessageType *string `json:"message_type,omitempty"`
|
||||||
|
TypeID *int32 `json:"type_id,omitempty"`
|
||||||
|
Count *int64 `json:"count,omitempty"`
|
||||||
|
AverageTime *int64 `json:"average_time,omitempty"`
|
||||||
|
TotalTime *int64 `json:"total_time,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// StatsMsgRpcsByType represents RPC stats by message type (v0.0.40_stats_msg_rpcs_by_type).
|
||||||
|
type StatsMsgRpcsByType []StatsMsgRpcsByTypeItem
|
||||||
|
|
||||||
|
// StatsMsgRpcsByUserItem represents a single RPC stats by user entry.
|
||||||
|
type StatsMsgRpcsByUserItem struct {
|
||||||
|
User *string `json:"user,omitempty"`
|
||||||
|
UserID *int32 `json:"user_id,omitempty"`
|
||||||
|
Count *int64 `json:"count,omitempty"`
|
||||||
|
AverageTime *int64 `json:"average_time,omitempty"`
|
||||||
|
TotalTime *int64 `json:"total_time,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// StatsMsgRpcsByUser represents RPC stats by user (v0.0.40_stats_msg_rpcs_by_user).
|
||||||
|
type StatsMsgRpcsByUser []StatsMsgRpcsByUserItem
|
||||||
|
|
||||||
|
// StatsMsg represents Slurm statistics message (v0.0.40_stats_msg).
|
||||||
|
type StatsMsg struct {
|
||||||
|
PartsPacked *int32 `json:"parts_packed,omitempty"`
|
||||||
|
ReqTime *Uint64NoVal `json:"req_time,omitempty"`
|
||||||
|
ReqTimeStart *Uint64NoVal `json:"req_time_start,omitempty"`
|
||||||
|
ServerThreadCount *int32 `json:"server_thread_count,omitempty"`
|
||||||
|
AgentQueueSize *int32 `json:"agent_queue_size,omitempty"`
|
||||||
|
AgentCount *int32 `json:"agent_count,omitempty"`
|
||||||
|
AgentThreadCount *int32 `json:"agent_thread_count,omitempty"`
|
||||||
|
DbdAgentQueueSize *int32 `json:"dbd_agent_queue_size,omitempty"`
|
||||||
|
GettimeofdayLatency *int32 `json:"gettimeofday_latency,omitempty"`
|
||||||
|
ScheduleCycleMax *int32 `json:"schedule_cycle_max,omitempty"`
|
||||||
|
ScheduleCycleLast *int32 `json:"schedule_cycle_last,omitempty"`
|
||||||
|
ScheduleCycleTotal *int32 `json:"schedule_cycle_total,omitempty"`
|
||||||
|
ScheduleCycleMean *int64 `json:"schedule_cycle_mean,omitempty"`
|
||||||
|
ScheduleCycleMeanDepth *int64 `json:"schedule_cycle_mean_depth,omitempty"`
|
||||||
|
ScheduleCyclePerMinute *int64 `json:"schedule_cycle_per_minute,omitempty"`
|
||||||
|
ScheduleQueueLength *int32 `json:"schedule_queue_length,omitempty"`
|
||||||
|
ScheduleExit *ScheduleExitFields `json:"schedule_exit,omitempty"`
|
||||||
|
JobsSubmitted *int32 `json:"jobs_submitted,omitempty"`
|
||||||
|
JobsStarted *int32 `json:"jobs_started,omitempty"`
|
||||||
|
JobsCompleted *int32 `json:"jobs_completed,omitempty"`
|
||||||
|
JobsCanceled *int32 `json:"jobs_canceled,omitempty"`
|
||||||
|
JobsFailed *int32 `json:"jobs_failed,omitempty"`
|
||||||
|
JobsPending *int32 `json:"jobs_pending,omitempty"`
|
||||||
|
JobsRunning *int32 `json:"jobs_running,omitempty"`
|
||||||
|
JobStatesTs *Uint64NoVal `json:"job_states_ts,omitempty"`
|
||||||
|
BfBackfilledJobs *int32 `json:"bf_backfilled_jobs,omitempty"`
|
||||||
|
BfLastBackfilledJobs *int32 `json:"bf_last_backfilled_jobs,omitempty"`
|
||||||
|
BfBackfilledHetJobs *int32 `json:"bf_backfilled_het_jobs,omitempty"`
|
||||||
|
BfCycleCounter *int32 `json:"bf_cycle_counter,omitempty"`
|
||||||
|
BfCycleMean *int64 `json:"bf_cycle_mean,omitempty"`
|
||||||
|
BfDepthMean *int64 `json:"bf_depth_mean,omitempty"`
|
||||||
|
BfDepthMeanTry *int64 `json:"bf_depth_mean_try,omitempty"`
|
||||||
|
BfCycleSum *int64 `json:"bf_cycle_sum,omitempty"`
|
||||||
|
BfCycleLast *int32 `json:"bf_cycle_last,omitempty"`
|
||||||
|
BfLastDepth *int32 `json:"bf_last_depth,omitempty"`
|
||||||
|
BfLastDepthTry *int32 `json:"bf_last_depth_try,omitempty"`
|
||||||
|
BfDepthSum *int32 `json:"bf_depth_sum,omitempty"`
|
||||||
|
BfDepthTrySum *int32 `json:"bf_depth_try_sum,omitempty"`
|
||||||
|
BfQueueLen *int32 `json:"bf_queue_len,omitempty"`
|
||||||
|
BfQueueLenMean *int64 `json:"bf_queue_len_mean,omitempty"`
|
||||||
|
BfQueueLenSum *int32 `json:"bf_queue_len_sum,omitempty"`
|
||||||
|
BfTableSize *int32 `json:"bf_table_size,omitempty"`
|
||||||
|
BfTableSizeMean *int64 `json:"bf_table_size_mean,omitempty"`
|
||||||
|
BfWhenLastCycle *Uint64NoVal `json:"bf_when_last_cycle,omitempty"`
|
||||||
|
BfActive *bool `json:"bf_active,omitempty"`
|
||||||
|
BfExit *BfExitFields `json:"bf_exit,omitempty"`
|
||||||
|
RpcsByMessageType *StatsMsgRpcsByType `json:"rpcs_by_message_type,omitempty"`
|
||||||
|
RpcsByUser *StatsMsgRpcsByUser `json:"rpcs_by_user,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ControllerPing represents a controller ping result (v0.0.40_controller_ping).
|
||||||
|
type ControllerPing struct {
|
||||||
|
Hostname *string `json:"hostname,omitempty"`
|
||||||
|
Pinged *string `json:"pinged,omitempty"`
|
||||||
|
Latency *int64 `json:"latency,omitempty"`
|
||||||
|
Mode *string `json:"mode,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ControllerPingArray represents an array of controller ping results (v0.0.40_controller_ping_array).
|
||||||
|
type ControllerPingArray []ControllerPing
|
||||||
|
|
||||||
|
// License represents Slurm license information (v0.0.40_license).
|
||||||
|
type License struct {
|
||||||
|
LicenseName *string `json:"LicenseName,omitempty"`
|
||||||
|
Total *int32 `json:"Total,omitempty"`
|
||||||
|
Used *int32 `json:"Used,omitempty"`
|
||||||
|
Free *int32 `json:"Free,omitempty"`
|
||||||
|
Remote *bool `json:"Remote,omitempty"`
|
||||||
|
Reserved *int32 `json:"Reserved,omitempty"`
|
||||||
|
LastConsumed *int32 `json:"LastConsumed,omitempty"`
|
||||||
|
LastDeficit *int32 `json:"LastDeficit,omitempty"`
|
||||||
|
LastUpdate *int64 `json:"LastUpdate,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Licenses represents a list of licenses (v0.0.40_licenses).
|
||||||
|
type Licenses []License
|
||||||
|
|
||||||
|
// OpenapiDiagResp represents the diag API response (v0.0.40_openapi_diag_resp).
|
||||||
|
type OpenapiDiagResp struct {
|
||||||
|
Statistics *StatsMsg `json:"statistics,omitempty"`
|
||||||
|
Meta *OpenapiMeta `json:"meta,omitempty"`
|
||||||
|
Errors OpenapiErrors `json:"errors,omitempty"`
|
||||||
|
Warnings OpenapiWarnings `json:"warnings,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenapiPingArrayResp represents the ping API response (v0.0.40_openapi_ping_array_resp).
|
||||||
|
type OpenapiPingArrayResp struct {
|
||||||
|
Pings ControllerPingArray `json:"pings,omitempty"`
|
||||||
|
Meta *OpenapiMeta `json:"meta,omitempty"`
|
||||||
|
Errors OpenapiErrors `json:"errors,omitempty"`
|
||||||
|
Warnings OpenapiWarnings `json:"warnings,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenapiLicensesResp represents the licenses API response (v0.0.40_openapi_licenses_resp).
|
||||||
|
type OpenapiLicensesResp struct {
|
||||||
|
Licenses Licenses `json:"licenses,omitempty"`
|
||||||
|
LastUpdate *Uint64NoVal `json:"last_update,omitempty"`
|
||||||
|
Meta *OpenapiMeta `json:"meta,omitempty"`
|
||||||
|
Errors OpenapiErrors `json:"errors,omitempty"`
|
||||||
|
Warnings OpenapiWarnings `json:"warnings,omitempty"`
|
||||||
|
}
|
||||||
309
internal/slurm/types_diag_test.go
Normal file
309
internal/slurm/types_diag_test.go
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
package slurm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestStatsMsgRoundTrip(t *testing.T) {
|
||||||
|
orig := StatsMsg{
|
||||||
|
PartsPacked: Ptr(int32(1)),
|
||||||
|
ReqTime: &Uint64NoVal{Set: Ptr(true), Number: Ptr(int64(1700000000))},
|
||||||
|
ReqTimeStart: &Uint64NoVal{Set: Ptr(true), Number: Ptr(int64(1699999999))},
|
||||||
|
ServerThreadCount: Ptr(int32(4)),
|
||||||
|
AgentQueueSize: Ptr(int32(0)),
|
||||||
|
AgentCount: Ptr(int32(10)),
|
||||||
|
AgentThreadCount: Ptr(int32(4)),
|
||||||
|
DbdAgentQueueSize: Ptr(int32(0)),
|
||||||
|
GettimeofdayLatency: Ptr(int32(1)),
|
||||||
|
ScheduleCycleMax: Ptr(int32(100)),
|
||||||
|
ScheduleCycleLast: Ptr(int32(5)),
|
||||||
|
ScheduleCycleTotal: Ptr(int32(500)),
|
||||||
|
ScheduleCycleMean: Ptr(int64(10)),
|
||||||
|
ScheduleCycleMeanDepth: Ptr(int64(3)),
|
||||||
|
ScheduleCyclePerMinute: Ptr(int64(60)),
|
||||||
|
ScheduleQueueLength: Ptr(int32(42)),
|
||||||
|
ScheduleExit: &ScheduleExitFields{
|
||||||
|
EndJobQueue: Ptr(int32(1)),
|
||||||
|
DefaultQueueDepth: Ptr(int32(100)),
|
||||||
|
MaxJobStart: Ptr(int32(0)),
|
||||||
|
MaxRpcCnt: Ptr(int32(0)),
|
||||||
|
MaxSchedTime: Ptr(int32(0)),
|
||||||
|
Licenses: Ptr(int32(0)),
|
||||||
|
},
|
||||||
|
JobsSubmitted: Ptr(int32(1000)),
|
||||||
|
JobsStarted: Ptr(int32(900)),
|
||||||
|
JobsCompleted: Ptr(int32(850)),
|
||||||
|
JobsCanceled: Ptr(int32(20)),
|
||||||
|
JobsFailed: Ptr(int32(5)),
|
||||||
|
JobsPending: Ptr(int32(30)),
|
||||||
|
JobsRunning: Ptr(int32(45)),
|
||||||
|
JobStatesTs: &Uint64NoVal{Set: Ptr(true), Number: Ptr(int64(1700000000))},
|
||||||
|
BfBackfilledJobs: Ptr(int32(200)),
|
||||||
|
BfLastBackfilledJobs: Ptr(int32(5)),
|
||||||
|
BfBackfilledHetJobs: Ptr(int32(0)),
|
||||||
|
BfCycleCounter: Ptr(int32(500)),
|
||||||
|
BfCycleMean: Ptr(int64(2)),
|
||||||
|
BfDepthMean: Ptr(int64(10)),
|
||||||
|
BfDepthMeanTry: Ptr(int64(8)),
|
||||||
|
BfCycleSum: Ptr(int64(1000)),
|
||||||
|
BfCycleLast: Ptr(int32(3)),
|
||||||
|
BfLastDepth: Ptr(int32(15)),
|
||||||
|
BfLastDepthTry: Ptr(int32(12)),
|
||||||
|
BfDepthSum: Ptr(int32(5000)),
|
||||||
|
BfDepthTrySum: Ptr(int32(4000)),
|
||||||
|
BfQueueLen: Ptr(int32(30)),
|
||||||
|
BfQueueLenMean: Ptr(int64(25)),
|
||||||
|
BfQueueLenSum: Ptr(int32(15000)),
|
||||||
|
BfTableSize: Ptr(int32(500)),
|
||||||
|
BfTableSizeMean: Ptr(int64(450)),
|
||||||
|
BfWhenLastCycle: &Uint64NoVal{Set: Ptr(true), Number: Ptr(int64(1700000050))},
|
||||||
|
BfActive: Ptr(true),
|
||||||
|
BfExit: &BfExitFields{
|
||||||
|
EndJobQueue: Ptr(int32(0)),
|
||||||
|
BfMaxJobStart: Ptr(int32(0)),
|
||||||
|
BfMaxJobTest: Ptr(int32(0)),
|
||||||
|
BfMaxTime: Ptr(int32(0)),
|
||||||
|
BfNodeSpaceSize: Ptr(int32(0)),
|
||||||
|
StateChanged: Ptr(int32(0)),
|
||||||
|
},
|
||||||
|
RpcsByMessageType: &StatsMsgRpcsByType{
|
||||||
|
{MessageType: Ptr("REQUEST_JOB_INFO"), TypeID: Ptr(int32(2001)), Count: Ptr(int64(500)), AverageTime: Ptr(int64(10)), TotalTime: Ptr(int64(5000))},
|
||||||
|
{MessageType: Ptr("REQUEST_NODE_INFO"), TypeID: Ptr(int32(2002)), Count: Ptr(int64(300)), AverageTime: Ptr(int64(5)), TotalTime: Ptr(int64(1500))},
|
||||||
|
},
|
||||||
|
RpcsByUser: &StatsMsgRpcsByUser{
|
||||||
|
{User: Ptr("root"), UserID: Ptr(int32(0)), Count: Ptr(int64(100)), AverageTime: Ptr(int64(3)), TotalTime: Ptr(int64(300))},
|
||||||
|
{User: Ptr("alice"), UserID: Ptr(int32(1001)), Count: Ptr(int64(50)), AverageTime: Ptr(int64(7)), TotalTime: Ptr(int64(350))},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
data, err := json.Marshal(orig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("marshal: %v", err)
|
||||||
|
}
|
||||||
|
var decoded StatsMsg
|
||||||
|
if err := json.Unmarshal(data, &decoded); err != nil {
|
||||||
|
t.Fatalf("unmarshal: %v", err)
|
||||||
|
}
|
||||||
|
if *decoded.PartsPacked != *orig.PartsPacked {
|
||||||
|
t.Errorf("PartsPacked: got %d, want %d", *decoded.PartsPacked, *orig.PartsPacked)
|
||||||
|
}
|
||||||
|
if *decoded.ScheduleExit.DefaultQueueDepth != *orig.ScheduleExit.DefaultQueueDepth {
|
||||||
|
t.Errorf("ScheduleExit.DefaultQueueDepth: got %d, want %d", *decoded.ScheduleExit.DefaultQueueDepth, *orig.ScheduleExit.DefaultQueueDepth)
|
||||||
|
}
|
||||||
|
if *decoded.BfActive != *orig.BfActive {
|
||||||
|
t.Errorf("BfActive: got %v, want %v", *decoded.BfActive, *orig.BfActive)
|
||||||
|
}
|
||||||
|
if len(*decoded.RpcsByMessageType) != len(*orig.RpcsByMessageType) {
|
||||||
|
t.Errorf("RpcsByMessageType length: got %d, want %d", len(*decoded.RpcsByMessageType), len(*orig.RpcsByMessageType))
|
||||||
|
}
|
||||||
|
if len(*decoded.RpcsByUser) != len(*orig.RpcsByUser) {
|
||||||
|
t.Errorf("RpcsByUser length: got %d, want %d", len(*decoded.RpcsByUser), len(*orig.RpcsByUser))
|
||||||
|
}
|
||||||
|
if *(*decoded.RpcsByMessageType)[0].MessageType != *(*orig.RpcsByMessageType)[0].MessageType {
|
||||||
|
t.Errorf("RpcsByMessageType[0].MessageType: got %s, want %s", *(*decoded.RpcsByMessageType)[0].MessageType, *(*orig.RpcsByMessageType)[0].MessageType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestScheduleExitFieldsRoundTrip(t *testing.T) {
|
||||||
|
orig := ScheduleExitFields{
|
||||||
|
EndJobQueue: Ptr(int32(1)),
|
||||||
|
DefaultQueueDepth: Ptr(int32(100)),
|
||||||
|
MaxJobStart: Ptr(int32(50)),
|
||||||
|
MaxRpcCnt: Ptr(int32(20)),
|
||||||
|
MaxSchedTime: Ptr(int32(30)),
|
||||||
|
Licenses: Ptr(int32(5)),
|
||||||
|
}
|
||||||
|
data, err := json.Marshal(orig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("marshal: %v", err)
|
||||||
|
}
|
||||||
|
var decoded ScheduleExitFields
|
||||||
|
if err := json.Unmarshal(data, &decoded); err != nil {
|
||||||
|
t.Fatalf("unmarshal: %v", err)
|
||||||
|
}
|
||||||
|
if *decoded.EndJobQueue != *orig.EndJobQueue {
|
||||||
|
t.Errorf("EndJobQueue: got %d, want %d", *decoded.EndJobQueue, *orig.EndJobQueue)
|
||||||
|
}
|
||||||
|
if *decoded.Licenses != *orig.Licenses {
|
||||||
|
t.Errorf("Licenses: got %d, want %d", *decoded.Licenses, *orig.Licenses)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBfExitFieldsRoundTrip(t *testing.T) {
|
||||||
|
orig := BfExitFields{
|
||||||
|
EndJobQueue: Ptr(int32(1)),
|
||||||
|
BfMaxJobStart: Ptr(int32(10)),
|
||||||
|
BfMaxJobTest: Ptr(int32(100)),
|
||||||
|
BfMaxTime: Ptr(int32(60)),
|
||||||
|
BfNodeSpaceSize: Ptr(int32(500)),
|
||||||
|
StateChanged: Ptr(int32(3)),
|
||||||
|
}
|
||||||
|
data, err := json.Marshal(orig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("marshal: %v", err)
|
||||||
|
}
|
||||||
|
var decoded BfExitFields
|
||||||
|
if err := json.Unmarshal(data, &decoded); err != nil {
|
||||||
|
t.Fatalf("unmarshal: %v", err)
|
||||||
|
}
|
||||||
|
if *decoded.BfMaxJobTest != *orig.BfMaxJobTest {
|
||||||
|
t.Errorf("BfMaxJobTest: got %d, want %d", *decoded.BfMaxJobTest, *orig.BfMaxJobTest)
|
||||||
|
}
|
||||||
|
if *decoded.StateChanged != *orig.StateChanged {
|
||||||
|
t.Errorf("StateChanged: got %d, want %d", *decoded.StateChanged, *orig.StateChanged)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestControllerPingRoundTrip(t *testing.T) {
|
||||||
|
orig := ControllerPing{
|
||||||
|
Hostname: Ptr("controller1"),
|
||||||
|
Pinged: Ptr("UP"),
|
||||||
|
Latency: Ptr(int64(42)),
|
||||||
|
Mode: Ptr("primary"),
|
||||||
|
}
|
||||||
|
data, err := json.Marshal(orig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("marshal: %v", err)
|
||||||
|
}
|
||||||
|
var decoded ControllerPing
|
||||||
|
if err := json.Unmarshal(data, &decoded); err != nil {
|
||||||
|
t.Fatalf("unmarshal: %v", err)
|
||||||
|
}
|
||||||
|
if *decoded.Hostname != *orig.Hostname {
|
||||||
|
t.Errorf("Hostname: got %s, want %s", *decoded.Hostname, *orig.Hostname)
|
||||||
|
}
|
||||||
|
if *decoded.Latency != *orig.Latency {
|
||||||
|
t.Errorf("Latency: got %d, want %d", *decoded.Latency, *orig.Latency)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLicenseRoundTrip(t *testing.T) {
|
||||||
|
orig := License{
|
||||||
|
LicenseName: Ptr("matlab"),
|
||||||
|
Total: Ptr(int32(100)),
|
||||||
|
Used: Ptr(int32(50)),
|
||||||
|
Free: Ptr(int32(50)),
|
||||||
|
Remote: Ptr(false),
|
||||||
|
Reserved: Ptr(int32(10)),
|
||||||
|
LastConsumed: Ptr(int32(45)),
|
||||||
|
LastDeficit: Ptr(int32(0)),
|
||||||
|
LastUpdate: Ptr(int64(1700000000)),
|
||||||
|
}
|
||||||
|
data, err := json.Marshal(orig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("marshal: %v", err)
|
||||||
|
}
|
||||||
|
var decoded License
|
||||||
|
if err := json.Unmarshal(data, &decoded); err != nil {
|
||||||
|
t.Fatalf("unmarshal: %v", err)
|
||||||
|
}
|
||||||
|
if *decoded.LicenseName != *orig.LicenseName {
|
||||||
|
t.Errorf("LicenseName: got %s, want %s", *decoded.LicenseName, *orig.LicenseName)
|
||||||
|
}
|
||||||
|
if *decoded.Total != *orig.Total {
|
||||||
|
t.Errorf("Total: got %d, want %d", *decoded.Total, *orig.Total)
|
||||||
|
}
|
||||||
|
if *decoded.Remote != *orig.Remote {
|
||||||
|
t.Errorf("Remote: got %v, want %v", *decoded.Remote, *orig.Remote)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOpenapiDiagRespRoundTrip(t *testing.T) {
|
||||||
|
orig := OpenapiDiagResp{
|
||||||
|
Statistics: &StatsMsg{
|
||||||
|
PartsPacked: Ptr(int32(1)),
|
||||||
|
ServerThreadCount: Ptr(int32(4)),
|
||||||
|
AgentCount: Ptr(int32(10)),
|
||||||
|
JobsRunning: Ptr(int32(45)),
|
||||||
|
BfActive: Ptr(true),
|
||||||
|
},
|
||||||
|
Meta: &OpenapiMeta{
|
||||||
|
Slurm: &MetaSlurm{
|
||||||
|
Version: &MetaSlurmVersion{Major: Ptr("24"), Minor: Ptr("05"), Micro: Ptr("5")},
|
||||||
|
Release: Ptr("24.05.5"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Errors: OpenapiErrors{},
|
||||||
|
Warnings: OpenapiWarnings{},
|
||||||
|
}
|
||||||
|
data, err := json.Marshal(orig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("marshal: %v", err)
|
||||||
|
}
|
||||||
|
var decoded OpenapiDiagResp
|
||||||
|
if err := json.Unmarshal(data, &decoded); err != nil {
|
||||||
|
t.Fatalf("unmarshal: %v", err)
|
||||||
|
}
|
||||||
|
if *decoded.Statistics.PartsPacked != *orig.Statistics.PartsPacked {
|
||||||
|
t.Errorf("Statistics.PartsPacked: got %d, want %d", *decoded.Statistics.PartsPacked, *orig.Statistics.PartsPacked)
|
||||||
|
}
|
||||||
|
if *decoded.Meta.Slurm.Release != *orig.Meta.Slurm.Release {
|
||||||
|
t.Errorf("Meta.Slurm.Release: got %s, want %s", *decoded.Meta.Slurm.Release, *orig.Meta.Slurm.Release)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOpenapiPingArrayRespRoundTrip(t *testing.T) {
|
||||||
|
orig := OpenapiPingArrayResp{
|
||||||
|
Pings: ControllerPingArray{
|
||||||
|
{Hostname: Ptr("ctrl1"), Pinged: Ptr("UP"), Latency: Ptr(int64(10))},
|
||||||
|
{Hostname: Ptr("ctrl2"), Pinged: Ptr("DOWN"), Latency: Ptr(int64(9999))},
|
||||||
|
},
|
||||||
|
Meta: &OpenapiMeta{
|
||||||
|
Slurm: &MetaSlurm{
|
||||||
|
Version: &MetaSlurmVersion{Major: Ptr("24"), Minor: Ptr("05"), Micro: Ptr("5")},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
data, err := json.Marshal(orig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("marshal: %v", err)
|
||||||
|
}
|
||||||
|
var decoded OpenapiPingArrayResp
|
||||||
|
if err := json.Unmarshal(data, &decoded); err != nil {
|
||||||
|
t.Fatalf("unmarshal: %v", err)
|
||||||
|
}
|
||||||
|
if len(decoded.Pings) != len(orig.Pings) {
|
||||||
|
t.Fatalf("Pings length: got %d, want %d", len(decoded.Pings), len(orig.Pings))
|
||||||
|
}
|
||||||
|
if *decoded.Pings[0].Hostname != *orig.Pings[0].Hostname {
|
||||||
|
t.Errorf("Pings[0].Hostname: got %s, want %s", *decoded.Pings[0].Hostname, *orig.Pings[0].Hostname)
|
||||||
|
}
|
||||||
|
if *decoded.Pings[1].Pinged != *orig.Pings[1].Pinged {
|
||||||
|
t.Errorf("Pings[1].Pinged: got %s, want %s", *decoded.Pings[1].Pinged, *orig.Pings[1].Pinged)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOpenapiLicensesRespRoundTrip(t *testing.T) {
|
||||||
|
orig := OpenapiLicensesResp{
|
||||||
|
Licenses: Licenses{
|
||||||
|
{LicenseName: Ptr("matlab"), Total: Ptr(int32(100)), Used: Ptr(int32(50))},
|
||||||
|
{LicenseName: Ptr("ansys"), Total: Ptr(int32(10)), Used: Ptr(int32(3))},
|
||||||
|
},
|
||||||
|
LastUpdate: &Uint64NoVal{Set: Ptr(true), Number: Ptr(int64(1700000000))},
|
||||||
|
Meta: &OpenapiMeta{
|
||||||
|
Slurm: &MetaSlurm{
|
||||||
|
Version: &MetaSlurmVersion{Major: Ptr("24"), Minor: Ptr("05"), Micro: Ptr("5")},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
data, err := json.Marshal(orig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("marshal: %v", err)
|
||||||
|
}
|
||||||
|
var decoded OpenapiLicensesResp
|
||||||
|
if err := json.Unmarshal(data, &decoded); err != nil {
|
||||||
|
t.Fatalf("unmarshal: %v", err)
|
||||||
|
}
|
||||||
|
if len(decoded.Licenses) != len(orig.Licenses) {
|
||||||
|
t.Fatalf("Licenses length: got %d, want %d", len(decoded.Licenses), len(orig.Licenses))
|
||||||
|
}
|
||||||
|
if *decoded.Licenses[0].LicenseName != *orig.Licenses[0].LicenseName {
|
||||||
|
t.Errorf("Licenses[0].LicenseName: got %s, want %s", *decoded.Licenses[0].LicenseName, *orig.Licenses[0].LicenseName)
|
||||||
|
}
|
||||||
|
if *decoded.Licenses[1].Used != *orig.Licenses[1].Used {
|
||||||
|
t.Errorf("Licenses[1].Used: got %d, want %d", *decoded.Licenses[1].Used, *orig.Licenses[1].Used)
|
||||||
|
}
|
||||||
|
if *decoded.LastUpdate.Number != *orig.LastUpdate.Number {
|
||||||
|
t.Errorf("LastUpdate.Number: got %d, want %d", *decoded.LastUpdate.Number, *orig.LastUpdate.Number)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user