Skip to content

Commit 593a1e9

Browse files
authored
feat(cli/exp): add target workspace/users to scaletest commands (#11701)
1 parent 4b059c4 commit 593a1e9

File tree

2 files changed

+128
-10
lines changed

2 files changed

+128
-10
lines changed

cli/exp_scaletest.go

+80-10
Original file line numberDiff line numberDiff line change
@@ -857,11 +857,12 @@ func (r *RootCmd) scaletestCreateWorkspaces() *clibase.Cmd {
857857

858858
func (r *RootCmd) scaletestWorkspaceTraffic() *clibase.Cmd {
859859
var (
860-
tickInterval time.Duration
861-
bytesPerTick int64
862-
ssh bool
863-
app string
864-
template string
860+
tickInterval time.Duration
861+
bytesPerTick int64
862+
ssh bool
863+
app string
864+
template string
865+
targetWorkspaces string
865866

866867
client = &codersdk.Client{}
867868
tracingFlags = &scaletestTracingFlags{}
@@ -912,6 +913,10 @@ func (r *RootCmd) scaletestWorkspaceTraffic() *clibase.Cmd {
912913
return xerrors.Errorf("parse template: %w", err)
913914
}
914915
}
916+
targetWorkspaceStart, targetWorkspaceEnd, err := parseTargetRange("workspaces", targetWorkspaces)
917+
if err != nil {
918+
return xerrors.Errorf("parse target workspaces: %w", err)
919+
}
915920

916921
appHost, err := client.AppHost(ctx)
917922
if err != nil {
@@ -923,9 +928,16 @@ func (r *RootCmd) scaletestWorkspaceTraffic() *clibase.Cmd {
923928
return err
924929
}
925930

931+
if targetWorkspaceEnd == 0 {
932+
targetWorkspaceEnd = len(workspaces)
933+
}
934+
926935
if len(workspaces) == 0 {
927936
return xerrors.Errorf("no scaletest workspaces exist")
928937
}
938+
if targetWorkspaceEnd > len(workspaces) {
939+
return xerrors.Errorf("target workspace end %d is greater than the number of workspaces %d", targetWorkspaceEnd, len(workspaces))
940+
}
929941

930942
tracerProvider, closeTracing, tracingEnabled, err := tracingFlags.provider(ctx)
931943
if err != nil {
@@ -951,6 +963,10 @@ func (r *RootCmd) scaletestWorkspaceTraffic() *clibase.Cmd {
951963

952964
th := harness.NewTestHarness(strategy.toStrategy(), cleanupStrategy.toStrategy())
953965
for idx, ws := range workspaces {
966+
if idx < targetWorkspaceStart || idx >= targetWorkspaceEnd {
967+
continue
968+
}
969+
954970
var (
955971
agent codersdk.WorkspaceAgent
956972
name = "workspace-traffic"
@@ -1039,6 +1055,12 @@ func (r *RootCmd) scaletestWorkspaceTraffic() *clibase.Cmd {
10391055
Description: "Name or ID of the template. Traffic generation will be limited to workspaces created from this template.",
10401056
Value: clibase.StringOf(&template),
10411057
},
1058+
{
1059+
Flag: "target-workspaces",
1060+
Env: "CODER_SCALETEST_TARGET_WORKSPACES",
1061+
Description: "Target a specific range of workspaces in the format [START]:[END] (exclusive). Example: 0:10 will target the 10 first alphabetically sorted workspaces (0-9).",
1062+
Value: clibase.StringOf(&targetWorkspaces),
1063+
},
10421064
{
10431065
Flag: "bytes-per-tick",
10441066
Env: "CODER_SCALETEST_WORKSPACE_TRAFFIC_BYTES_PER_TICK",
@@ -1080,10 +1102,11 @@ func (r *RootCmd) scaletestWorkspaceTraffic() *clibase.Cmd {
10801102

10811103
func (r *RootCmd) scaletestDashboard() *clibase.Cmd {
10821104
var (
1083-
interval time.Duration
1084-
jitter time.Duration
1085-
headless bool
1086-
randSeed int64
1105+
interval time.Duration
1106+
jitter time.Duration
1107+
headless bool
1108+
randSeed int64
1109+
targetUsers string
10871110

10881111
client = &codersdk.Client{}
10891112
tracingFlags = &scaletestTracingFlags{}
@@ -1106,6 +1129,10 @@ func (r *RootCmd) scaletestDashboard() *clibase.Cmd {
11061129
if !(jitter < interval) {
11071130
return xerrors.Errorf("--jitter must be less than --interval")
11081131
}
1132+
targetUserStart, targetUserEnd, err := parseTargetRange("users", targetUsers)
1133+
if err != nil {
1134+
return xerrors.Errorf("parse target users: %w", err)
1135+
}
11091136
ctx := inv.Context()
11101137
logger := inv.Logger.AppendSinks(sloghuman.Sink(inv.Stdout))
11111138
if r.verbose {
@@ -1142,8 +1169,15 @@ func (r *RootCmd) scaletestDashboard() *clibase.Cmd {
11421169
if err != nil {
11431170
return xerrors.Errorf("get scaletest users")
11441171
}
1172+
if targetUserEnd == 0 {
1173+
targetUserEnd = len(users)
1174+
}
1175+
1176+
for idx, usr := range users {
1177+
if idx < targetUserStart || idx >= targetUserEnd {
1178+
continue
1179+
}
11451180

1146-
for _, usr := range users {
11471181
//nolint:gosec // not used for cryptographic purposes
11481182
rndGen := rand.New(rand.NewSource(randSeed))
11491183
name := fmt.Sprintf("dashboard-%s", usr.Username)
@@ -1214,6 +1248,12 @@ func (r *RootCmd) scaletestDashboard() *clibase.Cmd {
12141248
}
12151249

12161250
cmd.Options = []clibase.Option{
1251+
{
1252+
Flag: "target-users",
1253+
Env: "CODER_SCALETEST_DASHBOARD_TARGET_USERS",
1254+
Description: "Target a specific range of users in the format [START]:[END] (exclusive). Example: 0:10 will target the 10 first alphabetically sorted users (0-9).",
1255+
Value: clibase.StringOf(&targetUsers),
1256+
},
12171257
{
12181258
Flag: "interval",
12191259
Env: "CODER_SCALETEST_DASHBOARD_INTERVAL",
@@ -1430,6 +1470,36 @@ func parseTemplate(ctx context.Context, client *codersdk.Client, organizationIDs
14301470
return tpl, nil
14311471
}
14321472

1473+
func parseTargetRange(name, targets string) (start, end int, err error) {
1474+
if targets == "" {
1475+
return 0, 0, nil
1476+
}
1477+
1478+
parts := strings.Split(targets, ":")
1479+
if len(parts) != 2 {
1480+
return 0, 0, xerrors.Errorf("invalid target %s %q", name, targets)
1481+
}
1482+
1483+
start, err = strconv.Atoi(parts[0])
1484+
if err != nil {
1485+
return 0, 0, xerrors.Errorf("invalid target %s %q: %w", name, targets, err)
1486+
}
1487+
1488+
end, err = strconv.Atoi(parts[1])
1489+
if err != nil {
1490+
return 0, 0, xerrors.Errorf("invalid target %s %q: %w", name, targets, err)
1491+
}
1492+
1493+
if start == end {
1494+
return 0, 0, xerrors.Errorf("invalid target %s %q: start and end cannot be equal", name, targets)
1495+
}
1496+
if end < start {
1497+
return 0, 0, xerrors.Errorf("invalid target %s %q: end cannot be less than start", name, targets)
1498+
}
1499+
1500+
return start, end, nil
1501+
}
1502+
14331503
func createWorkspaceAppConfig(client *codersdk.Client, appHost, app string, workspace codersdk.Workspace, agent codersdk.WorkspaceAgent) (workspacetraffic.AppConfig, error) {
14341504
if app == "" {
14351505
return workspacetraffic.AppConfig{}, nil

cli/exp_scaletest_test.go

+48
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,31 @@ func TestScaleTestWorkspaceTraffic_Template(t *testing.T) {
116116
require.ErrorContains(t, err, "could not find template \"doesnotexist\" in any organization")
117117
}
118118

119+
// This test just validates that the CLI command accepts its known arguments.
120+
func TestScaleTestWorkspaceTraffic_TargetWorkspaces(t *testing.T) {
121+
t.Parallel()
122+
123+
ctx, cancelFunc := context.WithTimeout(context.Background(), testutil.WaitMedium)
124+
defer cancelFunc()
125+
126+
log := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true})
127+
client := coderdtest.New(t, &coderdtest.Options{
128+
Logger: &log,
129+
})
130+
_ = coderdtest.CreateFirstUser(t, client)
131+
132+
inv, root := clitest.New(t, "exp", "scaletest", "workspace-traffic",
133+
"--target-workspaces", "0:0",
134+
)
135+
clitest.SetupConfig(t, client, root)
136+
pty := ptytest.New(t)
137+
inv.Stdout = pty.Output()
138+
inv.Stderr = pty.Output()
139+
140+
err := inv.WithContext(ctx).Run()
141+
require.ErrorContains(t, err, "invalid target workspaces \"0:0\": start and end cannot be equal")
142+
}
143+
119144
// This test just validates that the CLI command accepts its known arguments.
120145
func TestScaleTestCleanup_Template(t *testing.T) {
121146
t.Parallel()
@@ -218,4 +243,27 @@ func TestScaleTestDashboard(t *testing.T) {
218243
err := inv.WithContext(ctx).Run()
219244
require.NoError(t, err, "")
220245
})
246+
247+
t.Run("TargetUsers", func(t *testing.T) {
248+
t.Parallel()
249+
ctx, cancelFunc := context.WithTimeout(context.Background(), testutil.WaitMedium)
250+
defer cancelFunc()
251+
252+
log := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true})
253+
client := coderdtest.New(t, &coderdtest.Options{
254+
Logger: &log,
255+
})
256+
_ = coderdtest.CreateFirstUser(t, client)
257+
258+
inv, root := clitest.New(t, "exp", "scaletest", "dashboard",
259+
"--target-users", "0:0",
260+
)
261+
clitest.SetupConfig(t, client, root)
262+
pty := ptytest.New(t)
263+
inv.Stdout = pty.Output()
264+
inv.Stderr = pty.Output()
265+
266+
err := inv.WithContext(ctx).Run()
267+
require.ErrorContains(t, err, "invalid target users \"0:0\": start and end cannot be equal")
268+
})
221269
}

0 commit comments

Comments
 (0)