From f64e0dd8af118251aa36c524ab07b2255aa5c1c3 Mon Sep 17 00:00:00 2001 From: dailz Date: Wed, 8 Apr 2026 21:33:58 +0800 Subject: [PATCH] feat(slurmdb): add AccountsService Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- internal/slurm/slurmdb_accounts.go | 136 +++++++++++++++++ internal/slurm/slurmdb_accounts_test.go | 185 ++++++++++++++++++++++++ 2 files changed, 321 insertions(+) create mode 100644 internal/slurm/slurmdb_accounts.go create mode 100644 internal/slurm/slurmdb_accounts_test.go diff --git a/internal/slurm/slurmdb_accounts.go b/internal/slurm/slurmdb_accounts.go new file mode 100644 index 0000000..7f33fbe --- /dev/null +++ b/internal/slurm/slurmdb_accounts.go @@ -0,0 +1,136 @@ +package slurm + +import ( + "context" + "fmt" + "net/url" +) + +// GetAccountsOptions specifies optional parameters for GetAccounts and GetAccount. +type GetAccountsOptions struct { + Description *string `url:"description,omitempty"` + WithAssocs *string `url:"with_assocs,omitempty"` + WithCoords *string `url:"with_coords,omitempty"` + WithDeleted *string `url:"with_deleted,omitempty"` +} + +// GetAccounts lists all accounts. +func (s *SlurmdbAccountsService) GetAccounts(ctx context.Context, opts *GetAccountsOptions) (*OpenapiAccountsResp, *Response, error) { + path := "slurmdb/v0.0.40/accounts" + req, err := s.client.NewRequest("GET", path, nil) + if err != nil { + return nil, nil, err + } + + if opts != nil { + u, parseErr := url.Parse(req.URL.String()) + if parseErr != nil { + return nil, nil, parseErr + } + q := u.Query() + if opts.Description != nil { + q.Set("description", *opts.Description) + } + if opts.WithAssocs != nil { + q.Set("with_assocs", *opts.WithAssocs) + } + if opts.WithCoords != nil { + q.Set("with_coords", *opts.WithCoords) + } + if opts.WithDeleted != nil { + q.Set("with_deleted", *opts.WithDeleted) + } + u.RawQuery = q.Encode() + req.URL = u + } + + var result OpenapiAccountsResp + resp, err := s.client.Do(ctx, req, &result) + if err != nil { + return nil, resp, err + } + return &result, resp, nil +} + +// GetAccount gets a single account by name. +func (s *SlurmdbAccountsService) GetAccount(ctx context.Context, accountName string, opts *GetAccountsOptions) (*OpenapiAccountsResp, *Response, error) { + path := fmt.Sprintf("slurmdb/v0.0.40/account/%s", accountName) + req, err := s.client.NewRequest("GET", path, nil) + if err != nil { + return nil, nil, err + } + + if opts != nil { + u, parseErr := url.Parse(req.URL.String()) + if parseErr != nil { + return nil, nil, parseErr + } + q := u.Query() + if opts.WithAssocs != nil { + q.Set("with_assocs", *opts.WithAssocs) + } + if opts.WithCoords != nil { + q.Set("with_coords", *opts.WithCoords) + } + if opts.WithDeleted != nil { + q.Set("with_deleted", *opts.WithDeleted) + } + u.RawQuery = q.Encode() + req.URL = u + } + + var result OpenapiAccountsResp + resp, err := s.client.Do(ctx, req, &result) + if err != nil { + return nil, resp, err + } + return &result, resp, nil +} + +// PostAccounts updates accounts. +func (s *SlurmdbAccountsService) PostAccounts(ctx context.Context, body *OpenapiAccountsResp) (*OpenapiAccountsResp, *Response, error) { + path := "slurmdb/v0.0.40/accounts" + req, err := s.client.NewRequest("POST", path, body) + if err != nil { + return nil, nil, err + } + + var result OpenapiAccountsResp + resp, err := s.client.Do(ctx, req, &result) + if err != nil { + return nil, resp, err + } + return &result, resp, nil +} + +// PostAccountsAssociation adds accounts with conditional association. +func (s *SlurmdbAccountsService) PostAccountsAssociation(ctx context.Context, body *OpenapiAccountsAddCondResp) (*OpenapiAccountsAddCondRespStr, *Response, error) { + path := "slurmdb/v0.0.40/accounts_association" + req, err := s.client.NewRequest("POST", path, body) + if err != nil { + return nil, nil, err + } + + var result OpenapiAccountsAddCondRespStr + resp, err := s.client.Do(ctx, req, &result) + if err != nil { + return nil, resp, err + } + return &result, resp, nil +} + +// DeleteAccount deletes an account by name. +func (s *SlurmdbAccountsService) DeleteAccount(ctx context.Context, accountName string) (*OpenapiAccountsRemovedResp, *Response, error) { + path := fmt.Sprintf("slurmdb/v0.0.40/account/%s", accountName) + req, err := s.client.NewRequest("DELETE", path, nil) + if err != nil { + return nil, nil, err + } + + var result OpenapiAccountsRemovedResp + resp, err := s.client.Do(ctx, req, &result) + if err != nil { + return nil, resp, err + } + return &result, resp, nil +} diff --git a/internal/slurm/slurmdb_accounts_test.go b/internal/slurm/slurmdb_accounts_test.go new file mode 100644 index 0000000..b6c6240 --- /dev/null +++ b/internal/slurm/slurmdb_accounts_test.go @@ -0,0 +1,185 @@ +package slurm + +import ( + "context" + "fmt" + "net/http" + "net/http/httptest" + "strings" + "testing" +) + +func TestSlurmdbAccountsService_GetAccounts(t *testing.T) { + mux := http.NewServeMux() + mux.HandleFunc("/slurmdb/v0.0.40/accounts", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{"accounts": []}`) + }) + server := httptest.NewServer(mux) + defer server.Close() + + client, _ := NewClient(server.URL, nil) + resp, _, err := client.SlurmdbAccounts.GetAccounts(context.Background(), nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if resp == nil { + t.Fatal("expected non-nil response") + } + if len(resp.Accounts) != 0 { + t.Errorf("expected empty accounts, got %d", len(resp.Accounts)) + } +} + +func TestSlurmdbAccountsService_GetAccounts_WithOptions(t *testing.T) { + mux := http.NewServeMux() + mux.HandleFunc("/slurmdb/v0.0.40/accounts", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + q := r.URL.Query() + if q.Get("with_deleted") != "true" { + t.Errorf("expected with_deleted=true, got %s", q.Get("with_deleted")) + } + if q.Get("with_assocs") != "true" { + t.Errorf("expected with_assocs=true, got %s", q.Get("with_assocs")) + } + if q.Get("with_coords") != "true" { + t.Errorf("expected with_coords=true, got %s", q.Get("with_coords")) + } + if q.Get("description") != "test" { + t.Errorf("expected description=test, got %s", q.Get("description")) + } + fmt.Fprint(w, `{"accounts": []}`) + }) + server := httptest.NewServer(mux) + defer server.Close() + + client, _ := NewClient(server.URL, nil) + opts := &GetAccountsOptions{ + Description: Ptr("test"), + WithDeleted: Ptr("true"), + WithAssocs: Ptr("true"), + WithCoords: Ptr("true"), + } + resp, _, err := client.SlurmdbAccounts.GetAccounts(context.Background(), opts) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if resp == nil { + t.Fatal("expected non-nil response") + } +} + +func TestSlurmdbAccountsService_GetAccount(t *testing.T) { + mux := http.NewServeMux() + mux.HandleFunc("/slurmdb/v0.0.40/account/testacct", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{"accounts": [{"name": "testacct"}]}`) + }) + server := httptest.NewServer(mux) + defer server.Close() + + client, _ := NewClient(server.URL, nil) + resp, _, err := client.SlurmdbAccounts.GetAccount(context.Background(), "testacct", nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if resp == nil { + t.Fatal("expected non-nil response") + } + if len(resp.Accounts) != 1 { + t.Fatalf("expected 1 account, got %d", len(resp.Accounts)) + } + if resp.Accounts[0].Name == nil || *resp.Accounts[0].Name != "testacct" { + t.Errorf("expected name=testacct, got %v", resp.Accounts[0].Name) + } +} + +func TestSlurmdbAccountsService_PostAccounts(t *testing.T) { + mux := http.NewServeMux() + mux.HandleFunc("/slurmdb/v0.0.40/accounts", 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, `{"accounts": []}`) + }) + server := httptest.NewServer(mux) + defer server.Close() + + client, _ := NewClient(server.URL, nil) + body := &OpenapiAccountsResp{} + resp, _, err := client.SlurmdbAccounts.PostAccounts(context.Background(), body) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if resp == nil { + t.Fatal("expected non-nil response") + } +} + +func TestSlurmdbAccountsService_PostAccountsAssociation(t *testing.T) { + mux := http.NewServeMux() + mux.HandleFunc("/slurmdb/v0.0.40/accounts_association", 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, `{"added_accounts": "acct1,acct2"}`) + }) + server := httptest.NewServer(mux) + defer server.Close() + + client, _ := NewClient(server.URL, nil) + body := &OpenapiAccountsAddCondResp{} + resp, _, err := client.SlurmdbAccounts.PostAccountsAssociation(context.Background(), body) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if resp == nil { + t.Fatal("expected non-nil response") + } + if resp.AddedAccounts == nil || *resp.AddedAccounts != "acct1,acct2" { + t.Errorf("expected added_accounts=acct1,acct2, got %v", resp.AddedAccounts) + } +} + +func TestSlurmdbAccountsService_DeleteAccount(t *testing.T) { + mux := http.NewServeMux() + mux.HandleFunc("/slurmdb/v0.0.40/account/testacct", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + fmt.Fprint(w, `{"removed_accounts": ["testacct"]}`) + }) + server := httptest.NewServer(mux) + defer server.Close() + + client, _ := NewClient(server.URL, nil) + resp, _, err := client.SlurmdbAccounts.DeleteAccount(context.Background(), "testacct") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if resp == nil { + t.Fatal("expected non-nil response") + } + if len(resp.RemovedAccounts) != 1 || resp.RemovedAccounts[0] != "testacct" { + t.Errorf("expected removed_accounts=[testacct], got %v", resp.RemovedAccounts) + } +} + +func TestSlurmdbAccountsService_GetAccount_Error(t *testing.T) { + mux := http.NewServeMux() + mux.HandleFunc("/slurmdb/v0.0.40/account/nonexistent", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotFound) + fmt.Fprint(w, `{"errors": [{"error": "account not found"}]}`) + }) + server := httptest.NewServer(mux) + defer server.Close() + + client, _ := NewClient(server.URL, nil) + _, _, err := client.SlurmdbAccounts.GetAccount(context.Background(), "nonexistent", nil) + if err == nil { + t.Fatal("expected error for 404 response") + } + if !strings.Contains(err.Error(), "404") { + t.Errorf("expected error to contain 404, got %v", err) + } +}