Some checks failed
Server CI / Postgres (shard 0) (push) Has been skipped
Server CI / Postgres (shard 3) (push) Has been skipped
BuildEnv Docker Image / build-image (push) Failing after 4s
BuildEnv Docker Image / build-image-fips (push) Failing after 4s
Migration Review & Release Notes / Generate migration review & release notes (push) Failing after 3s
Server CI / Build Environment (push) Failing after 3s
Server CI / Postgres (shard 1) (push) Has been skipped
Tools CI / check-style (mattermost-govet) (push) Failing after 4s
Server CI / Postgres (shard 2) (push) Has been skipped
Tools CI / check-style (mmgotool) (push) Failing after 3s
Server CI / Elasticsearch v8 Compatibility (push) Has been skipped
Server CI / OpenSearch v2 Compatibility (push) Has been skipped
Server CI / Postgres FIPS (shard 0) (push) Has been skipped
Tools CI / Test (mattermost-govet) (push) Failing after 3s
Server CI / Postgres FIPS (shard 1) (push) Has been skipped
Server CI / Postgres FIPS (shard 2) (push) Has been skipped
Tools CI / Test (mmgotool) (push) Failing after 3s
Server CI / Postgres FIPS (shard 3) (push) Has been skipped
Server CI / Run mmctl tests (push) Has been skipped
Server CI / Run mmctl tests (FIPS) (push) Has been skipped
Server CI / Merge Postgres Test Results (push) Has been skipped
Server CI / Merge Postgres FIPS Test Results (push) Has been skipped
Server CI / Check backport migrations (push) Has been skipped
Server CI / Check generated files (push) Has been skipped
Server CI / check-style (push) Has been skipped
Server CI / Vet API (push) Has been skipped
Server CI / Build mattermost server app (push) Has been skipped
Server CI / Server CI Complete (push) Failing after 2s
Server CI / Server CI Artifacts (push) Has been skipped
Server CI / Sentry Upload (push) Has been skipped
Server CI / Server CI Report (push) Failing after 5m1s
Server CI Nightly Race / Race Detector (push) Has been skipped
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Webapp CI Cache Warm / Warm Webapp node_modules Cache (push) Has been cancelled
E2E CI Cache Warm / Warm E2E npm Registry Cache (push) Has been cancelled
API / build (push) Has been cancelled
Web App CI / check-types (push) Has been cancelled
Web App CI / check-lint (push) Has been cancelled
Web App CI / check-i18n (push) Has been cancelled
Web App CI / check-external-links (push) Has been cancelled
Web App CI / test (platform) (push) Has been cancelled
Web App CI / test (mattermost-redux) (push) Has been cancelled
Web App CI / test (channels shard 1/4) (push) Has been cancelled
Web App CI / test (channels shard 2/4) (push) Has been cancelled
Web App CI / test (channels shard 3/4) (push) Has been cancelled
Web App CI / test (channels shard 4/4) (push) Has been cancelled
Web App CI / upload-coverage (push) Has been cancelled
Web App CI / build (push) Has been cancelled
YAML Lint / yamllint (push) Has been cancelled
Push mirrored docker images / cd/Push mirrored docker images (push) Has been cancelled
docs-cd / Build and deploy docs (push) Has been cancelled
Docs CI / build (push) Has been cancelled
E2E Cache Warm: Cypress deps / Warm Cypress deps cache (push) Has been cancelled
Scorecards supply-chain security / Scorecard analysis (push) Has been cancelled
Server CI Weekly / Postgres FIPS (push) Has been skipped
Server CI Weekly / Run mmctl tests (FIPS) (push) Has been skipped
Server CI Weekly / Postgres with binary parameters (push) Has been skipped
Server CI Weekly / Build Environment (push) Failing after 1s
Server CI Nightly Race / Build Environment (push) Failing after 1s
Server CI Cache Warm / Warm Go Module and Build Cache (push) Failing after 2s
589 lines
15 KiB
Go
589 lines
15 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")
|
|
})
|
|
}
|
|
|
|
// TestResolveOptionNamesToIDs covers the assignment side of rank-typed
|
|
// attribute resolution: when an admin sets a rank value by option name, the
|
|
// name is resolved to the stored option ID. Rank fields share the single-value
|
|
// resolution path with select fields.
|
|
func (s *MmctlUnitTestSuite) TestResolveOptionNamesToIDs() {
|
|
secretID := model.NewId()
|
|
topSecretID := model.NewId()
|
|
rankField := &model.PropertyField{
|
|
ID: model.NewId(),
|
|
Name: "clearance",
|
|
Type: model.PropertyFieldTypeRank,
|
|
Attrs: model.StringInterface{
|
|
model.PropertyFieldAttributeOptions: []any{
|
|
map[string]any{"id": secretID, "name": "SECRET", "rank": 2},
|
|
map[string]any{"id": topSecretID, "name": "TOP SECRET", "rank": 3},
|
|
},
|
|
},
|
|
}
|
|
|
|
s.Run("resolves an option name to its ID for assignment", func() {
|
|
resolved, err := resolveOptionNamesToIDs(rankField, []string{"TOP SECRET"})
|
|
s.Require().NoError(err)
|
|
s.Equal([]string{topSecretID}, resolved)
|
|
})
|
|
|
|
s.Run("passes through a value that is already an option ID", func() {
|
|
resolved, err := resolveOptionNamesToIDs(rankField, []string{secretID})
|
|
s.Require().NoError(err)
|
|
s.Equal([]string{secretID}, resolved)
|
|
})
|
|
|
|
s.Run("passes through an unknown option name unchanged", func() {
|
|
resolved, err := resolveOptionNamesToIDs(rankField, []string{"UNKNOWN"})
|
|
s.Require().NoError(err)
|
|
s.Equal([]string{"UNKNOWN"}, resolved)
|
|
})
|
|
}
|