mattermost-community-enterp.../cmd/mmctl/commands/user_attributes_value_test.go
Claude ec1f89217a Merge: Complete Mattermost Server with Community Enterprise
Full Mattermost server source with integrated Community Enterprise features.
Includes vendor directory for offline/air-gapped builds.

Structure:
- enterprise-impl/: Enterprise feature implementations
- enterprise-community/: Init files that register implementations
- enterprise/: Bridge imports (community_imports.go)
- vendor/: All dependencies for offline builds

Build (online):
  go build ./cmd/mattermost

Build (offline/air-gapped):
  go build -mod=vendor ./cmd/mattermost

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 23:59:07 +09:00

551 lines
13 KiB
Go

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package commands
import (
"context"
"encoding/json"
"errors"
"net/http"
"github.com/golang/mock/gomock"
"github.com/mattermost/mattermost/server/public/model"
"github.com/mattermost/mattermost/server/v8/cmd/mmctl/printer"
"github.com/spf13/cobra"
)
func (s *MmctlUnitTestSuite) TestCPAValueListCmd() {
s.Run("Should list all CPA values with plain text output format", func() {
printer.Clean()
printer.SetFormat(printer.FormatPlain)
mockUser := &model.User{
Id: "user123",
Username: "testuser",
}
fieldID1 := model.NewId()
fieldID2 := model.NewId()
mockFields := []*model.PropertyField{
{
ID: fieldID1,
Name: "Department",
Type: model.PropertyFieldTypeText,
},
{
ID: fieldID2,
Name: "Skills",
Type: model.PropertyFieldTypeMultiselect,
Attrs: model.StringInterface{
"options": []*model.CustomProfileAttributesSelectOption{
{ID: "opt1", Name: "Go"},
{ID: "opt2", Name: "React"},
{ID: "opt3", Name: "Python"},
},
},
},
}
mockValues := map[string]json.RawMessage{
fieldID1: json.RawMessage(`"Engineering"`),
fieldID2: json.RawMessage(`["opt1", "opt2", "opt3"]`),
}
s.client.
EXPECT().
ListCPAFields(context.TODO()).
Return(mockFields, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
GetUserByEmail(context.TODO(), "testuser@example.com", "").
Return(mockUser, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
ListCPAValues(context.TODO(), "user123").
Return(mockValues, &model.Response{}, nil).
Times(1)
err := cpaValueListCmdF(s.client, &cobra.Command{}, []string{"testuser@example.com"})
s.Require().NoError(err)
lines := printer.GetLines()
s.Require().NotEmpty(lines)
// Check that we have human-readable output
found := false
for _, line := range lines {
if lineStr, ok := line.(string); ok {
if lineStr == "Department (text): Engineering" {
found = true
break
}
}
}
s.Require().True(found, "Should contain human-readable field name and value")
})
s.Run("Should output raw data structure when --json flag is used", func() {
printer.Clean()
printer.SetFormat(printer.FormatJSON)
mockUser := &model.User{
Id: "user123",
Username: "testuser",
}
fieldID1 := model.NewId()
mockFields := []*model.PropertyField{
{
ID: fieldID1,
Name: "Department",
Type: model.PropertyFieldTypeText,
},
}
mockValues := map[string]json.RawMessage{
fieldID1: json.RawMessage(`"Engineering"`),
}
s.client.
EXPECT().
ListCPAFields(context.TODO()).
Return(mockFields, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
GetUserByEmail(context.TODO(), "testuser@example.com", "").
Return(mockUser, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
ListCPAValues(context.TODO(), "user123").
Return(mockValues, &model.Response{}, nil).
Times(1)
err := cpaValueListCmdF(s.client, &cobra.Command{}, []string{"testuser@example.com"})
s.Require().NoError(err)
lines := printer.GetLines()
s.Require().NotEmpty(lines)
// Check that JSON format outputs raw data structure
found := false
for _, line := range lines {
if lineMap, ok := line.(map[string]any); ok {
if val, exists := lineMap[fieldID1]; exists {
if rawVal, ok := val.(json.RawMessage); ok && string(rawVal) == `"Engineering"` {
found = true
break
}
}
}
}
s.Require().True(found, "JSON output should contain raw field ID and value")
})
s.Run("Should resolve multiselect option names correctly", func() {
printer.Clean()
printer.SetFormat(printer.FormatPlain)
mockUser := &model.User{
Id: "user123",
Username: "testuser",
}
fieldID := model.NewId()
mockFields := []*model.PropertyField{
{
ID: fieldID,
Name: "Skills",
Type: model.PropertyFieldTypeMultiselect,
Attrs: model.StringInterface{
"options": []*model.CustomProfileAttributesSelectOption{
{ID: "opt1", Name: "Go"},
{ID: "opt2", Name: "React"},
{ID: "opt3", Name: "Python"},
},
},
},
}
mockValues := map[string]json.RawMessage{
fieldID: json.RawMessage(`["opt1", "opt3"]`),
}
s.client.
EXPECT().
ListCPAFields(context.TODO()).
Return(mockFields, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
GetUserByEmail(context.TODO(), "testuser@example.com", "").
Return(mockUser, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
ListCPAValues(context.TODO(), "user123").
Return(mockValues, &model.Response{}, nil).
Times(1)
err := cpaValueListCmdF(s.client, &cobra.Command{}, []string{"testuser@example.com"})
s.Require().NoError(err)
lines := printer.GetLines()
s.Require().NotEmpty(lines)
// Check that multiselect options are resolved to names
found := false
for _, line := range lines {
if lineStr, ok := line.(string); ok {
if lineStr == "Skills (multiselect): [Go, Python]" {
found = true
break
}
}
}
s.Require().True(found, "Should resolve multiselect option IDs to names")
})
s.Run("Should handle empty value list scenario", func() {
printer.Clean()
printer.SetFormat(printer.FormatPlain)
mockUser := &model.User{
Id: "user123",
Username: "testuser",
}
s.client.
EXPECT().
ListCPAFields(context.TODO()).
Return([]*model.PropertyField{}, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
GetUserByEmail(context.TODO(), "testuser@example.com", "").
Return(mockUser, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
ListCPAValues(context.TODO(), "user123").
Return(map[string]json.RawMessage{}, &model.Response{}, nil).
Times(1)
err := cpaValueListCmdF(s.client, &cobra.Command{}, []string{"testuser@example.com"})
s.Require().NoError(err)
lines := printer.GetLines()
// When there are no values, no output should be produced
s.Require().Len(lines, 0)
})
s.Run("Should handle API error when ListCPAValues fails", func() {
printer.Clean()
mockUser := &model.User{
Id: "user123",
Username: "testuser",
}
expectedError := errors.New("API error")
s.client.
EXPECT().
ListCPAFields(context.TODO()).
Return([]*model.PropertyField{}, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
GetUserByEmail(context.TODO(), "testuser@example.com", "").
Return(mockUser, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
ListCPAValues(context.TODO(), "user123").
Return(nil, &model.Response{}, expectedError).
Times(1)
err := cpaValueListCmdF(s.client, &cobra.Command{}, []string{"testuser@example.com"})
s.Require().Error(err)
s.Require().Contains(err.Error(), "failed to get CPA values for user")
s.Require().Contains(err.Error(), "API error")
})
s.Run("Should handle API error when ListCPAFields fails", func() {
printer.Clean()
expectedError := errors.New("fields API error")
s.client.
EXPECT().
ListCPAFields(context.TODO()).
Return(nil, &model.Response{}, expectedError).
Times(1)
err := cpaValueListCmdF(s.client, &cobra.Command{}, []string{"testuser@example.com"})
s.Require().Error(err)
s.Require().Contains(err.Error(), "failed to get CPA fields for template context")
s.Require().Contains(err.Error(), "fields API error")
})
s.Run("Should handle getUserFromArg error", func() {
printer.Clean()
notFoundError := errors.New("user not found")
notFoundResponse := &model.Response{StatusCode: http.StatusNotFound}
s.client.
EXPECT().
ListCPAFields(context.TODO()).
Return([]*model.PropertyField{}, &model.Response{}, nil).
Times(1)
// getUserFromArg tries email first, then username, then user ID
// All should return NotFoundError so it tries all methods
s.client.
EXPECT().
GetUserByEmail(context.TODO(), "nonexistent@example.com", "").
Return(nil, notFoundResponse, notFoundError).
Times(1)
s.client.
EXPECT().
GetUserByUsername(context.TODO(), "nonexistent@example.com", "").
Return(nil, notFoundResponse, notFoundError).
Times(1)
s.client.
EXPECT().
GetUser(context.TODO(), "nonexistent@example.com", "").
Return(nil, notFoundResponse, notFoundError).
Times(1)
err := cpaValueListCmdF(s.client, &cobra.Command{}, []string{"nonexistent@example.com"})
s.Require().Error(err)
})
}
func (s *MmctlUnitTestSuite) TestCPAValueSetCmd() {
s.Run("Should successfully set single CPA value", func() {
printer.Clean()
printer.SetFormat(printer.FormatPlain)
mockUser := &model.User{
Id: "user123",
Username: "testuser",
}
fieldID := model.NewId()
mockFields := []*model.PropertyField{
{
ID: fieldID,
Name: "Department",
Type: model.PropertyFieldTypeText,
},
}
mockUpdatedValues := map[string]json.RawMessage{
fieldID: json.RawMessage(`"Engineering"`),
}
cmd := &cobra.Command{}
cmd.Flags().StringSlice("value", []string{"Engineering"}, "")
s.client.
EXPECT().
GetUserByEmail(context.TODO(), "testuser@example.com", "").
Return(mockUser, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
ListCPAFields(context.TODO()).
Return(mockFields, &model.Response{}, nil).
Times(2)
s.client.
EXPECT().
PatchCPAValuesForUser(context.TODO(), "user123", gomock.Any()).
Return(mockUpdatedValues, &model.Response{}, nil).
Times(1)
err := cpaValueSetCmdF(s.client, cmd, []string{"testuser@example.com", fieldID})
s.Require().NoError(err)
})
s.Run("Should successfully set multiple CPA values", func() {
printer.Clean()
printer.SetFormat(printer.FormatPlain)
mockUser := &model.User{
Id: "user123",
Username: "testuser",
}
fieldID := model.NewId()
mockFields := []*model.PropertyField{
{
ID: fieldID,
Name: "Skills",
Type: model.PropertyFieldTypeMultiselect,
},
}
mockUpdatedValues := map[string]json.RawMessage{
fieldID: json.RawMessage(`["Go", "React", "Python"]`),
}
cmd := &cobra.Command{}
cmd.Flags().StringSlice("value", []string{"Go", "React", "Python"}, "")
s.client.
EXPECT().
GetUserByEmail(context.TODO(), "testuser@example.com", "").
Return(mockUser, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
ListCPAFields(context.TODO()).
Return(mockFields, &model.Response{}, nil).
Times(2)
s.client.
EXPECT().
PatchCPAValuesForUser(context.TODO(), "user123", gomock.Any()).
Return(mockUpdatedValues, &model.Response{}, nil).
Times(1)
err := cpaValueSetCmdF(s.client, cmd, []string{"testuser@example.com", fieldID})
s.Require().NoError(err)
})
s.Run("Should handle field not found error", func() {
printer.Clean()
mockUser := &model.User{
Id: "user123",
Username: "testuser",
}
mockFields := []*model.PropertyField{
{
ID: "different_field",
Name: "Department",
Type: model.PropertyFieldTypeText,
},
}
cmd := &cobra.Command{}
cmd.Flags().StringSlice("value", []string{"Engineering"}, "")
s.client.
EXPECT().
GetUserByEmail(context.TODO(), "testuser@example.com", "").
Return(mockUser, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
ListCPAFields(context.TODO()).
Return(mockFields, &model.Response{}, nil).
Times(1)
err := cpaValueSetCmdF(s.client, cmd, []string{"testuser@example.com", "nonexistent_field"})
s.Require().Error(err)
s.Require().Contains(err.Error(), "failed to get field for \"nonexistent_field\"")
})
s.Run("Should handle API error when PatchCPAValuesForUser fails", func() {
printer.Clean()
mockUser := &model.User{
Id: "user123",
Username: "testuser",
}
fieldID := model.NewId()
mockFields := []*model.PropertyField{
{
ID: fieldID,
Name: "Department",
Type: model.PropertyFieldTypeText,
},
}
expectedError := errors.New("permission denied")
cmd := &cobra.Command{}
cmd.Flags().StringSlice("value", []string{"Engineering"}, "")
s.client.
EXPECT().
GetUserByEmail(context.TODO(), "testuser@example.com", "").
Return(mockUser, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
ListCPAFields(context.TODO()).
Return(mockFields, &model.Response{}, nil).
Times(2)
s.client.
EXPECT().
PatchCPAValuesForUser(context.TODO(), "user123", gomock.Any()).
Return(nil, &model.Response{}, expectedError).
Times(1)
err := cpaValueSetCmdF(s.client, cmd, []string{"testuser@example.com", fieldID})
s.Require().Error(err)
s.Require().Contains(err.Error(), "failed to set CPA value")
s.Require().Contains(err.Error(), "permission denied")
})
s.Run("Should handle ListCPAFields API error", func() {
printer.Clean()
mockUser := &model.User{
Id: "user123",
Username: "testuser",
}
expectedError := errors.New("fields API error")
cmd := &cobra.Command{}
cmd.Flags().StringSlice("value", []string{"Engineering"}, "")
s.client.
EXPECT().
GetUserByEmail(context.TODO(), "testuser@example.com", "").
Return(mockUser, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
ListCPAFields(context.TODO()).
Return(nil, &model.Response{}, expectedError).
Times(1)
err := cpaValueSetCmdF(s.client, cmd, []string{"testuser@example.com", "field123"})
s.Require().Error(err)
s.Require().Contains(err.Error(), "failed to get CPA fields")
s.Require().Contains(err.Error(), "fields API error")
})
}