Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commita368b05

Browse files
committed
feat: add scaletest Runner for dynamicparameters load gen
1 parent6238937 commita368b05

File tree

6 files changed

+361
-0
lines changed

6 files changed

+361
-0
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package dynamicparameters
2+
3+
import"github.com/google/uuid"
4+
5+
typeConfigstruct {
6+
TemplateVersion uuid.UUID`json:"template_version"`
7+
SessionTokenstring`json:"session_token"`
8+
Metrics*Metrics`json:"-"`
9+
MetricLabelValues []string`json:"metric_label_values"`
10+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package dynamicparameters
2+
3+
import"github.com/prometheus/client_golang/prometheus"
4+
5+
typeMetricsstruct {
6+
LatencyInitialResponseSeconds prometheus.HistogramVec
7+
LatencyChangeResponseSeconds prometheus.HistogramVec
8+
}
9+
10+
funcNewMetrics(reg prometheus.Registerer,labelNames...string)*Metrics {
11+
m:=&Metrics{
12+
LatencyInitialResponseSeconds:*prometheus.NewHistogramVec(prometheus.HistogramOpts{
13+
Namespace:"coderd",
14+
Subsystem:"scaletest",
15+
Name:"dynamic_parameters_latency_initial_response_seconds",
16+
Help:"Time in seconds to get the initial dynamic parameters response from start of request.",
17+
},labelNames),
18+
LatencyChangeResponseSeconds:*prometheus.NewHistogramVec(prometheus.HistogramOpts{
19+
Namespace:"coderd",
20+
Subsystem:"scaletest",
21+
Name:"dynamic_parameters_latency_change_response_seconds",
22+
Help:"Time in seconds to between sending a dynamic parameters change request and receiving the response.",
23+
},labelNames),
24+
}
25+
reg.MustRegister(m.LatencyInitialResponseSeconds)
26+
reg.MustRegister(m.LatencyChangeResponseSeconds)
27+
returnm
28+
}

‎scaletest/dynamicparameters/run.go‎

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package dynamicparameters
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"io"
7+
"slices"
8+
"time"
9+
10+
"golang.org/x/xerrors"
11+
12+
"github.com/coder/coder/v2/codersdk"
13+
"github.com/coder/coder/v2/scaletest/harness"
14+
"github.com/coder/websocket"
15+
)
16+
17+
typeRunnerstruct {
18+
client*codersdk.Client
19+
cfgConfig
20+
}
21+
22+
var_ harness.Runnable=&Runner{}
23+
24+
funcNewRunner(client*codersdk.Client,cfgConfig)*Runner {
25+
clone:=codersdk.New(client.URL)
26+
clone.HTTPClient=client.HTTPClient
27+
clone.SetLogger(client.Logger())
28+
clone.SetSessionToken(cfg.SessionToken)
29+
return&Runner{
30+
client:clone,
31+
cfg:cfg,
32+
}
33+
}
34+
35+
// Run executes the dynamic parameters test, which:
36+
//
37+
// 1. connects to the dynamic parameters stream
38+
// 2. waits for the initial response
39+
// 3. sends a change request
40+
// 4. waits for the change response
41+
// 5. closes the stream
42+
func (r*Runner)Run(ctx context.Context,_string,logs io.Writer) (retErrerror) {
43+
startTime:=time.Now()
44+
stream,err:=r.client.TemplateVersionDynamicParameters(ctx,codersdk.Me,r.cfg.TemplateVersion)
45+
iferr!=nil {
46+
returnxerrors.Errorf("connect to dynamic parameters stream: %w",err)
47+
}
48+
deferstream.Close(websocket.StatusNormalClosure)
49+
respCh:=stream.Chan()
50+
51+
varinitTime time.Time
52+
select {
53+
case<-ctx.Done():
54+
returnctx.Err()
55+
caseresp,ok:=<-respCh:
56+
if!ok {
57+
returnxerrors.Errorf("dynamic parameters stream closed before initial response")
58+
}
59+
initTime=time.Now()
60+
r.cfg.Metrics.LatencyInitialResponseSeconds.
61+
WithLabelValues(r.cfg.MetricLabelValues...).
62+
Observe(initTime.Sub(startTime).Seconds())
63+
_,_=fmt.Fprintf(logs,"initial response: %+v\n",resp)
64+
if!slices.ContainsFunc(resp.Parameters,func(p codersdk.PreviewParameter)bool {
65+
returnp.Name=="zero"
66+
}) {
67+
returnxerrors.Errorf("mising expected parameter: 'zero'")
68+
}
69+
iferr:=checkNoDiagnostics(resp);err!=nil {
70+
returnxerrors.Errorf("unexpected initial response diagnostics: %w",err)
71+
}
72+
}
73+
74+
err=stream.Send(codersdk.DynamicParametersRequest{
75+
ID:1,
76+
Inputs:map[string]string{
77+
"zero":"B",
78+
},
79+
})
80+
iferr!=nil {
81+
returnxerrors.Errorf("send change request: %w",err)
82+
}
83+
select {
84+
case<-ctx.Done():
85+
returnctx.Err()
86+
caseresp,ok:=<-respCh:
87+
if!ok {
88+
returnxerrors.Errorf("dynamic parameters stream closed before change response")
89+
}
90+
_,_=fmt.Fprintf(logs,"change response: %+v\n",resp)
91+
r.cfg.Metrics.LatencyChangeResponseSeconds.
92+
WithLabelValues(r.cfg.MetricLabelValues...).
93+
Observe(time.Since(initTime).Seconds())
94+
ifresp.ID!=1 {
95+
returnxerrors.Errorf("unexpected response ID: %d",resp.ID)
96+
}
97+
iferr:=checkNoDiagnostics(resp);err!=nil {
98+
returnxerrors.Errorf("unexpected change response diagnostics: %w",err)
99+
}
100+
returnnil
101+
}
102+
}
103+
104+
funccheckNoDiagnostics(resp codersdk.DynamicParametersResponse)error {
105+
iflen(resp.Diagnostics)!=0 {
106+
returnxerrors.Errorf("unexpected response diagnostics: %v",resp.Diagnostics)
107+
}
108+
for_,param:=rangeresp.Parameters {
109+
iflen(param.Diagnostics)!=0 {
110+
returnxerrors.Errorf("unexpected parameter diagnostics for '%s': %v",param.Name,param.Diagnostics)
111+
}
112+
}
113+
returnnil
114+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package dynamicparameters_test
2+
3+
import (
4+
"strings"
5+
"testing"
6+
7+
"github.com/prometheus/client_golang/prometheus"
8+
"github.com/stretchr/testify/require"
9+
10+
"github.com/coder/coder/v2/coderd/coderdtest"
11+
"github.com/coder/coder/v2/scaletest/dynamicparameters"
12+
"github.com/coder/coder/v2/testutil"
13+
)
14+
15+
funcTestRun(t*testing.T) {
16+
t.Parallel()
17+
ctx:=testutil.Context(t,testutil.WaitLong)
18+
19+
client:=coderdtest.New(t,&coderdtest.Options{IncludeProvisionerDaemon:true})
20+
first:=coderdtest.CreateFirstUser(t,client)
21+
userClient,_:=coderdtest.CreateAnotherUser(t,client,first.OrganizationID)
22+
orgID:=first.OrganizationID
23+
24+
dynamicParametersTerraformSource,err:=dynamicparameters.TemplateContent()
25+
require.NoError(t,err)
26+
27+
template,version:=coderdtest.DynamicParameterTemplate(t,client,orgID, coderdtest.DynamicParameterTemplateParams{
28+
MainTF:dynamicParametersTerraformSource,
29+
Plan:nil,
30+
ModulesArchive:nil,
31+
StaticParams:nil,
32+
})
33+
34+
reg:=prometheus.NewRegistry()
35+
cfg:= dynamicparameters.Config{
36+
TemplateVersion:version.ID,
37+
SessionToken:userClient.SessionToken(),
38+
Metrics:dynamicparameters.NewMetrics(reg,"template","test_label_name"),
39+
MetricLabelValues: []string{template.Name,"test_label_value"},
40+
}
41+
runner:=dynamicparameters.NewRunner(userClient,cfg)
42+
varlogs strings.Builder
43+
err=runner.Run(ctx,t.Name(),&logs)
44+
t.Log("Runner logs:\n\n"+logs.String())
45+
require.NoError(t,err)
46+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package dynamicparameters
2+
3+
import (
4+
_"embed"
5+
"strings"
6+
"text/template"
7+
8+
"github.com/coder/coder/v2/cryptorand"
9+
)
10+
11+
//go:embed workspace-template.tf
12+
vartemplateContentstring
13+
14+
funcTemplateContent() (string,error) {
15+
randomString,err:=cryptorand.String(8)
16+
iferr!=nil {
17+
return"",err
18+
}
19+
20+
// Parse the template
21+
tmpl,err:=template.New("workspace-template").Parse(templateContent)
22+
iferr!=nil {
23+
return"",err
24+
}
25+
26+
// Execute the template with the random string
27+
varresult strings.Builder
28+
err=tmpl.Execute(&result,map[string]string{
29+
"RandomString":randomString,
30+
})
31+
iferr!=nil {
32+
// Return the original template if execution fails
33+
return"",err
34+
}
35+
36+
returnresult.String(),nil
37+
}
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# Cache busting string so each copy of the template is unique: {{.RandomString}}
2+
terraform {
3+
required_providers {
4+
coder={
5+
source="coder/coder"
6+
version="2.5.3"
7+
}
8+
}
9+
}
10+
11+
locals {
12+
one_options={
13+
"A"= ["AA","AB"]
14+
"B"= ["BA","BB"]
15+
}
16+
17+
three_options={
18+
"AA"= ["AAA","AAB"]
19+
"AB"= ["ABA","ABB"]
20+
"BA"= ["BAA","BAB"]
21+
"BB"= ["BBA","BBB"]
22+
}
23+
24+
username=data.coder_workspace_owner.me.name
25+
}
26+
27+
data"coder_workspace_owner""me" {}
28+
29+
data"coder_parameter""zero" {
30+
name="zero"
31+
display_name="Root"
32+
description="Hello${local.username}, pick your next parameter using this `dropdown` parameter."
33+
form_type="dropdown"
34+
mutable=true
35+
default="A"
36+
37+
option {
38+
value="A"
39+
name="A"
40+
}
41+
42+
option {
43+
value="B"
44+
name="B"
45+
}
46+
}
47+
48+
data"coder_parameter""one" {
49+
50+
name="One"
51+
display_name="Level One"
52+
description="This is the first level."
53+
54+
type="list(string)"
55+
form_type="multi-select"
56+
order=2
57+
mutable=true
58+
default="[\"${local.one_options[data.coder_parameter.zero.value][0]}\"]"
59+
60+
dynamic"option" {
61+
for_each=local.one_options[data.coder_parameter.zero.value]
62+
content {
63+
name=option.value
64+
value=option.value
65+
}
66+
}
67+
}
68+
69+
data"coder_parameter""two" {
70+
71+
name="Two"
72+
display_name="Level Two"
73+
description="This is the second level."
74+
75+
type="string"
76+
form_type="textarea"
77+
order=3
78+
mutable=true
79+
80+
default=trim(data.coder_parameter.one.value,"[\"]")
81+
}
82+
83+
data"coder_parameter""three" {
84+
85+
name="Three"
86+
display_name="Level Three"
87+
description="This is the first level."
88+
89+
type="string"
90+
form_type="radio"
91+
order=4
92+
mutable=true
93+
default=local.three_options[data.coder_parameter.two.value][0]
94+
95+
dynamic"option" {
96+
for_each=local.three_options[data.coder_parameter.two.value]
97+
content {
98+
name=option.value
99+
value=option.value
100+
}
101+
}
102+
}
103+
104+
data"coder_parameter""four" {
105+
name="four"
106+
display_name="Level Four"
107+
description="This is the last level."
108+
order=5
109+
110+
type="string"
111+
form_type="radio"
112+
default="a_fake_value_to_satify_import"
113+
114+
option {
115+
name=format("%s-%s", local.username, data.coder_parameter.three.value)
116+
value="a_fake_value_to_satify_import"
117+
}
118+
119+
dynamic"option" {
120+
for_each=data.coder_workspace_owner.me.rbac_roles
121+
content {
122+
name=format("%s-%s", option.value.name, data.coder_parameter.three.value)
123+
value=option.value.name
124+
}
125+
}
126+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp