Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9b5d499

Browse files
authored
chore: refactor dynamic parameters into dedicated package (#18420)
This PR extracts dynamic parameter rendering logic from coderd/parameters.go into a new coderd/dynamicparameters package. Partly for organization and maintainability, but primarily to be reused in `wsbuilder` to be leveraged as validation.
1 parent 72f7d70 commit 9b5d499

File tree

10 files changed

+941
-409
lines changed

10 files changed

+941
-409
lines changed
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package coderdtest
2+
3+
import (
4+
"encoding/json"
5+
"testing"
6+
7+
"github.com/google/uuid"
8+
"github.com/stretchr/testify/assert"
9+
"github.com/stretchr/testify/require"
10+
11+
"github.com/coder/coder/v2/coderd/util/ptr"
12+
"github.com/coder/coder/v2/coderd/util/slice"
13+
"github.com/coder/coder/v2/codersdk"
14+
"github.com/coder/coder/v2/provisioner/echo"
15+
"github.com/coder/coder/v2/provisionersdk/proto"
16+
)
17+
18+
type DynamicParameterTemplateParams struct {
19+
MainTF string
20+
Plan json.RawMessage
21+
ModulesArchive []byte
22+
23+
// StaticParams is used if the provisioner daemon version does not support dynamic parameters.
24+
StaticParams []*proto.RichParameter
25+
}
26+
27+
func DynamicParameterTemplate(t *testing.T, client *codersdk.Client, org uuid.UUID, args DynamicParameterTemplateParams) (codersdk.Template, codersdk.TemplateVersion) {
28+
t.Helper()
29+
30+
files := echo.WithExtraFiles(map[string][]byte{
31+
"main.tf": []byte(args.MainTF),
32+
})
33+
files.ProvisionPlan = []*proto.Response{{
34+
Type: &proto.Response_Plan{
35+
Plan: &proto.PlanComplete{
36+
Plan: args.Plan,
37+
ModuleFiles: args.ModulesArchive,
38+
Parameters: args.StaticParams,
39+
},
40+
},
41+
}}
42+
43+
version := CreateTemplateVersion(t, client, org, files)
44+
AwaitTemplateVersionJobCompleted(t, client, version.ID)
45+
tpl := CreateTemplate(t, client, org, version.ID)
46+
47+
var err error
48+
tpl, err = client.UpdateTemplateMeta(t.Context(), tpl.ID, codersdk.UpdateTemplateMeta{
49+
UseClassicParameterFlow: ptr.Ref(false),
50+
})
51+
require.NoError(t, err)
52+
53+
return tpl, version
54+
}
55+
56+
type ParameterAsserter struct {
57+
Name string
58+
Params []codersdk.PreviewParameter
59+
t *testing.T
60+
}
61+
62+
func AssertParameter(t *testing.T, name string, params []codersdk.PreviewParameter) *ParameterAsserter {
63+
return &ParameterAsserter{
64+
Name: name,
65+
Params: params,
66+
t: t,
67+
}
68+
}
69+
70+
func (a *ParameterAsserter) find(name string) *codersdk.PreviewParameter {
71+
a.t.Helper()
72+
for _, p := range a.Params {
73+
if p.Name == name {
74+
return &p
75+
}
76+
}
77+
78+
assert.Fail(a.t, "parameter not found", "expected parameter %q to exist", a.Name)
79+
return nil
80+
}
81+
82+
func (a *ParameterAsserter) NotExists() *ParameterAsserter {
83+
a.t.Helper()
84+
85+
names := slice.Convert(a.Params, func(p codersdk.PreviewParameter) string {
86+
return p.Name
87+
})
88+
89+
assert.NotContains(a.t, names, a.Name)
90+
return a
91+
}
92+
93+
func (a *ParameterAsserter) Exists() *ParameterAsserter {
94+
a.t.Helper()
95+
96+
names := slice.Convert(a.Params, func(p codersdk.PreviewParameter) string {
97+
return p.Name
98+
})
99+
100+
assert.Contains(a.t, names, a.Name)
101+
return a
102+
}
103+
104+
func (a *ParameterAsserter) Value(expected string) *ParameterAsserter {
105+
a.t.Helper()
106+
107+
p := a.find(a.Name)
108+
if p == nil {
109+
return a
110+
}
111+
112+
assert.Equal(a.t, expected, p.Value.Value)
113+
return a
114+
}
115+
116+
func (a *ParameterAsserter) Options(expected ...string) *ParameterAsserter {
117+
a.t.Helper()
118+
119+
p := a.find(a.Name)
120+
if p == nil {
121+
return a
122+
}
123+
124+
optValues := slice.Convert(p.Options, func(p codersdk.PreviewParameterOption) string {
125+
return p.Value.Value
126+
})
127+
assert.ElementsMatch(a.t, expected, optValues, "parameter %q options", a.Name)
128+
return a
129+
}

coderd/coderdtest/stream.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package coderdtest
2+
3+
import "github.com/coder/coder/v2/codersdk/wsjson"
4+
5+
// SynchronousStream returns a function that assumes the stream is synchronous.
6+
// Meaning each request sent assumes exactly one response will be received.
7+
// The function will block until the response is received or an error occurs.
8+
//
9+
// This should not be used in production code, as it does not handle edge cases.
10+
// The second function `pop` can be used to retrieve the next response from the
11+
// stream without sending a new request. This is useful for dynamic parameters
12+
func SynchronousStream[R any, W any](stream *wsjson.Stream[R, W]) (do func(W) (R, error), pop func() R) {
13+
rec := stream.Chan()
14+
15+
return func(req W) (R, error) {
16+
err := stream.Send(req)
17+
if err != nil {
18+
return *new(R), err
19+
}
20+
21+
return <-rec, nil
22+
}, func() R {
23+
return <-rec
24+
}
25+
}

0 commit comments

Comments
 (0)