Skip to content

Commit 1c48610

Browse files
authored
feat(scaletest/dashboard): integrate chromedp (#9927)
* Adds a set of actions to automatically interact with a Coder instance using chromedp * Integrates the chromedp actions into the scaletest dashboard command, * Re-enables the previously disabled unit tests for scaletest/dashboard * Removes previous dashboard actions based around codersdk
1 parent 1906cc4 commit 1c48610

File tree

14 files changed

+490
-604
lines changed

14 files changed

+490
-604
lines changed

cli/exp_scaletest.go

Lines changed: 64 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"encoding/json"
66
"fmt"
77
"io"
8+
"math/rand"
89
"net/http"
910
"os"
1011
"strconv"
@@ -1046,9 +1047,10 @@ func (r *RootCmd) scaletestWorkspaceTraffic() *clibase.Cmd {
10461047

10471048
func (r *RootCmd) scaletestDashboard() *clibase.Cmd {
10481049
var (
1049-
count int64
1050-
minWait time.Duration
1051-
maxWait time.Duration
1050+
interval time.Duration
1051+
jitter time.Duration
1052+
headless bool
1053+
randSeed int64
10521054

10531055
client = &codersdk.Client{}
10541056
tracingFlags = &scaletestTracingFlags{}
@@ -1065,6 +1067,12 @@ func (r *RootCmd) scaletestDashboard() *clibase.Cmd {
10651067
r.InitClient(client),
10661068
),
10671069
Handler: func(inv *clibase.Invocation) error {
1070+
if !(interval > 0) {
1071+
return xerrors.Errorf("--interval must be greater than zero")
1072+
}
1073+
if !(jitter < interval) {
1074+
return xerrors.Errorf("--jitter must be less than --interval")
1075+
}
10681076
ctx := inv.Context()
10691077
logger := slog.Make(sloghuman.Sink(inv.Stdout)).Leveled(slog.LevelInfo)
10701078
tracerProvider, closeTracing, tracingEnabled, err := tracingFlags.provider(ctx)
@@ -1094,19 +1102,42 @@ func (r *RootCmd) scaletestDashboard() *clibase.Cmd {
10941102

10951103
th := harness.NewTestHarness(strategy.toStrategy(), cleanupStrategy.toStrategy())
10961104

1097-
for i := int64(0); i < count; i++ {
1098-
name := fmt.Sprintf("dashboard-%d", i)
1105+
users, err := getScaletestUsers(ctx, client)
1106+
if err != nil {
1107+
return xerrors.Errorf("get scaletest users")
1108+
}
1109+
1110+
for _, usr := range users {
1111+
//nolint:gosec // not used for cryptographic purposes
1112+
rndGen := rand.New(rand.NewSource(randSeed))
1113+
name := fmt.Sprintf("dashboard-%s", usr.Username)
1114+
userTokResp, err := client.CreateToken(ctx, usr.ID.String(), codersdk.CreateTokenRequest{
1115+
Lifetime: 30 * 24 * time.Hour,
1116+
Scope: "",
1117+
TokenName: fmt.Sprintf("scaletest-%d", time.Now().Unix()),
1118+
})
1119+
if err != nil {
1120+
return xerrors.Errorf("create token for user: %w", err)
1121+
}
1122+
1123+
userClient := codersdk.New(client.URL)
1124+
userClient.SetSessionToken(userTokResp.Key)
1125+
10991126
config := dashboard.Config{
1100-
MinWait: minWait,
1101-
MaxWait: maxWait,
1102-
Trace: tracingEnabled,
1103-
Logger: logger.Named(name),
1104-
RollTable: dashboard.DefaultActions,
1127+
Interval: interval,
1128+
Jitter: jitter,
1129+
Trace: tracingEnabled,
1130+
Logger: logger.Named(name),
1131+
Headless: headless,
1132+
ActionFunc: dashboard.ClickRandomElement,
1133+
RandIntn: rndGen.Intn,
11051134
}
1135+
//nolint:gocritic
1136+
logger.Info(ctx, "runner config", slog.F("min_wait", interval), slog.F("max_wait", jitter), slog.F("headless", headless), slog.F("trace", tracingEnabled))
11061137
if err := config.Validate(); err != nil {
11071138
return err
11081139
}
1109-
var runner harness.Runnable = dashboard.NewRunner(client, metrics, config)
1140+
var runner harness.Runnable = dashboard.NewRunner(userClient, metrics, config)
11101141
if tracingEnabled {
11111142
runner = &runnableTraceWrapper{
11121143
tracer: tracer,
@@ -1143,25 +1174,32 @@ func (r *RootCmd) scaletestDashboard() *clibase.Cmd {
11431174

11441175
cmd.Options = []clibase.Option{
11451176
{
1146-
Flag: "count",
1147-
Env: "CODER_SCALETEST_DASHBOARD_COUNT",
1148-
Default: "1",
1149-
Description: "Number of concurrent workers.",
1150-
Value: clibase.Int64Of(&count),
1177+
Flag: "interval",
1178+
Env: "CODER_SCALETEST_DASHBOARD_INTERVAL",
1179+
Default: "3s",
1180+
Description: "Interval between actions.",
1181+
Value: clibase.DurationOf(&interval),
11511182
},
11521183
{
1153-
Flag: "min-wait",
1154-
Env: "CODER_SCALETEST_DASHBOARD_MIN_WAIT",
1155-
Default: "100ms",
1156-
Description: "Minimum wait between fetches.",
1157-
Value: clibase.DurationOf(&minWait),
1184+
Flag: "jitter",
1185+
Env: "CODER_SCALETEST_DASHBOARD_JITTER",
1186+
Default: "2s",
1187+
Description: "Jitter between actions.",
1188+
Value: clibase.DurationOf(&jitter),
11581189
},
11591190
{
1160-
Flag: "max-wait",
1161-
Env: "CODER_SCALETEST_DASHBOARD_MAX_WAIT",
1162-
Default: "1s",
1163-
Description: "Maximum wait between fetches.",
1164-
Value: clibase.DurationOf(&maxWait),
1191+
Flag: "headless",
1192+
Env: "CODER_SCALETEST_DASHBOARD_HEADLESS",
1193+
Default: "true",
1194+
Description: "Controls headless mode. Setting to false is useful for debugging.",
1195+
Value: clibase.BoolOf(&headless),
1196+
},
1197+
{
1198+
Flag: "rand-seed",
1199+
Env: "CODER_SCALETEST_DASHBOARD_RAND_SEED",
1200+
Default: "0",
1201+
Description: "Seed for the random number generator.",
1202+
Value: clibase.Int64Of(&randSeed),
11651203
},
11661204
}
11671205

cli/exp_scaletest_test.go

Lines changed: 71 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -92,28 +92,78 @@ func TestScaleTestWorkspaceTraffic(t *testing.T) {
9292
// This test just validates that the CLI command accepts its known arguments.
9393
func TestScaleTestDashboard(t *testing.T) {
9494
t.Parallel()
95-
ctx, cancelFunc := context.WithTimeout(context.Background(), testutil.WaitMedium)
96-
defer cancelFunc()
97-
98-
log := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true})
99-
client := coderdtest.New(t, &coderdtest.Options{
100-
Logger: &log,
95+
t.Run("MinWait", func(t *testing.T) {
96+
t.Parallel()
97+
ctx, cancelFunc := context.WithTimeout(context.Background(), testutil.WaitShort)
98+
defer cancelFunc()
99+
100+
log := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true})
101+
client := coderdtest.New(t, &coderdtest.Options{
102+
Logger: &log,
103+
})
104+
_ = coderdtest.CreateFirstUser(t, client)
105+
106+
inv, root := clitest.New(t, "exp", "scaletest", "dashboard",
107+
"--interval", "0s",
108+
)
109+
clitest.SetupConfig(t, client, root)
110+
pty := ptytest.New(t)
111+
inv.Stdout = pty.Output()
112+
inv.Stderr = pty.Output()
113+
114+
err := inv.WithContext(ctx).Run()
115+
require.ErrorContains(t, err, "--interval must be greater than zero")
101116
})
102-
_ = coderdtest.CreateFirstUser(t, client)
103117

104-
inv, root := clitest.New(t, "exp", "scaletest", "dashboard",
105-
"--count", "1",
106-
"--min-wait", "100ms",
107-
"--max-wait", "1s",
108-
"--timeout", "5s",
109-
"--scaletest-prometheus-address", "127.0.0.1:0",
110-
"--scaletest-prometheus-wait", "0s",
111-
)
112-
clitest.SetupConfig(t, client, root)
113-
pty := ptytest.New(t)
114-
inv.Stdout = pty.Output()
115-
inv.Stderr = pty.Output()
118+
t.Run("MaxWait", func(t *testing.T) {
119+
t.Parallel()
120+
ctx, cancelFunc := context.WithTimeout(context.Background(), testutil.WaitShort)
121+
defer cancelFunc()
122+
123+
log := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true})
124+
client := coderdtest.New(t, &coderdtest.Options{
125+
Logger: &log,
126+
})
127+
_ = coderdtest.CreateFirstUser(t, client)
128+
129+
inv, root := clitest.New(t, "exp", "scaletest", "dashboard",
130+
"--interval", "1s",
131+
"--jitter", "1s",
132+
)
133+
clitest.SetupConfig(t, client, root)
134+
pty := ptytest.New(t)
135+
inv.Stdout = pty.Output()
136+
inv.Stderr = pty.Output()
137+
138+
err := inv.WithContext(ctx).Run()
139+
require.ErrorContains(t, err, "--jitter must be less than --interval")
140+
})
116141

117-
err := inv.WithContext(ctx).Run()
118-
require.NoError(t, err, "")
142+
t.Run("OK", func(t *testing.T) {
143+
t.Parallel()
144+
ctx, cancelFunc := context.WithTimeout(context.Background(), testutil.WaitMedium)
145+
defer cancelFunc()
146+
147+
log := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true})
148+
client := coderdtest.New(t, &coderdtest.Options{
149+
Logger: &log,
150+
})
151+
_ = coderdtest.CreateFirstUser(t, client)
152+
153+
inv, root := clitest.New(t, "exp", "scaletest", "dashboard",
154+
"--interval", "1s",
155+
"--jitter", "500ms",
156+
"--timeout", "5s",
157+
"--scaletest-prometheus-address", "127.0.0.1:0",
158+
"--scaletest-prometheus-wait", "0s",
159+
"--rand-seed", "1234567890",
160+
)
161+
clitest.SetupConfig(t, client, root)
162+
pty := ptytest.New(t)
163+
inv.Stdout = pty.Output()
164+
inv.Stderr = pty.Output()
165+
166+
err := inv.WithContext(ctx).Run()
167+
require.NoError(t, err, "")
168+
})
119169
}

go.mod

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,9 @@ require (
244244
github.com/bep/godartsass/v2 v2.0.0 // indirect
245245
github.com/bep/golibsass v1.1.1 // indirect
246246
github.com/cespare/xxhash/v2 v2.2.0 // indirect
247+
github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89 // indirect
248+
github.com/chromedp/chromedp v0.9.2 // indirect
249+
github.com/chromedp/sysutil v1.0.0 // indirect
247250
github.com/clbanning/mxj/v2 v2.7.0 // indirect
248251
github.com/cloudflare/circl v1.3.3 // indirect
249252
github.com/containerd/continuity v0.4.2-0.20230616210509-1e0d26eb2381 // indirect
@@ -273,6 +276,9 @@ require (
273276
github.com/go-test/deep v1.0.8 // indirect
274277
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4 // indirect
275278
github.com/gobwas/glob v0.2.3 // indirect
279+
github.com/gobwas/httphead v0.1.0 // indirect
280+
github.com/gobwas/pool v0.2.1 // indirect
281+
github.com/gobwas/ws v1.2.1 // indirect
276282
github.com/godbus/dbus/v5 v5.1.0 // indirect
277283
github.com/gogo/protobuf v1.3.2 // indirect
278284
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect

0 commit comments

Comments
 (0)