feat: add --username-infix to scaletest create-users (#28514)

This commit is contained in:
Callum Styan
2026-08-25 12:45:02 -07:00
committed by GitHub
parent ce59a86a81
commit f4730aed12
3 changed files with 108 additions and 2 deletions
+23 -1
View File
@@ -23,6 +23,7 @@ func (r *RootCmd) scaletestCreateUsers() *serpent.Command {
var (
count int64
templateAdminPercentage float64
usernameInfix string
noCleanup bool
tracingFlags = &scaletestTracingFlags{}
@@ -93,6 +94,15 @@ func (r *RootCmd) scaletestCreateUsers() *serpent.Command {
th := harness.NewTestHarness(strategy.toStrategy(), cleanupStrategy.toStrategy())
// The scaletest- root is always kept so the cleanup command still
// finds these users; --username-infix is inserted between it and the
// random suffix, e.g. --username-infix asdf produces usernames like
// scaletest-asdf-<random>-<id>.
userPrefix := loadtestutil.ScaleTestPrefix + "-"
if usernameInfix != "" {
userPrefix += usernameInfix + "-"
}
_, _ = fmt.Fprintln(inv.Stderr, "Creating users...")
for i := range count {
id := strconv.FormatInt(i, 10)
@@ -110,9 +120,15 @@ func (r *RootCmd) scaletestCreateUsers() *serpent.Command {
return xerrors.Errorf("create runner client: %w", err)
}
// Username and email are generated by createusers when left empty.
username, email, err := loadtestutil.GenerateUserIdentifierWithPrefix(userPrefix, id)
if err != nil {
return xerrors.Errorf("generate user identifier: %w", err)
}
config := createusers.Config{
OrganizationID: me.OrganizationIDs[0],
Username: username,
Email: email,
}
if err := config.Validate(); err != nil {
return xerrors.Errorf("validate config: %w", err)
@@ -191,6 +207,12 @@ func (r *RootCmd) scaletestCreateUsers() *serpent.Command {
Description: "Percentage of users to assign the Template Admin role to (0-100).",
Value: serpent.Float64Of(&templateAdminPercentage),
},
{
Flag: "username-infix",
Env: "CODER_SCALETEST_CREATE_USERS_USERNAME_INFIX",
Description: "Optional infix inserted between the mandatory \"scaletest-\" root and the rest of each generated username. For example --username-infix asdf produces usernames like scaletest-asdf-<random>-<id>; leave empty for the default scaletest-<random>-<id> names. Use it to partition users into disjoint pools that a matching --reuse-users run can select. The scaletest- root is always kept so the cleanup command still discovers the users.",
Value: serpent.StringOf(&usernameInfix),
},
{
Flag: "no-cleanup",
Env: "CODER_SCALETEST_NO_CLEANUP",
+13 -1
View File
@@ -21,12 +21,24 @@ const (
// The username follows the pattern: scaletest-<random>-<id>
// The email follows the pattern: <random>-<id>@scaletest.local
func GenerateUserIdentifier(id string) (username, email string, err error) {
return GenerateUserIdentifierWithPrefix(ScaleTestPrefix+"-", id)
}
// GenerateUserIdentifierWithPrefix generates a username and email for scale
// testing using a caller-supplied username prefix. The username follows the
// pattern: <prefix><random>-<id>. Callers are expected to keep the "scaletest-"
// root in prefix so users created with a custom prefix are still discovered by
// IsScaleTestUser and the scaletest cleanup command; a caller-chosen infix
// is inserted between the root and the random suffix (for example prefix
// "scaletest-asdf-" yields scaletest-asdf-<random>-<id>). The email keeps the
// scaletest domain regardless (<random>-<id>@scaletest.local).
func GenerateUserIdentifierWithPrefix(prefix, id string) (username, email string, err error) {
randStr, err := cryptorand.String(DefaultRandLength)
if err != nil {
return "", "", err
}
username = fmt.Sprintf("%s-%s-%s", ScaleTestPrefix, randStr, id)
username = fmt.Sprintf("%s%s-%s", prefix, randStr, id)
email = fmt.Sprintf("%s-%s%s", randStr, id, EmailDomain)
return username, email, nil
}
+72
View File
@@ -0,0 +1,72 @@
package loadtestutil_test
import (
"strings"
"testing"
"github.com/stretchr/testify/require"
"github.com/coder/coder/v2/scaletest/loadtestutil"
)
func TestGenerateUserIdentifierWithPrefix(t *testing.T) {
t.Parallel()
const id = "7"
cases := []struct {
name string
prefix string
wantPrefix string
}{
{
name: "default scaletest prefix",
prefix: loadtestutil.ScaleTestPrefix + "-",
wantPrefix: "scaletest-",
},
{
name: "infix inserted after scaletest root",
prefix: loadtestutil.ScaleTestPrefix + "-notif-",
wantPrefix: "scaletest-notif-",
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
username, email, err := loadtestutil.GenerateUserIdentifierWithPrefix(tc.prefix, id)
require.NoError(t, err)
// username == <prefix><random>-<id>.
require.True(t, strings.HasPrefix(username, tc.wantPrefix),
"username %q should start with %q", username, tc.wantPrefix)
require.True(t, strings.HasSuffix(username, "-"+id),
"username %q should end with %q", username, "-"+id)
randPart := strings.TrimSuffix(strings.TrimPrefix(username, tc.prefix), "-"+id)
require.Len(t, randPart, loadtestutil.DefaultRandLength)
// The email reuses the same random-id and keeps the scaletest domain.
require.Equal(t, randPart+"-"+id+loadtestutil.EmailDomain, email)
// Custom prefixes that keep the scaletest- root stay discoverable.
require.True(t, loadtestutil.IsScaleTestUser(username, email))
})
}
}
func TestGenerateUserIdentifierUsesDefaultPrefix(t *testing.T) {
t.Parallel()
username, email, err := loadtestutil.GenerateUserIdentifier("3")
require.NoError(t, err)
require.True(t, strings.HasPrefix(username, loadtestutil.ScaleTestPrefix+"-"),
"username %q should start with the scaletest- root", username)
require.True(t, strings.HasSuffix(username, "-3"),
"username %q should end with the id", username)
require.True(t, strings.HasSuffix(email, "-3"+loadtestutil.EmailDomain),
"email %q should end with the id and scaletest domain", email)
require.True(t, loadtestutil.IsScaleTestUser(username, email))
}