diff --git a/internal/slurm/slurmdb_users.go b/internal/slurm/slurmdb_users.go new file mode 100644 index 0000000..a0b6147 --- /dev/null +++ b/internal/slurm/slurmdb_users.go @@ -0,0 +1,155 @@ +package slurm + +import ( + "context" + "fmt" + "net/url" +) + +// GetUsersOptions specifies optional parameters for GetUsers and GetUser. +type GetUsersOptions struct { + AdminLevel *string `url:"admin_level,omitempty"` + DefaultAccount *string `url:"default_account,omitempty"` + DefaultWckey *string `url:"default_wckey,omitempty"` + WithAssocs *string `url:"with_assocs,omitempty"` + WithCoords *string `url:"with_coords,omitempty"` + WithDeleted *string `url:"with_deleted,omitempty"` + WithWckeys *string `url:"with_wckeys,omitempty"` + WithoutDefaults *string `url:"without_defaults,omitempty"` +} + +// GetUsers lists all users. +func (s *SlurmdbUsersService) GetUsers(ctx context.Context, opts *GetUsersOptions) (*OpenapiUsersResp, *Response, error) { + path := "slurmdb/v0.0.40/users" + 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.AdminLevel != nil { + q.Set("admin_level", *opts.AdminLevel) + } + if opts.DefaultAccount != nil { + q.Set("default_account", *opts.DefaultAccount) + } + if opts.DefaultWckey != nil { + q.Set("default_wckey", *opts.DefaultWckey) + } + 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) + } + if opts.WithWckeys != nil { + q.Set("with_wckeys", *opts.WithWckeys) + } + if opts.WithoutDefaults != nil { + q.Set("without_defaults", *opts.WithoutDefaults) + } + u.RawQuery = q.Encode() + req.URL = u + } + + var result OpenapiUsersResp + resp, err := s.client.Do(ctx, req, &result) + if err != nil { + return nil, resp, err + } + return &result, resp, nil +} + +// GetUser gets a single user by name. +func (s *SlurmdbUsersService) GetUser(ctx context.Context, userName string, opts *GetUsersOptions) (*OpenapiUsersResp, *Response, error) { + path := fmt.Sprintf("slurmdb/v0.0.40/user/%s", userName) + 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.WithDeleted != nil { + q.Set("with_deleted", *opts.WithDeleted) + } + if opts.WithAssocs != nil { + q.Set("with_assocs", *opts.WithAssocs) + } + if opts.WithCoords != nil { + q.Set("with_coords", *opts.WithCoords) + } + if opts.WithWckeys != nil { + q.Set("with_wckeys", *opts.WithWckeys) + } + u.RawQuery = q.Encode() + req.URL = u + } + + var result OpenapiUsersResp + resp, err := s.client.Do(ctx, req, &result) + if err != nil { + return nil, resp, err + } + return &result, resp, nil +} + +// PostUsers updates users. +func (s *SlurmdbUsersService) PostUsers(ctx context.Context, body *OpenapiUsersResp) (*OpenapiUsersResp, *Response, error) { + path := "slurmdb/v0.0.40/users" + req, err := s.client.NewRequest("POST", path, body) + if err != nil { + return nil, nil, err + } + + var result OpenapiUsersResp + resp, err := s.client.Do(ctx, req, &result) + if err != nil { + return nil, resp, err + } + return &result, resp, nil +} + +// PostUsersAssociation adds users with conditional association. +func (s *SlurmdbUsersService) PostUsersAssociation(ctx context.Context, body *OpenapiUsersAddCondResp) (*OpenapiUsersAddCondRespStr, *Response, error) { + path := "slurmdb/v0.0.40/users_association" + req, err := s.client.NewRequest("POST", path, body) + if err != nil { + return nil, nil, err + } + + var result OpenapiUsersAddCondRespStr + resp, err := s.client.Do(ctx, req, &result) + if err != nil { + return nil, resp, err + } + return &result, resp, nil +} + +// DeleteUser deletes a user by name. +func (s *SlurmdbUsersService) DeleteUser(ctx context.Context, userName string) (*OpenapiResp, *Response, error) { + path := fmt.Sprintf("slurmdb/v0.0.40/user/%s", userName) + req, err := s.client.NewRequest("DELETE", 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 +} diff --git a/internal/slurm/slurmdb_users_test.go b/internal/slurm/slurmdb_users_test.go new file mode 100644 index 0000000..1d2e342 --- /dev/null +++ b/internal/slurm/slurmdb_users_test.go @@ -0,0 +1,160 @@ +package slurm + +import ( + "context" + "fmt" + "net/http" + "net/http/httptest" + "strings" + "testing" +) + +func TestSlurmdbUsersService_GetUsers(t *testing.T) { + mux := http.NewServeMux() + mux.HandleFunc("/slurmdb/v0.0.40/users", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{"users": [{"name": "testuser"}]}`) + }) + server := httptest.NewServer(mux) + defer server.Close() + + client, _ := NewClient(server.URL, nil) + resp, _, err := client.SlurmdbUsers.GetUsers(context.Background(), nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if resp == nil { + t.Fatal("expected non-nil response") + } +} + +func TestSlurmdbUsersService_GetUsersWithOptions(t *testing.T) { + mux := http.NewServeMux() + mux.HandleFunc("/slurmdb/v0.0.40/users", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + if r.URL.Query().Get("with_deleted") != "true" { + t.Error("expected with_deleted=true query param") + } + if r.URL.Query().Get("with_assocs") != "true" { + t.Error("expected with_assocs=true query param") + } + fmt.Fprint(w, `{"users": [{"name": "testuser"}]}`) + }) + server := httptest.NewServer(mux) + defer server.Close() + + client, _ := NewClient(server.URL, nil) + deleted := "true" + assocs := "true" + opts := &GetUsersOptions{WithDeleted: &deleted, WithAssocs: &assocs} + resp, _, err := client.SlurmdbUsers.GetUsers(context.Background(), opts) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if resp == nil { + t.Fatal("expected non-nil response") + } +} + +func TestSlurmdbUsersService_GetUser(t *testing.T) { + mux := http.NewServeMux() + mux.HandleFunc("/slurmdb/v0.0.40/user/testuser", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{"users": [{"name": "testuser"}]}`) + }) + server := httptest.NewServer(mux) + defer server.Close() + + client, _ := NewClient(server.URL, nil) + resp, _, err := client.SlurmdbUsers.GetUser(context.Background(), "testuser", nil) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if resp == nil { + t.Fatal("expected non-nil response") + } +} + +func TestSlurmdbUsersService_PostUsers(t *testing.T) { + mux := http.NewServeMux() + mux.HandleFunc("/slurmdb/v0.0.40/users", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "POST") + fmt.Fprint(w, `{"users": [{"name": "testuser"}]}`) + }) + server := httptest.NewServer(mux) + defer server.Close() + + client, _ := NewClient(server.URL, nil) + body := &OpenapiUsersResp{} + resp, _, err := client.SlurmdbUsers.PostUsers(context.Background(), body) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if resp == nil { + t.Fatal("expected non-nil response") + } +} + +func TestSlurmdbUsersService_PostUsersAssociation(t *testing.T) { + mux := http.NewServeMux() + mux.HandleFunc("/slurmdb/v0.0.40/users_association", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "POST") + fmt.Fprint(w, `{"added_users": "user1,user2"}`) + }) + server := httptest.NewServer(mux) + defer server.Close() + + client, _ := NewClient(server.URL, nil) + body := &OpenapiUsersAddCondResp{} + resp, _, err := client.SlurmdbUsers.PostUsersAssociation(context.Background(), body) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if resp == nil { + t.Fatal("expected non-nil response") + } + if resp.AddedUsers == nil { + t.Fatal("expected non-nil AddedUsers") + } + if *resp.AddedUsers != "user1,user2" { + t.Errorf("expected added_users 'user1,user2', got %s", *resp.AddedUsers) + } +} + +func TestSlurmdbUsersService_DeleteUser(t *testing.T) { + mux := http.NewServeMux() + mux.HandleFunc("/slurmdb/v0.0.40/user/testuser", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + fmt.Fprint(w, `{"meta": {"plugin": {"type": "openapi/v0.0.40"}}}`) + }) + server := httptest.NewServer(mux) + defer server.Close() + + client, _ := NewClient(server.URL, nil) + resp, _, err := client.SlurmdbUsers.DeleteUser(context.Background(), "testuser") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if resp == nil { + t.Fatal("expected non-nil response") + } +} + +func TestSlurmdbUsersService_GetUsers_Error(t *testing.T) { + mux := http.NewServeMux() + mux.HandleFunc("/slurmdb/v0.0.40/users", 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.SlurmdbUsers.GetUsers(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) + } +}