From 7b54130b51f6e451a802c8b4789187465a89ee3e Mon Sep 17 00:00:00 2001 From: Kugamoorthy Gajananan Date: Sun, 1 Sep 2024 17:41:59 +1000 Subject: [PATCH 1/7] Derive profile name from display name in `ProfileService.CreateProfile` Currently, clients of the API are required to derive the profile name from the display name using various transformations. This results in duplicated logic across the ecosystem, increasing complexity and potential inconsistencies. This commit scopes the logic to derive the profile name from the display name to the ProfileService.CreateProfile endpoint. By centralizing this logic, we reduce redundancy and simplify client code. Clients of the API are no longer need to implement logic to deriive the profile name when creating a new profile. Signed-off-by: Kugamoorthy Gajananan --- internal/profiles/service.go | 7 ++++- internal/profiles/util.go | 55 ++++++++++++++++++++++++++++++++++ internal/profiles/util_test.go | 54 +++++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+), 1 deletion(-) diff --git a/internal/profiles/service.go b/internal/profiles/service.go index 8bb8e4ddcc..a3aa64459b 100644 --- a/internal/profiles/service.go +++ b/internal/profiles/service.go @@ -20,6 +20,7 @@ import ( "encoding/json" "errors" "fmt" + // ignore this linter warning - this is pre-existing code, and I do not // want to change the logging library it uses at this time. // nolint:depguard @@ -129,6 +130,10 @@ func (p *profileService) CreateProfile( PopulateRuleNames(profile) displayName := profile.GetDisplayName() + + // Derive the profile name from the profile display name + name := DeriveProfileNameFromDisplayName(profile) + // if empty use the name if displayName == "" { displayName = profile.GetName() @@ -136,7 +141,7 @@ func (p *profileService) CreateProfile( params := db.CreateProfileParams{ ProjectID: projectID, - Name: profile.GetName(), + Name: name, DisplayName: displayName, Labels: profile.GetLabels(), Remediate: db.ValidateRemediateType(profile.GetRemediate()), diff --git a/internal/profiles/util.go b/internal/profiles/util.go index 7f1d85529d..5d28b04bda 100644 --- a/internal/profiles/util.go +++ b/internal/profiles/util.go @@ -21,6 +21,8 @@ import ( "io" "os" "path/filepath" + "regexp" + "strings" "github.com/rs/zerolog/log" "github.com/sqlc-dev/pqtype" @@ -299,6 +301,59 @@ func MergeDatabaseGetByNameIntoProfiles(ppl []db.GetProfileByProjectAndNameRow) return profiles } +// Derive the profile name from the profile display name +func DeriveProfileNameFromDisplayName( + profile *pb.Profile, +) (profileName string) { + + displayName := profile.GetDisplayName() + name := profile.GetName() + + if displayName != "" && name != "" { + // when both a display name and a profile name are provided + // then the profile name from the incoming request is used as the profile name + profileName = name + + // when both a display name and a profile name are provided, but the project already has a profile with that name + + } else if displayName != "" && name == "" { + // when a display name is provided, but no name + // then the profile name is created and saved based on the profile display name + + profileName = CleanDisplayName(displayName) + + } + + return profileName +} + +// The profile name should be derived from the profile display name given the following logic +func CleanDisplayName(displayName string) string { + + // Trim leading and trailing whitespace + displayName = strings.TrimSpace(displayName) + + // Remove non-alphanumeric characters + re := regexp.MustCompile(`[^a-zA-Z0-9\s]`) + displayName = re.ReplaceAllString(displayName, "") + + // Replace multiple spaces with a single space + displayName = regexp.MustCompile(`\s{2,}`).ReplaceAllString(displayName, " ") + + // Replace all whitespace with underscores + displayName = strings.ReplaceAll(displayName, " ", "_") + + // Convert to lower-case + displayName = strings.ToLower(displayName) + + // Trim to a maximum length of 63 characters + if len(displayName) > 63 { + displayName = displayName[:63] + } + + return displayName +} + func dbProfileToPB(p db.Profile) *pb.Profile { profileID := p.ID.String() project := p.ProjectID.String() diff --git a/internal/profiles/util_test.go b/internal/profiles/util_test.go index e58534fb0b..0402b12aaf 100644 --- a/internal/profiles/util_test.go +++ b/internal/profiles/util_test.go @@ -634,3 +634,57 @@ func TestFilterRulesForType(t *testing.T) { }) } } + +func TestCleanDisplayName(t *testing.T) { + tests := []struct { + name string + input string + expected string + }{ + { + name: "A short DisplayName with whitespace", + input: "My custom profile", + expected: "my_custom_profile", + }, + { + name: "A very long DisplayName with whitespaces and more than 63 characters", + input: "A very long profile name that is longer than sixty three characters and will be trimmed", + expected: "a_very_long_profile_name_that_is_longer_than_sixty_three_charac", + }, + { + name: "A DisplayName with special characters", + input: "Profile with !#$() characters", + expected: "profile_with_characters", + }, + { + name: "A DisplayName with alphanumeric values", + input: "My 1st Profile", + expected: "my_1st_profile", + }, + { + name: "A DisplayName with non-alphanumeric characters and leadning & trailing whitespaces", + input: " New, Profile! 123. This is a Test Display Name with Special Characters! ", + expected: "new_profile_123_this_is_a_test_display_name_with_special_charac", + }, + { + name: "A DisplayName with Leading and trailing white spaces", + input: " Leading and trailing spaces ", + expected: "leading_and_trailing_spaces", + }, + { + name: "A DisplayName with mix of upper and low case", + input: "UPPER CASE to lower case", + expected: "upper_case_to_lower_case", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + result := profiles.CleanDisplayName(tt.input) + if result != tt.expected { + t.Errorf("CleanDisplayName(%q) = %q; want %q", tt.input, result, tt.expected) + } + }) + } +} From 7d9e174f51604de458e93bda65373a875b585152 Mon Sep 17 00:00:00 2001 From: Kugamoorthy Gajananan Date: Sat, 7 Sep 2024 21:20:51 +1000 Subject: [PATCH 2/7] Derive profile name from display name in `ProfileService.CreateProfile` Define regexes to be a global but non exported variable. Refactor unit test to test `DeriveProfileNameFromDisplayName` instead of `cleanDisplayName` which is not exported anymore. Signed-off-by: Kugamoorthy Gajananan --- internal/profiles/util.go | 39 +++++++++++----------- internal/profiles/util_test.go | 61 ++++++++++++++++++++++++---------- 2 files changed, 62 insertions(+), 38 deletions(-) diff --git a/internal/profiles/util.go b/internal/profiles/util.go index 5d28b04bda..301adccfab 100644 --- a/internal/profiles/util.go +++ b/internal/profiles/util.go @@ -34,6 +34,10 @@ import ( pb "github.com/stacklok/minder/pkg/api/protobuf/go/minder/v1" ) +var nonAlphanumericRegex = regexp.MustCompile(`[^a-zA-Z0-9\s]`) + +var multipleSpacesRegex = regexp.MustCompile(`\s{2,}`) + // RuleValidationError is used to report errors from evaluating a rule, including // attribution of the particular error encountered. type RuleValidationError struct { @@ -301,44 +305,39 @@ func MergeDatabaseGetByNameIntoProfiles(ppl []db.GetProfileByProjectAndNameRow) return profiles } -// Derive the profile name from the profile display name +// DeriveProfileNameFromDisplayName derives the profile name from the profile display name func DeriveProfileNameFromDisplayName( profile *pb.Profile, -) (profileName string) { +) (name string) { displayName := profile.GetDisplayName() - name := profile.GetName() - - if displayName != "" && name != "" { - // when both a display name and a profile name are provided - // then the profile name from the incoming request is used as the profile name - profileName = name - - // when both a display name and a profile name are provided, but the project already has a profile with that name + name = profile.GetName() - } else if displayName != "" && name == "" { - // when a display name is provided, but no name + if displayName != "" && name == "" { + // when a display name is provided, but no profile name // then the profile name is created and saved based on the profile display name - - profileName = CleanDisplayName(displayName) - + return cleanDisplayName(displayName) } + // when both a display name and a profile name are provided + // then the profile name from the incoming request is used as the profile name + // but the project already has a profile with that name + + return name - return profileName } // The profile name should be derived from the profile display name given the following logic -func CleanDisplayName(displayName string) string { +func cleanDisplayName(displayName string) string { // Trim leading and trailing whitespace displayName = strings.TrimSpace(displayName) // Remove non-alphanumeric characters - re := regexp.MustCompile(`[^a-zA-Z0-9\s]`) - displayName = re.ReplaceAllString(displayName, "") + + displayName = nonAlphanumericRegex.ReplaceAllString(displayName, "") // Replace multiple spaces with a single space - displayName = regexp.MustCompile(`\s{2,}`).ReplaceAllString(displayName, " ") + displayName = multipleSpacesRegex.ReplaceAllString(displayName, " ") // Replace all whitespace with underscores displayName = strings.ReplaceAll(displayName, " ", "_") diff --git a/internal/profiles/util_test.go b/internal/profiles/util_test.go index 0402b12aaf..b1ff458ecf 100644 --- a/internal/profiles/util_test.go +++ b/internal/profiles/util_test.go @@ -635,55 +635,80 @@ func TestFilterRulesForType(t *testing.T) { } } -func TestCleanDisplayName(t *testing.T) { +func TestDeriveProfileNameFromDisplayName(t *testing.T) { + t.Parallel() tests := []struct { name string - input string + profile *minderv1.Profile expected string }{ { - name: "A short DisplayName with whitespace", - input: "My custom profile", + name: "A short DisplayName with whitespace", + profile: &minderv1.Profile{ + Name: "", + DisplayName: "My custom profile", + }, expected: "my_custom_profile", }, { - name: "A very long DisplayName with whitespaces and more than 63 characters", - input: "A very long profile name that is longer than sixty three characters and will be trimmed", + name: "A very long DisplayName with whitespaces and more than 63 characters", + profile: &minderv1.Profile{ + Name: "", + DisplayName: "A very long profile name that is longer than sixty three characters and will be trimmed", + }, expected: "a_very_long_profile_name_that_is_longer_than_sixty_three_charac", }, { - name: "A DisplayName with special characters", - input: "Profile with !#$() characters", + name: "A DisplayName with special characters", + profile: &minderv1.Profile{ + Name: "", + DisplayName: "Profile with !#$() characters", + }, expected: "profile_with_characters", }, { - name: "A DisplayName with alphanumeric values", - input: "My 1st Profile", + name: "A DisplayName with alphanumeric values", + profile: &minderv1.Profile{ + Name: "", + DisplayName: "My 1st Profile", + }, expected: "my_1st_profile", }, { - name: "A DisplayName with non-alphanumeric characters and leadning & trailing whitespaces", - input: " New, Profile! 123. This is a Test Display Name with Special Characters! ", + name: "A DisplayName with non-alphanumeric characters and leadning & trailing whitespaces", + profile: &minderv1.Profile{ + Name: "", + DisplayName: " New, Profile! 123. This is a Test Display Name with Special Characters! ", + }, expected: "new_profile_123_this_is_a_test_display_name_with_special_charac", }, { - name: "A DisplayName with Leading and trailing white spaces", - input: " Leading and trailing spaces ", + name: "A DisplayName with Leading and trailing white spaces", + profile: &minderv1.Profile{ + Name: "", + DisplayName: " Leading and trailing spaces ", + }, expected: "leading_and_trailing_spaces", }, { - name: "A DisplayName with mix of upper and low case", - input: "UPPER CASE to lower case", + name: "A DisplayName with mix of upper and low case", + profile: &minderv1.Profile{ + Name: "", + DisplayName: "UPPER CASE to lower case", + }, expected: "upper_case_to_lower_case", }, } for _, tt := range tests { + + tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() - result := profiles.CleanDisplayName(tt.input) + + result := profiles.DeriveProfileNameFromDisplayName(tt.profile) if result != tt.expected { - t.Errorf("CleanDisplayName(%q) = %q; want %q", tt.input, result, tt.expected) + t.Errorf("DeriveProfileNameFromDisplayName: for profile %+v, expected %s, but got %s", tt.profile, tt.expected, result) } }) } From 0fb4539b7f0a4703a5c48724e767d9d769e0908f Mon Sep 17 00:00:00 2001 From: Kugamoorthy Gajananan Date: Sat, 7 Sep 2024 23:20:59 +1000 Subject: [PATCH 3/7] Derive profile name from display name in `ProfileService.CreateProfile` Handle cases where the derived profile name already exists in the same project. Signed-off-by: Kugamoorthy Gajananan --- internal/profiles/service.go | 15 ++++++++- internal/profiles/util.go | 16 +++++++--- internal/profiles/util_test.go | 57 +++++++++++++++++++++++++++------- 3 files changed, 72 insertions(+), 16 deletions(-) diff --git a/internal/profiles/service.go b/internal/profiles/service.go index a3aa64459b..63bcba64af 100644 --- a/internal/profiles/service.go +++ b/internal/profiles/service.go @@ -131,8 +131,21 @@ func (p *profileService) CreateProfile( displayName := profile.GetDisplayName() + listParams := db.ListProfilesByProjectIDAndLabelParams{ + ProjectID: projectID, + } + + existingProfiles, err := qtx.ListProfilesByProjectIDAndLabel(ctx, listParams) + if err != nil { + return nil, status.Errorf(codes.Unknown, "failed to get profiles: %s", err) + } + + profileMap := MergeDatabaseListIntoProfiles(existingProfiles) + + existingProfileNames := make([]string, 0, len(profileMap)) + // Derive the profile name from the profile display name - name := DeriveProfileNameFromDisplayName(profile) + name := DeriveProfileNameFromDisplayName(profile, existingProfileNames) // if empty use the name if displayName == "" { diff --git a/internal/profiles/util.go b/internal/profiles/util.go index 301adccfab..11acf0e9c1 100644 --- a/internal/profiles/util.go +++ b/internal/profiles/util.go @@ -305,9 +305,10 @@ func MergeDatabaseGetByNameIntoProfiles(ppl []db.GetProfileByProjectAndNameRow) return profiles } -// DeriveProfileNameFromDisplayName derives the profile name from the profile display name +// DeriveProfileNameFromDisplayName generates a unique profile name based on the display name and existing profiles. func DeriveProfileNameFromDisplayName( profile *pb.Profile, + existingProfileNames []string, ) (name string) { displayName := profile.GetDisplayName() @@ -316,13 +317,20 @@ func DeriveProfileNameFromDisplayName( if displayName != "" && name == "" { // when a display name is provided, but no profile name // then the profile name is created and saved based on the profile display name - return cleanDisplayName(displayName) + name = cleanDisplayName(displayName) } // when both a display name and a profile name are provided // then the profile name from the incoming request is used as the profile name - // but the project already has a profile with that name - return name + derivedName := name + counter := 1 + + // check if the current project already has a profile with that name, then add a counter + for strings.Contains(strings.Join(existingProfileNames, " "), derivedName) { + derivedName = fmt.Sprintf("%s-%d", name, counter) + counter++ + } + return derivedName } diff --git a/internal/profiles/util_test.go b/internal/profiles/util_test.go index b1ff458ecf..1bc1983caf 100644 --- a/internal/profiles/util_test.go +++ b/internal/profiles/util_test.go @@ -638,9 +638,10 @@ func TestFilterRulesForType(t *testing.T) { func TestDeriveProfileNameFromDisplayName(t *testing.T) { t.Parallel() tests := []struct { - name string - profile *minderv1.Profile - expected string + name string + profile *minderv1.Profile + existingProfileNames []string + expected string }{ { name: "A short DisplayName with whitespace", @@ -648,7 +649,8 @@ func TestDeriveProfileNameFromDisplayName(t *testing.T) { Name: "", DisplayName: "My custom profile", }, - expected: "my_custom_profile", + existingProfileNames: []string{}, + expected: "my_custom_profile", }, { name: "A very long DisplayName with whitespaces and more than 63 characters", @@ -656,7 +658,8 @@ func TestDeriveProfileNameFromDisplayName(t *testing.T) { Name: "", DisplayName: "A very long profile name that is longer than sixty three characters and will be trimmed", }, - expected: "a_very_long_profile_name_that_is_longer_than_sixty_three_charac", + existingProfileNames: []string{}, + expected: "a_very_long_profile_name_that_is_longer_than_sixty_three_charac", }, { name: "A DisplayName with special characters", @@ -664,7 +667,8 @@ func TestDeriveProfileNameFromDisplayName(t *testing.T) { Name: "", DisplayName: "Profile with !#$() characters", }, - expected: "profile_with_characters", + existingProfileNames: []string{}, + expected: "profile_with_characters", }, { name: "A DisplayName with alphanumeric values", @@ -672,7 +676,8 @@ func TestDeriveProfileNameFromDisplayName(t *testing.T) { Name: "", DisplayName: "My 1st Profile", }, - expected: "my_1st_profile", + existingProfileNames: []string{}, + expected: "my_1st_profile", }, { name: "A DisplayName with non-alphanumeric characters and leadning & trailing whitespaces", @@ -680,7 +685,8 @@ func TestDeriveProfileNameFromDisplayName(t *testing.T) { Name: "", DisplayName: " New, Profile! 123. This is a Test Display Name with Special Characters! ", }, - expected: "new_profile_123_this_is_a_test_display_name_with_special_charac", + existingProfileNames: []string{}, + expected: "new_profile_123_this_is_a_test_display_name_with_special_charac", }, { name: "A DisplayName with Leading and trailing white spaces", @@ -688,7 +694,8 @@ func TestDeriveProfileNameFromDisplayName(t *testing.T) { Name: "", DisplayName: " Leading and trailing spaces ", }, - expected: "leading_and_trailing_spaces", + existingProfileNames: []string{}, + expected: "leading_and_trailing_spaces", }, { name: "A DisplayName with mix of upper and low case", @@ -696,7 +703,35 @@ func TestDeriveProfileNameFromDisplayName(t *testing.T) { Name: "", DisplayName: "UPPER CASE to lower case", }, - expected: "upper_case_to_lower_case", + existingProfileNames: []string{}, + expected: "upper_case_to_lower_case", + }, + { + name: "Derived profile name does not exist in the current project", + profile: &minderv1.Profile{ + Name: "", + DisplayName: "My profile", + }, + existingProfileNames: []string{"other_profile", "custom_profile"}, + expected: "my_profile", + }, + { + name: "Derived profile name does exist in the current project", + profile: &minderv1.Profile{ + Name: "", + DisplayName: "My profile", + }, + existingProfileNames: []string{"other_profile", "my_profile"}, + expected: "my_profile-1", + }, + { + name: "Derived profile name does exist in the current project", + profile: &minderv1.Profile{ + Name: "", + DisplayName: "My profile", + }, + existingProfileNames: []string{"other_profile", "my_profile", "my_profile-1"}, + expected: "my_profile-2", }, } @@ -706,7 +741,7 @@ func TestDeriveProfileNameFromDisplayName(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - result := profiles.DeriveProfileNameFromDisplayName(tt.profile) + result := profiles.DeriveProfileNameFromDisplayName(tt.profile, tt.existingProfileNames) if result != tt.expected { t.Errorf("DeriveProfileNameFromDisplayName: for profile %+v, expected %s, but got %s", tt.profile, tt.expected, result) } From fd597b963cf45675ee5f3d79905ba39f4ac86243 Mon Sep 17 00:00:00 2001 From: Kugamoorthy Gajananan Date: Sat, 7 Sep 2024 23:24:08 +1000 Subject: [PATCH 4/7] Derive profile name from display name in `ProfileService.CreateProfile` Remove empty line Signed-off-by: Kugamoorthy Gajananan --- internal/profiles/util.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/profiles/util.go b/internal/profiles/util.go index 11acf0e9c1..b34e775034 100644 --- a/internal/profiles/util.go +++ b/internal/profiles/util.go @@ -341,7 +341,6 @@ func cleanDisplayName(displayName string) string { displayName = strings.TrimSpace(displayName) // Remove non-alphanumeric characters - displayName = nonAlphanumericRegex.ReplaceAllString(displayName, "") // Replace multiple spaces with a single space From 2aaba5f174250f66adc06edb47909042d8b659b3 Mon Sep 17 00:00:00 2001 From: Kugamoorthy Gajananan Date: Mon, 9 Sep 2024 21:58:52 +1000 Subject: [PATCH 5/7] Derive profile name from display name in `ProfileService.CreateProfile` Added additional test to increase coverage Signed-off-by: Kugamoorthy Gajananan --- internal/profiles/util_test.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/internal/profiles/util_test.go b/internal/profiles/util_test.go index 1bc1983caf..aa80043082 100644 --- a/internal/profiles/util_test.go +++ b/internal/profiles/util_test.go @@ -643,6 +643,15 @@ func TestDeriveProfileNameFromDisplayName(t *testing.T) { existingProfileNames []string expected string }{ + { + name: "A short DisplayName with whitespace", + profile: &minderv1.Profile{ + Name: "profile_name", + DisplayName: "", + }, + existingProfileNames: []string{}, + expected: "profile_name", + }, { name: "A short DisplayName with whitespace", profile: &minderv1.Profile{ From a06ba8a72203b4acc9ef49fe4c2958134aaf16cc Mon Sep 17 00:00:00 2001 From: Kugamoorthy Gajananan Date: Fri, 13 Sep 2024 19:50:38 +1000 Subject: [PATCH 6/7] Derive profile name from display name in `ProfileService.CreateProfile` Fixed duplicated test names Fixed DeriveProfileNameFromDisplayName to handle the edge cases where the name will exceed 63 characters once we append the counter. Added unit-tests for edge cases Signed-off-by: Kugamoorthy Gajananan --- internal/profiles/util.go | 8 +++++++- internal/profiles/util_test.go | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/internal/profiles/util.go b/internal/profiles/util.go index b34e775034..0226245f01 100644 --- a/internal/profiles/util.go +++ b/internal/profiles/util.go @@ -38,6 +38,8 @@ var nonAlphanumericRegex = regexp.MustCompile(`[^a-zA-Z0-9\s]`) var multipleSpacesRegex = regexp.MustCompile(`\s{2,}`) +const profileNameMaxLength = 63 + // RuleValidationError is used to report errors from evaluating a rule, including // attribution of the particular error encountered. type RuleValidationError struct { @@ -328,6 +330,10 @@ func DeriveProfileNameFromDisplayName( // check if the current project already has a profile with that name, then add a counter for strings.Contains(strings.Join(existingProfileNames, " "), derivedName) { derivedName = fmt.Sprintf("%s-%d", name, counter) + if len(derivedName) > profileNameMaxLength { + nameLength := profileNameMaxLength - len(fmt.Sprintf("-%d", counter)) + derivedName = fmt.Sprintf("%s-%d", name[:nameLength], counter) + } counter++ } return derivedName @@ -353,7 +359,7 @@ func cleanDisplayName(displayName string) string { displayName = strings.ToLower(displayName) // Trim to a maximum length of 63 characters - if len(displayName) > 63 { + if len(displayName) > profileNameMaxLength { displayName = displayName[:63] } diff --git a/internal/profiles/util_test.go b/internal/profiles/util_test.go index aa80043082..6cda3da580 100644 --- a/internal/profiles/util_test.go +++ b/internal/profiles/util_test.go @@ -725,7 +725,7 @@ func TestDeriveProfileNameFromDisplayName(t *testing.T) { expected: "my_profile", }, { - name: "Derived profile name does exist in the current project", + name: "Derived profile name that does exist in the current project", profile: &minderv1.Profile{ Name: "", DisplayName: "My profile", @@ -734,7 +734,7 @@ func TestDeriveProfileNameFromDisplayName(t *testing.T) { expected: "my_profile-1", }, { - name: "Derived profile name does exist in the current project", + name: "Derived profile name which does exist in the current project, when adding a counter to the name", profile: &minderv1.Profile{ Name: "", DisplayName: "My profile", @@ -742,6 +742,35 @@ func TestDeriveProfileNameFromDisplayName(t *testing.T) { existingProfileNames: []string{"other_profile", "my_profile", "my_profile-1"}, expected: "my_profile-2", }, + { + name: "Derived profile name for the edge case: name exceeds 63 characters with single digit counter", + profile: &minderv1.Profile{ + Name: "", + DisplayName: "This is a very long display name that will exceed the limit when counter is added", + }, + existingProfileNames: []string{"this_is_a_very_long_display_name_that_will_exceed_the_limit_when"}, + expected: "this_is_a_very_long_display_name_that_will_exceed_the_limit_w-1", + }, + { + name: "Derived profile name for the edge case: name exceeds 63 characters with double digit counter", + profile: &minderv1.Profile{ + Name: "", + DisplayName: "This is a very long display name that will exceed the limit when counter is added", + }, + existingProfileNames: []string{ + "this_is_a_very_long_display_name_that_will_exceed_the_limit_when", + "this_is_a_very_long_display_name_that_will_exceed_the_limit_w-1", + "this_is_a_very_long_display_name_that_will_exceed_the_limit_w-2", + "this_is_a_very_long_display_name_that_will_exceed_the_limit_w-3", + "this_is_a_very_long_display_name_that_will_exceed_the_limit_w-4", + "this_is_a_very_long_display_name_that_will_exceed_the_limit_w-5", + "this_is_a_very_long_display_name_that_will_exceed_the_limit_w-6", + "this_is_a_very_long_display_name_that_will_exceed_the_limit_w-7", + "this_is_a_very_long_display_name_that_will_exceed_the_limit_w-8", + "this_is_a_very_long_display_name_that_will_exceed_the_limit_w-9", + }, + expected: "this_is_a_very_long_display_name_that_will_exceed_the_limit_-10", + }, } for _, tt := range tests { From c5195568a267db723e62f7a12e2cb4e832214a98 Mon Sep 17 00:00:00 2001 From: Kugamoorthy Gajananan Date: Fri, 13 Sep 2024 20:03:43 +1000 Subject: [PATCH 7/7] Derive profile name from display name in `ProfileService.CreateProfile` Remoed hardcoded value for profileNameMaxLength Signed-off-by: Kugamoorthy Gajananan --- internal/profiles/util.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/profiles/util.go b/internal/profiles/util.go index 0226245f01..fef336730f 100644 --- a/internal/profiles/util.go +++ b/internal/profiles/util.go @@ -360,7 +360,7 @@ func cleanDisplayName(displayName string) string { // Trim to a maximum length of 63 characters if len(displayName) > profileNameMaxLength { - displayName = displayName[:63] + displayName = displayName[:profileNameMaxLength] } return displayName