mattermost/server/cmd/mmctl/commands/user_attributes_value_e2e_test.go
2026-05-14 12:46:07 -04:00

367 lines
11 KiB
Go

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package commands
import (
"context"
"encoding/json"
"github.com/mattermost/mattermost/server/public/model"
"github.com/spf13/cobra"
"github.com/mattermost/mattermost/server/v8/cmd/mmctl/printer"
)
// listCPAValuesForUser fetches the user's CPA values via the admin HTTP
// client (field-id → raw-JSON map, same shape the command returns).
func (s *MmctlE2ETestSuite) listCPAValuesForUser(userID string) map[string]json.RawMessage {
s.T().Helper()
values, _, err := s.th.SystemAdminClient.ListCPAValues(context.Background(), userID)
s.Require().NoError(err)
return values
}
// cleanCPAValuesForUser removes all CPA values for a user
func (s *MmctlE2ETestSuite) cleanCPAValuesForUser(userID string) {
s.T().Helper()
existing := s.listCPAValuesForUser(userID)
if len(existing) == 0 {
return
}
// Clear all existing values by setting them to null
updates := make(map[string]json.RawMessage, len(existing))
for fieldID := range existing {
updates[fieldID] = json.RawMessage("null")
}
_, _, err := s.th.SystemAdminClient.PatchCPAValuesForUser(context.Background(), userID, updates)
s.Require().NoError(err)
}
func (s *MmctlE2ETestSuite) TestCPAValueList() {
s.SetupEnterpriseTestHelper().InitBasic(s.T())
s.th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise))
s.Run("List CPA values with no values", func() {
c := s.th.SystemAdminClient
printer.Clean()
s.cleanCPAFields()
s.cleanCPAValuesForUser(s.th.BasicUser.Id)
// Test listing when no values are set
err := cpaValueListCmdF(c, &cobra.Command{}, []string{s.th.BasicUser.Email})
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 0)
s.Require().Len(printer.GetErrorLines(), 0)
})
s.Run("List CPA values with existing values", func() {
c := s.th.SystemAdminClient
printer.Clean()
s.cleanCPAFields()
s.cleanCPAValuesForUser(s.th.BasicUser.Id)
// Create a text field
textField := &model.CPAField{
PropertyField: model.PropertyField{
Name: "Department",
Type: model.PropertyFieldTypeText,
TargetType: "user",
},
Attrs: model.CPAAttrs{
Managed: "",
},
}
createdField := s.createCPAField(textField)
// Seed a text value via the admin HTTP client.
updates := map[string]json.RawMessage{
createdField.ID: json.RawMessage(`"Engineering"`),
}
_, _, err := s.th.SystemAdminClient.PatchCPAValuesForUser(context.Background(), s.th.BasicUser.Id, updates)
s.Require().NoError(err)
// Test listing the values with plain format (human-readable)
printer.SetFormat(printer.FormatPlain)
err = cpaValueListCmdF(c, &cobra.Command{}, []string{s.th.BasicUser.Email})
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Len(printer.GetErrorLines(), 0)
// Check that the human-readable format is used
output := printer.GetLines()[0].(string)
s.Require().Equal("Department (text): Engineering", output)
// Test with JSON format to ensure raw data is preserved
printer.Clean()
printer.SetFormat(printer.FormatJSON)
err = cpaValueListCmdF(c, &cobra.Command{}, []string{s.th.BasicUser.Email})
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Len(printer.GetErrorLines(), 0)
// Check that JSON format outputs raw data structure
outputMap := printer.GetLines()[0].(map[string]any)
s.Require().Contains(outputMap, createdField.ID)
s.Require().Equal(`"Engineering"`, string(outputMap[createdField.ID].(json.RawMessage)))
})
}
func (s *MmctlE2ETestSuite) TestCPAValueSet() {
s.SetupEnterpriseTestHelper().InitBasic(s.T())
s.th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise))
s.Run("Set value for text type field", func() {
c := s.th.SystemAdminClient
printer.Clean()
s.cleanCPAFields()
s.cleanCPAValuesForUser(s.th.BasicUser.Id)
// Create a text field
textField := &model.CPAField{
PropertyField: model.PropertyField{
Name: "Department",
Type: model.PropertyFieldTypeText,
TargetType: "user",
},
Attrs: model.CPAAttrs{
Managed: "",
},
}
createdField := s.createCPAField(textField)
// Set a text value
cmd := &cobra.Command{}
cmd.Flags().StringSlice("value", []string{}, "")
err := cmd.Flags().Set("value", "Engineering")
s.Require().Nil(err)
err = cpaValueSetCmdF(c, cmd, []string{s.th.BasicUser.Email, createdField.ID})
s.Require().Nil(err)
// Verify the value was set
values := s.listCPAValuesForUser(s.th.BasicUser.Id)
s.Require().Len(values, 1)
s.Require().Equal(`"Engineering"`, string(values[createdField.ID]))
})
s.Run("Set value for select type field", func() {
c := s.th.SystemAdminClient
printer.Clean()
s.cleanCPAFields()
s.cleanCPAValuesForUser(s.th.BasicUser.Id)
// Create a select field with options
selectField := &model.CPAField{
PropertyField: model.PropertyField{
Name: "Level",
Type: model.PropertyFieldTypeSelect,
TargetType: "user",
},
Attrs: model.CPAAttrs{
Managed: "",
Options: []*model.CustomProfileAttributesSelectOption{
{ID: model.NewId(), Name: "Junior"},
{ID: model.NewId(), Name: "Senior"},
{ID: model.NewId(), Name: "Lead"},
},
},
}
createdField := s.createCPAField(selectField)
// Set a select value using the option name
cmd := &cobra.Command{}
cmd.Flags().StringSlice("value", []string{}, "")
err := cmd.Flags().Set("value", "Senior")
s.Require().Nil(err)
err = cpaValueSetCmdF(c, cmd, []string{s.th.BasicUser.Email, createdField.ID})
s.Require().Nil(err)
// Verify the value was set (should be stored as option ID)
values := s.listCPAValuesForUser(s.th.BasicUser.Id)
s.Require().Len(values, 1)
// Find the Senior option ID for verification
var seniorOptionID string
for _, option := range createdField.Attrs.Options {
if option.Name == "Senior" {
seniorOptionID = option.ID
break
}
}
s.Require().Equal(`"`+seniorOptionID+`"`, string(values[createdField.ID]))
})
s.Run("Set value for multiselect type field", func() {
c := s.th.SystemAdminClient
printer.Clean()
s.cleanCPAFields()
s.cleanCPAValuesForUser(s.th.BasicUser.Id)
// Create a multiselect field with options
multiselectField := &model.CPAField{
PropertyField: model.PropertyField{
Name: "Skills",
Type: model.PropertyFieldTypeMultiselect,
TargetType: "user",
},
Attrs: model.CPAAttrs{
Managed: "",
Options: []*model.CustomProfileAttributesSelectOption{
{ID: model.NewId(), Name: "Go"},
{ID: model.NewId(), Name: "React"},
{ID: model.NewId(), Name: "Python"},
{ID: model.NewId(), Name: "JavaScript"},
},
},
}
createdField := s.createCPAField(multiselectField)
// Set multiple values using option names
cmd := &cobra.Command{}
cmd.Flags().StringSlice("value", []string{}, "")
err := cmd.Flags().Set("value", "Go")
s.Require().Nil(err)
err = cmd.Flags().Set("value", "React")
s.Require().Nil(err)
err = cmd.Flags().Set("value", "Python")
s.Require().Nil(err)
err = cpaValueSetCmdF(c, cmd, []string{s.th.BasicUser.Email, createdField.ID})
s.Require().Nil(err)
// Verify the values were set (should be stored as option IDs)
values := s.listCPAValuesForUser(s.th.BasicUser.Id)
s.Require().Len(values, 1)
// Find the option IDs for verification
var goOptionID, reactOptionID, pythonOptionID string
for _, option := range createdField.Attrs.Options {
switch option.Name {
case "Go":
goOptionID = option.ID
case "React":
reactOptionID = option.ID
case "Python":
pythonOptionID = option.ID
}
}
// The multiselect values should be stored as an array of option IDs
// The JSON serialization may include spaces, so we need to compare the content, not exact string
actualValue := string(values[createdField.ID])
s.Require().Contains(actualValue, goOptionID)
s.Require().Contains(actualValue, reactOptionID)
s.Require().Contains(actualValue, pythonOptionID)
})
s.Run("Set a single value for multiselect type field", func() {
c := s.th.SystemAdminClient
printer.Clean()
s.cleanCPAFields()
s.cleanCPAValuesForUser(s.th.BasicUser.Id)
// Create a multiselect field with options
multiselectField := &model.CPAField{
PropertyField: model.PropertyField{
Name: "Programming Languages",
Type: model.PropertyFieldTypeMultiselect,
TargetType: "user",
},
Attrs: model.CPAAttrs{
Managed: "",
Options: []*model.CustomProfileAttributesSelectOption{
{ID: model.NewId(), Name: "Go"},
{ID: model.NewId(), Name: "Python"},
{ID: model.NewId(), Name: "JavaScript"},
},
},
}
createdField := s.createCPAField(multiselectField)
// Set a single value using option name
cmd := &cobra.Command{}
cmd.Flags().StringSlice("value", []string{}, "")
err := cmd.Flags().Set("value", "Python")
s.Require().Nil(err)
err = cpaValueSetCmdF(c, cmd, []string{s.th.BasicUser.Email, createdField.ID})
s.Require().Nil(err)
// Verify the value was set (should be stored as an array with single option ID)
values := s.listCPAValuesForUser(s.th.BasicUser.Id)
s.Require().Len(values, 1)
// Find the option ID for verification
var pythonOptionID string
for _, option := range createdField.Attrs.Options {
if option.Name == "Python" {
pythonOptionID = option.ID
break
}
}
// The multiselect value should be stored as an array with single option ID
// Even for single value, multiselect fields store values as arrays
actualValue := string(values[createdField.ID])
s.Require().Contains(actualValue, pythonOptionID)
s.Require().Contains(actualValue, "[")
s.Require().Contains(actualValue, "]")
// Verify it doesn't contain other option IDs
for _, option := range createdField.Attrs.Options {
if option.Name != "Python" {
s.Require().NotContains(actualValue, option.ID)
}
}
})
s.Run("Set value for user type field", func() {
c := s.th.SystemAdminClient
printer.Clean()
s.cleanCPAFields()
s.cleanCPAValuesForUser(s.th.BasicUser.Id)
// Create a user field
userField := &model.CPAField{
PropertyField: model.PropertyField{
Name: "Manager",
Type: model.PropertyFieldTypeUser,
TargetType: "user",
},
Attrs: model.CPAAttrs{
Managed: "",
},
}
createdField := s.createCPAField(userField)
// Set a user value using the system admin user ID
cmd := &cobra.Command{}
cmd.Flags().StringSlice("value", []string{}, "")
err := cmd.Flags().Set("value", s.th.SystemAdminUser.Id)
s.Require().Nil(err)
err = cpaValueSetCmdF(c, cmd, []string{s.th.BasicUser.Email, createdField.ID})
s.Require().Nil(err)
// Verify the value was set
values := s.listCPAValuesForUser(s.th.BasicUser.Id)
s.Require().Len(values, 1)
s.Require().Equal(`"`+s.th.SystemAdminUser.Id+`"`, string(values[createdField.ID]))
})
}