diff --git a/Makefile b/Makefile index 8362410..c81fa6b 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ build: .PHONY: build test: - go test -v -cover + go test -v -cover -timeout=15m .PHONY: test clean: diff --git a/client.go b/client.go index 25716e7..4a75d7b 100644 --- a/client.go +++ b/client.go @@ -41,8 +41,9 @@ type Client struct { BOM BOMService Component ComponentService Config ConfigService - Finding FindingService Event EventService + Finding FindingService + Health HealthService LDAP LDAPService License LicenseService Metrics MetricsService @@ -93,8 +94,9 @@ func NewClient(baseURL string, options ...ClientOption) (*Client, error) { client.BOM = BOMService{client: &client} client.Component = ComponentService{client: &client} client.Config = ConfigService{client: &client} - client.Finding = FindingService{client: &client} client.Event = EventService{client: &client} + client.Finding = FindingService{client: &client} + client.Health = HealthService{client: &client} client.LDAP = LDAPService{client: &client} client.License = LicenseService{client: &client} client.Metrics = MetricsService{client: &client} @@ -193,7 +195,7 @@ func withPathParams(params map[string]string) requestOption { } for k, v := range params { - req.URL.Path = strings.Replace(req.URL.Path, fmt.Sprintf("{%s}", k), v, -1) + req.URL.Path = strings.ReplaceAll(req.URL.Path, fmt.Sprintf("{%s}", k), v) } return nil } diff --git a/component_test.go b/component_test.go index fabc8fa..1c502d3 100644 --- a/component_test.go +++ b/component_test.go @@ -69,6 +69,8 @@ func TestComponentLifecycle(t *testing.T) { // Delete { err := client.Component.Delete(context.Background(), component.UUID) + // Occassionally receives 500 response from API - https://github.com/DependencyTrack/client-go/actions/runs/20657420675/job/59312871798?pr=55 + // Due to the intermittent nature, the cause is not yet identified. require.NoError(t, err) } diff --git a/health.go b/health.go new file mode 100644 index 0000000..b0cc615 --- /dev/null +++ b/health.go @@ -0,0 +1,31 @@ +package dtrack + +import ( + "context" + "net/http" +) + +type HealthCheck struct { + Name string `json:"name"` + Status string `json:"status"` + Data interface{} `json:"data,omitempty"` +} + +type Health struct { + Status string `json:"status"` + Checks []HealthCheck `json:"checks"` +} + +type HealthService struct { + client *Client +} + +func (hs HealthService) Get(ctx context.Context) (h Health, err error) { + req, err := hs.client.newRequest(ctx, http.MethodGet, "health", withoutAuth()) + if err != nil { + return + } + + _, err = hs.client.doRequest(req, &h) + return +} diff --git a/health_test.go b/health_test.go new file mode 100644 index 0000000..51c3f9f --- /dev/null +++ b/health_test.go @@ -0,0 +1,24 @@ +package dtrack + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestHealth(t *testing.T) { + client := setUpContainer(t, testContainerOptions{}) + + health, err := client.Health.Get(context.TODO()) + require.NoError(t, err) + require.NotNil(t, health) + + require.Equal(t, "UP", health.Status) + require.Equal(t, 1, len(health.Checks)) + require.Equal(t, "database", health.Checks[0].Name) + require.Equal(t, "UP", health.Checks[0].Status) + require.NotNil(t, health.Checks[0].Data) + require.Equal(t, "UP", health.Checks[0].Data.(map[string]any)["nontx_connection_pool"]) + require.Equal(t, "UP", health.Checks[0].Data.(map[string]any)["tx_connection_pool"]) +} diff --git a/oidc.go b/oidc.go index 4c09d88..5d1faf8 100644 --- a/oidc.go +++ b/oidc.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net/http" + "net/url" "strconv" "github.com/google/uuid" @@ -28,7 +29,25 @@ type OIDCMapping struct { UUID uuid.UUID `json:"uuid"` } +type OIDCUser struct { + Username string `json:"username"` + SubjectIdentifier string `json:"subjectIdentifier"` + Email string `json:"email"` + Teams []Team `json:"teams"` + Permissions []Permission `json:"permissions"` +} + +type OIDCTokens struct { + ID string `json:"idToken"` + Access string `json:"accessToken,omitempty"` +} + func (s OIDCService) Available(ctx context.Context) (available bool, err error) { + err = s.client.assertServerVersionAtLeast("4.0.0") + if err != nil { + return + } + req, err := s.client.newRequest(ctx, http.MethodGet, "api/v1/oidc/available", withAcceptContentType("text/plain")) if err != nil { return @@ -44,22 +63,28 @@ func (s OIDCService) Available(ctx context.Context) (available bool, err error) return } -func (s OIDCService) GetAllGroups(ctx context.Context, po PageOptions) (p Page[OIDCGroup], err error) { - req, err := s.client.newRequest(ctx, http.MethodGet, "api/v1/oidc/group", withPageOptions(po)) +func (s OIDCService) GetAllGroups(ctx context.Context) (groups []OIDCGroup, err error) { + err = s.client.assertServerVersionAtLeast("4.0.0") if err != nil { return } - res, err := s.client.doRequest(req, &p.Items) + req, err := s.client.newRequest(ctx, http.MethodGet, "api/v1/oidc/group") if err != nil { return } - p.TotalCount = res.TotalCount + _, err = s.client.doRequest(req, &groups) return + } func (s OIDCService) CreateGroup(ctx context.Context, name string) (g OIDCGroup, err error) { + err = s.client.assertServerVersionAtLeast("4.0.0") + if err != nil { + return + } + req, err := s.client.newRequest(ctx, http.MethodPut, "api/v1/oidc/group", withBody(OIDCGroup{Name: name})) if err != nil { return @@ -69,6 +94,11 @@ func (s OIDCService) CreateGroup(ctx context.Context, name string) (g OIDCGroup, return } func (s OIDCService) UpdateGroup(ctx context.Context, group OIDCGroup) (g OIDCGroup, err error) { + err = s.client.assertServerVersionAtLeast("4.0.0") + if err != nil { + return + } + req, err := s.client.newRequest(ctx, http.MethodPost, "api/v1/oidc/group", withBody(group)) if err != nil { return @@ -79,6 +109,11 @@ func (s OIDCService) UpdateGroup(ctx context.Context, group OIDCGroup) (g OIDCGr } func (s OIDCService) DeleteGroup(ctx context.Context, groupUUID uuid.UUID) (err error) { + err = s.client.assertServerVersionAtLeast("4.0.0") + if err != nil { + return + } + req, err := s.client.newRequest(ctx, http.MethodDelete, fmt.Sprintf("api/v1/oidc/group/%s", groupUUID.String())) if err != nil { return @@ -88,22 +123,27 @@ func (s OIDCService) DeleteGroup(ctx context.Context, groupUUID uuid.UUID) (err return } -func (s OIDCService) GetAllTeamsOf(ctx context.Context, group OIDCGroup, po PageOptions) (p Page[Team], err error) { - req, err := s.client.newRequest(ctx, http.MethodGet, fmt.Sprintf("api/v1/oidc/group/%s/team", group.UUID.String()), withPageOptions(po)) +func (s OIDCService) GetAllTeamsOf(ctx context.Context, group OIDCGroup) (teams []Team, err error) { + err = s.client.assertServerVersionAtLeast("4.0.0") if err != nil { return } - res, err := s.client.doRequest(req, &p.Items) + req, err := s.client.newRequest(ctx, http.MethodGet, fmt.Sprintf("api/v1/oidc/group/%s/team", group.UUID.String())) if err != nil { return } - p.TotalCount = res.TotalCount + _, err = s.client.doRequest(req, &teams) return } func (s OIDCService) AddTeamMapping(ctx context.Context, mapping OIDCMappingRequest) (m OIDCMapping, err error) { + err = s.client.assertServerVersionAtLeast("4.0.0") + if err != nil { + return + } + req, err := s.client.newRequest(ctx, http.MethodPut, "api/v1/oidc/mapping", withBody(mapping)) if err != nil { return @@ -114,6 +154,11 @@ func (s OIDCService) AddTeamMapping(ctx context.Context, mapping OIDCMappingRequ } func (s OIDCService) RemoveTeamMapping(ctx context.Context, mappingID uuid.UUID) (err error) { + err = s.client.assertServerVersionAtLeast("4.0.0") + if err != nil { + return + } + req, err := s.client.newRequest(ctx, http.MethodDelete, fmt.Sprintf("api/v1/oidc/mapping/%s", mappingID.String())) if err != nil { return @@ -122,3 +167,87 @@ func (s OIDCService) RemoveTeamMapping(ctx context.Context, mappingID uuid.UUID) _, err = s.client.doRequest(req, nil) return } + +func (s OIDCService) RemoveTeamMapping2(ctx context.Context, groupID, teamID uuid.UUID) (err error) { + err = s.client.assertServerVersionAtLeast("4.0.0") + if err != nil { + return + } + + req, err := s.client.newRequest(ctx, http.MethodDelete, fmt.Sprintf("api/v1/oidc/group/%s/team/%s/mapping", groupID.String(), teamID.String())) + if err != nil { + return + } + + _, err = s.client.doRequest(req, nil) + return +} + +func (s OIDCService) GetAllUsers(ctx context.Context) (p Page[OIDCUser], err error) { + err = s.client.assertServerVersionAtLeast("4.0.0") + if err != nil { + return + } + + req, err := s.client.newRequest(ctx, http.MethodGet, "api/v1/user/oidc") + if err != nil { + return + } + + res, err := s.client.doRequest(req, &p.Items) + if err != nil { + return + } + + p.TotalCount = res.TotalCount + return +} + +func (s OIDCService) CreateUser(ctx context.Context, userReq OIDCUser) (userRes OIDCUser, err error) { + err = s.client.assertServerVersionAtLeast("4.0.0") + if err != nil { + return + } + + req, err := s.client.newRequest(ctx, http.MethodPut, "api/v1/user/oidc", withBody(userReq)) + if err != nil { + return + } + + _, err = s.client.doRequest(req, &userRes) + return +} + +func (s OIDCService) DeleteUser(ctx context.Context, user OIDCUser) (err error) { + err = s.client.assertServerVersionAtLeast("4.0.0") + if err != nil { + return + } + + req, err := s.client.newRequest(ctx, http.MethodDelete, "api/v1/user/oidc", withBody(user)) + if err != nil { + return + } + + _, err = s.client.doRequest(req, nil) + return +} + +func (s OIDCService) Login(ctx context.Context, tokens OIDCTokens) (token string, err error) { + err = s.client.assertServerVersionAtLeast("4.0.0") + if err != nil { + return + } + + body := url.Values{} + body.Set("idToken", tokens.ID) + body.Set("accessToken", tokens.Access) + + req, err := s.client.newRequest(ctx, http.MethodPost, "api/v1/user/oidc/login", withBody(body)) + if err != nil { + return + } + + _, err = s.client.doRequest(req, &token) + return +} diff --git a/oidc_test.go b/oidc_test.go new file mode 100644 index 0000000..f6f02dd --- /dev/null +++ b/oidc_test.go @@ -0,0 +1,201 @@ +package dtrack + +import ( + "context" + "fmt" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestOIDCGroup(t *testing.T) { + ctx := context.Background() + client := setUpContainer(t, testContainerOptions{ + APIPermissions: []string{ + PermissionAccessManagement, + }, + }) + // Check absence + { + groups, err := client.OIDC.GetAllGroups(ctx) + require.NoError(t, err) + require.Empty(t, groups) + } + // Create Group + group, err := client.OIDC.CreateGroup(ctx, "Test_Group") + require.NoError(t, err) + require.Equal(t, group.Name, "Test_Group") + require.NotZero(t, group.UUID) + + // Check presence + { + groups, err := client.OIDC.GetAllGroups(ctx) + require.NoError(t, err) + require.Equal(t, len(groups), 1) + require.Equal(t, groups[0], group) + } + + // Update Group + { + updated, err := client.OIDC.UpdateGroup(ctx, OIDCGroup{ + UUID: group.UUID, + Name: "Updated_Test_Group", + }) + require.NoError(t, err) + require.Equal(t, updated.UUID, group.UUID) + require.Equal(t, updated.Name, "Updated_Test_Group") + } + + // Check updated + { + groups, err := client.OIDC.GetAllGroups(ctx) + require.NoError(t, err) + require.Equal(t, len(groups), 1) + require.Equal(t, groups[0], OIDCGroup{ + UUID: group.UUID, + Name: "Updated_Test_Group", + }) + } + + // Delete Group + { + err := client.OIDC.DeleteGroup(ctx, group.UUID) + require.NoError(t, err) + } + + // Check absence + { + groups, err := client.OIDC.GetAllGroups(ctx) + require.NoError(t, err) + require.Empty(t, groups) + } +} + +func TestOIDCTeamMappings(t *testing.T) { + ctx := context.Background() + client := setUpContainer(t, testContainerOptions{ + APIPermissions: []string{ + PermissionAccessManagement, + }, + }) + + // Add Team + team, err := client.Team.Create(ctx, Team{ + Name: "Team_Name", + }) + require.NoError(t, err) + + // Add OIDC Group + group, err := client.OIDC.CreateGroup(ctx, "Group_Name") + require.NoError(t, err) + + // Check absence + { + teams, err := client.OIDC.GetAllTeamsOf(ctx, group) + require.NoError(t, err) + require.Empty(t, teams) + } + + // Add Mapping + mapping, err := client.OIDC.AddTeamMapping(ctx, OIDCMappingRequest{ + Team: team.UUID, + Group: group.UUID, + }) + require.NoError(t, err) + + // Check presence + { + teams, err := client.OIDC.GetAllTeamsOf(ctx, group) + require.NoError(t, err) + require.Equal(t, len(teams), 1) + require.Equal(t, teams[0].UUID, team.UUID) + } + + // Delete using mapping ID + { + err := client.OIDC.RemoveTeamMapping(ctx, mapping.UUID) + require.NoError(t, err) + } + + // Check absence + { + teams, err := client.OIDC.GetAllTeamsOf(ctx, group) + require.NoError(t, err) + require.Empty(t, teams) + } + + // Add Mapping + _, err = client.OIDC.AddTeamMapping(ctx, OIDCMappingRequest{ + Team: team.UUID, + Group: group.UUID, + }) + require.NoError(t, err) + + // Check presence + { + teams, err := client.OIDC.GetAllTeamsOf(ctx, group) + require.NoError(t, err) + require.Equal(t, len(teams), 1) + require.Equal(t, teams[0].UUID, team.UUID) + } + + // Delete using Team ID, Group ID + { + err := client.OIDC.RemoveTeamMapping2(ctx, group.UUID, team.UUID) + require.NoError(t, err) + } + + // Check absence + { + teams, err := client.OIDC.GetAllTeamsOf(ctx, group) + require.NoError(t, err) + require.Empty(t, teams) + } +} + +func TestOIDCUsers(t *testing.T) { + ctx := context.Background() + client := setUpContainer(t, testContainerOptions{ + APIPermissions: []string{ + PermissionAccessManagement, + }, + }) + + // Check absence + { + users, err := client.OIDC.GetAllUsers(ctx) + require.NoError(t, err) + require.Empty(t, users.Items) + require.Zero(t, users.TotalCount) + } + + // Create User + user, err := client.OIDC.CreateUser(ctx, OIDCUser{ + Username: "Username", + }) + require.NoError(t, err) + fmt.Printf("%+v", user) + require.Equal(t, user.Username, "Username") + + // Check presence + { + users, err := client.OIDC.GetAllUsers(ctx) + require.NoError(t, err) + require.Equal(t, users.TotalCount, 1) + require.Equal(t, users.Items[0], user) + } + + // Delete User + { + err := client.OIDC.DeleteUser(ctx, user) + require.NoError(t, err) + } + + // Check absence + { + users, err := client.OIDC.GetAllUsers(ctx) + require.NoError(t, err) + require.Empty(t, users.Items) + require.Zero(t, users.TotalCount) + } +} diff --git a/permission.go b/permission.go index 6c11a0b..4763b1c 100644 --- a/permission.go +++ b/permission.go @@ -67,3 +67,23 @@ func (ps PermissionService) RemovePermissionFromTeam(ctx context.Context, permis _, err = ps.client.doRequest(req, &t) return } + +func (ps PermissionService) AddPermissionToUser(ctx context.Context, permission Permission, username string) (user UserPrincipal, err error) { + req, err := ps.client.newRequest(ctx, http.MethodPost, fmt.Sprintf("api/v1/permission/%s/user/%s", permission.Name, username)) + if err != nil { + return + } + + _, err = ps.client.doRequest(req, &user) + return +} + +func (ps PermissionService) RemovePermissionFromUser(ctx context.Context, permission Permission, username string) (user UserPrincipal, err error) { + req, err := ps.client.newRequest(ctx, http.MethodDelete, fmt.Sprintf("api/v1/permission/%s/user/%s", permission.Name, username)) + if err != nil { + return + } + + _, err = ps.client.doRequest(req, &user) + return +} diff --git a/project.go b/project.go index cb06a00..c2538a7 100644 --- a/project.go +++ b/project.go @@ -217,7 +217,7 @@ func (ps ProjectService) GetChildren(ctx context.Context, projectUUID uuid.UUID, "uuid": projectUUID.String(), } - req, err := ps.client.newRequest(ctx, http.MethodGet, "/api/v1/project/{uuid}/children", withPathParams(pathParams), withPageOptions(po)) + req, err := ps.client.newRequest(ctx, http.MethodGet, "api/v1/project/{uuid}/children", withPathParams(pathParams), withPageOptions(po)) if err != nil { return } diff --git a/user.go b/user.go index 6245d44..d9ee07b 100644 --- a/user.go +++ b/user.go @@ -2,15 +2,50 @@ package dtrack import ( "context" + "fmt" "net/http" "net/url" + + "github.com/google/uuid" ) type UserService struct { client *Client } +type ManagedUser struct { + Username string `json:"username"` + LastPasswordChange int `json:"lastPasswordChange"` + Fullname string `json:"fullname,omitempty"` + Email string `json:"email,omitempty"` + Suspended bool `json:"suspended,omitempty"` + ForcePasswordChange bool `json:"forcePasswordChange,omitempty"` + NonExpiryPassword bool `json:"nonExpiryPassword,omitempty"` + Teams []Team `json:"teams,omitempty"` + Permissions []Permission `json:"permissions,omitempty"` + NewPassword string `json:"newPassword,omitempty"` + ConfirmPassword string `json:"confirmPassword,omitempty"` +} + +type UserPrincipal struct { + Teams []Team `json:"teams"` + Username string `json:"username"` + Email string `json:"email"` + Id int64 `json:"id,omitempty"` + Permissions []Permission `json:"permissions"` + Name string `json:"name"` +} + +type IdentifiableObject struct { + UUID uuid.UUID `json:"uuid"` +} + func (us UserService) Login(ctx context.Context, username, password string) (token string, err error) { + err = us.client.assertServerVersionAtLeast("3.0.0") + if err != nil { + return + } + body := url.Values{} body.Set("username", username) body.Set("password", password) @@ -27,6 +62,11 @@ func (us UserService) Login(ctx context.Context, username, password string) (tok } func (us UserService) ForceChangePassword(ctx context.Context, username, password, newPassword string) (err error) { + err = us.client.assertServerVersionAtLeast("3.0.0") + if err != nil { + return + } + body := url.Values{} body.Set("username", username) body.Set("password", password) @@ -43,3 +83,123 @@ func (us UserService) ForceChangePassword(ctx context.Context, username, passwor _, err = us.client.doRequest(req, nil) return } + +func (us UserService) GetAllManaged(ctx context.Context, po PageOptions) (p Page[ManagedUser], err error) { + err = us.client.assertServerVersionAtLeast("3.0.0") + if err != nil { + return + } + + req, err := us.client.newRequest(ctx, http.MethodGet, "api/v1/user/managed", withPageOptions(po)) + if err != nil { + return + } + _, err = us.client.doRequest(req, &p.Items) + return +} + +func (us UserService) CreateManaged(ctx context.Context, usr ManagedUser) (user ManagedUser, err error) { + err = us.client.assertServerVersionAtLeast("3.0.0") + if err != nil { + return + } + + req, err := us.client.newRequest(ctx, http.MethodPut, "api/v1/user/managed", withBody(usr)) + if err != nil { + return + } + _, err = us.client.doRequest(req, &user) + return +} + +func (us UserService) UpdateManaged(ctx context.Context, usr ManagedUser) (user ManagedUser, err error) { + err = us.client.assertServerVersionAtLeast("3.0.0") + if err != nil { + return + } + + req, err := us.client.newRequest(ctx, http.MethodPost, "api/v1/user/managed", withBody(usr)) + if err != nil { + return + } + _, err = us.client.doRequest(req, &user) + return +} + +func (us UserService) DeleteManaged(ctx context.Context, user ManagedUser) (err error) { + err = us.client.assertServerVersionAtLeast("3.0.0") + if err != nil { + return + } + + req, err := us.client.newRequest(ctx, http.MethodDelete, "api/v1/user/managed", withBody(user)) + if err != nil { + return + } + _, err = us.client.doRequest(req, nil) + return +} + +func (us UserService) AddTeamToUser(ctx context.Context, username string, team uuid.UUID) (user UserPrincipal, err error) { + err = us.client.assertServerVersionAtLeast("3.0.0") + if err != nil { + return + } + + req, err := us.client.newRequest(ctx, http.MethodPost, fmt.Sprintf("api/v1/user/%s/membership", username), withBody(IdentifiableObject{ + UUID: team, + })) + if err != nil { + return + } + + _, err = us.client.doRequest(req, &user) + return +} + +func (us UserService) RemoveTeamFromUser(ctx context.Context, username string, team uuid.UUID) (user UserPrincipal, err error) { + err = us.client.assertServerVersionAtLeast("3.0.0") + if err != nil { + return + } + + req, err := us.client.newRequest(ctx, http.MethodDelete, fmt.Sprintf("api/v1/user/%s/membership", username), withBody(IdentifiableObject{ + UUID: team, + })) + if err != nil { + return + } + + _, err = us.client.doRequest(req, &user) + return +} + +func (us UserService) GetSelf(ctx context.Context) (user UserPrincipal, err error) { + err = us.client.assertServerVersionAtLeast("3.0.0") + if err != nil { + return + } + + req, err := us.client.newRequest(ctx, http.MethodGet, "api/v1/user/self") + if err != nil { + return + } + + _, err = us.client.doRequest(req, &user) + return +} + +func (us UserService) UpdateSelf(ctx context.Context, userReq ManagedUser) (userRes ManagedUser, err error) { + err = us.client.assertServerVersionAtLeast("3.0.0") + if err != nil { + return + } + + req, err := us.client.newRequest(ctx, http.MethodPost, "api/v1/user/self", withBody(userReq)) + if err != nil { + return + } + + _, err = us.client.doRequest(req, &userRes) + return +} diff --git a/user_test.go b/user_test.go new file mode 100644 index 0000000..47aadb5 --- /dev/null +++ b/user_test.go @@ -0,0 +1,142 @@ +package dtrack + +import ( + "context" + "github.com/stretchr/testify/require" + "testing" +) + +func TestCreateManagedUser(t *testing.T) { + client := setUpContainer(t, testContainerOptions{ + APIPermissions: []string{ + PermissionAccessManagement, + }, + }) + + user, err := client.User.CreateManaged(context.Background(), ManagedUser{ + Username: "test-managed", + Fullname: "test-managed-full-name", + Email: "test-managed-email@localhost", + NewPassword: "test-managed-password", + ConfirmPassword: "test-managed-password", + }) + require.NoError(t, err) + + require.Equal(t, user.Username, "test-managed") + require.NotNil(t, user.LastPasswordChange) + require.Equal(t, user.Fullname, "test-managed-full-name") + require.Equal(t, user.Email, "test-managed-email@localhost") + require.Equal(t, user.Teams, []Team{}) + require.Equal(t, user.Permissions, []Permission{}) + require.Equal(t, user.Suspended, false) + require.Equal(t, user.ForcePasswordChange, false) + require.Equal(t, user.NonExpiryPassword, false) +} + +func TestUpdateManagedUser(t *testing.T) { + client := setUpContainer(t, testContainerOptions{ + APIPermissions: []string{ + PermissionAccessManagement, + }, + }) + + user, err := client.User.CreateManaged(context.Background(), ManagedUser{ + Username: "test-managed", + Fullname: "test-managed-full-name", + Email: "test-managed-email@localhost", + NewPassword: "test-managed-password", + ConfirmPassword: "test-managed-password", + }) + require.NoError(t, err) + require.Equal(t, user.Username, "test-managed") + require.Equal(t, user.Fullname, "test-managed-full-name") + require.Equal(t, user.Email, "test-managed-email@localhost") + + updated, err := client.User.UpdateManaged(context.Background(), ManagedUser{ + Username: user.Username, + Fullname: "test-managed-full-name-updated", + Email: user.Email, + }) + + require.NoError(t, err) + require.Equal(t, updated.Username, user.Username) + require.Equal(t, updated.Fullname, "test-managed-full-name-updated") + require.Equal(t, updated.Email, user.Email) +} + +func TestGetAllManagedUsers(t *testing.T) { + client := setUpContainer(t, testContainerOptions{ + APIPermissions: []string{ + PermissionAccessManagement, + }, + }) + + user, err := client.User.CreateManaged(context.Background(), ManagedUser{ + Username: "test-managed", + Fullname: "test-managed-full-name", + Email: "test-managed-email@localhost", + NewPassword: "test-managed-password", + ConfirmPassword: "test-managed-password", + }) + require.NoError(t, err) + require.Equal(t, user.Username, "test-managed") + require.Equal(t, user.Fullname, "test-managed-full-name") + require.Equal(t, user.Email, "test-managed-email@localhost") + + users, err := FetchAll(func(po PageOptions) (Page[ManagedUser], error) { + return client.User.GetAllManaged(context.Background(), po) + }) + + require.NoError(t, err) + require.Equal(t, len(users), 2) + require.Equal(t, users[0].Username, "admin") + require.Equal(t, len(users[0].Teams), 1) + require.Equal(t, users[0].Teams[0].Name, "Administrators") + require.Equal(t, len(users[0].Permissions), 14) + + require.Equal(t, users[1].Username, "test-managed") +} + +func TestDeleteManagedUser(t *testing.T) { + // Create User + // Validate creation of user + // Delete user + // Validate deletion of user + client := setUpContainer(t, testContainerOptions{ + APIPermissions: []string{ + PermissionAccessManagement, + }, + }) + + user, err := client.User.CreateManaged(context.Background(), ManagedUser{ + Username: "test-managed", + Fullname: "test-managed-full-name", + Email: "test-managed-email@localhost", + NewPassword: "test-managed-password", + ConfirmPassword: "test-managed-password", + }) + require.NoError(t, err) + require.Equal(t, user.Username, "test-managed") + require.Equal(t, user.Fullname, "test-managed-full-name") + require.Equal(t, user.Email, "test-managed-email@localhost") + + users, err := FetchAll(func(po PageOptions) (Page[ManagedUser], error) { + return client.User.GetAllManaged(context.Background(), po) + }) + + require.NoError(t, err) + require.Equal(t, len(users), 2) + + err = client.User.DeleteManaged(context.Background(), ManagedUser{ + Username: user.Username, + }) + + require.NoError(t, err) + + users, err = FetchAll(func(po PageOptions) (Page[ManagedUser], error) { + return client.User.GetAllManaged(context.Background(), po) + }) + + require.NoError(t, err) + require.Equal(t, len(users), 1) +}