Skip to content

Commit b2b43c8

Browse files
dannykoppingEmyrk
authored andcommitted
Document usage in test
Signed-off-by: Danny Kopping <danny@coder.com>
1 parent f97ca89 commit b2b43c8

File tree

5 files changed

+129
-27
lines changed

5 files changed

+129
-27
lines changed

coderd/runtimeconfig/config.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ func (e *Entry[T]) SetKey(k string) {
5656
e.k = k
5757
}
5858

59+
func (e *Entry[T]) Set(s string) error {
60+
return e.SetStartupValue(s)
61+
}
62+
5963
func (e *Entry[T]) SetStartupValue(s string) error {
6064
return e.val().Set(s)
6165
}
@@ -75,6 +79,9 @@ func (e *Entry[T]) String() string {
7579
return e.val().String()
7680
}
7781

82+
// StartupValue returns the wrapped type T which represents the state as of the definition of this Entry.
83+
// This function would've been named Value, but this conflicts with a field named Value on some implementations of T in
84+
// the serpent library; plus it's just more clear.
7885
func (e *Entry[T]) StartupValue() T {
7986
return e.val()
8087
}
@@ -85,7 +92,16 @@ func (e *Entry[T]) SetRuntimeValue(ctx context.Context, m Mutator, val T) error
8592
return err
8693
}
8794

88-
return m.MutateByKey(ctx, key, val.String())
95+
return m.UpsertRuntimeSetting(ctx, key, val.String())
96+
}
97+
98+
func (e *Entry[T]) UnsetRuntimeValue(ctx context.Context, m Mutator) error {
99+
key, err := e.key()
100+
if err != nil {
101+
return err
102+
}
103+
104+
return m.DeleteRuntimeSetting(ctx, key)
89105
}
90106

91107
func (e *Entry[T]) Resolve(ctx context.Context, r Resolver) (T, error) {
@@ -96,7 +112,7 @@ func (e *Entry[T]) Resolve(ctx context.Context, r Resolver) (T, error) {
96112
return zero, err
97113
}
98114

99-
val, err := r.ResolveByKey(ctx, key)
115+
val, err := r.GetRuntimeSetting(ctx, key)
100116
if err != nil {
101117
return zero, err
102118
}

coderd/runtimeconfig/config_test.go

Lines changed: 85 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,77 @@ import (
1717
"github.com/coder/coder/v2/testutil"
1818
)
1919

20+
func TestUsage(t *testing.T) {
21+
t.Run("deployment value without runtimeconfig", func(t *testing.T) {
22+
t.Parallel()
23+
24+
var field serpent.StringArray
25+
opt := serpent.Option{
26+
Name: "my deployment value",
27+
Description: "this mimicks an option we'd define in codersdk/deployment.go",
28+
Env: "MY_DEPLOYMENT_VALUE",
29+
Default: "pestle,mortar",
30+
Value: &field,
31+
}
32+
33+
set := serpent.OptionSet{opt}
34+
require.NoError(t, set.SetDefaults())
35+
require.Equal(t, []string{"pestle", "mortar"}, field.Value())
36+
})
37+
38+
t.Run("deployment value with runtimeconfig", func(t *testing.T) {
39+
t.Parallel()
40+
41+
_, altOrg := setup(t)
42+
43+
ctx := testutil.Context(t, testutil.WaitShort)
44+
store := dbmem.New()
45+
resolver := runtimeconfig.NewOrgResolver(altOrg.ID, runtimeconfig.NewStoreResolver(store))
46+
mutator := runtimeconfig.NewOrgMutator(altOrg.ID, runtimeconfig.NewStoreMutator(store))
47+
48+
// NOTE: this field is now wrapped
49+
var field runtimeconfig.Entry[*serpent.HostPort]
50+
opt := serpent.Option{
51+
Name: "my deployment value",
52+
Description: "this mimicks an option we'd define in codersdk/deployment.go",
53+
Env: "MY_DEPLOYMENT_VALUE",
54+
Default: "localhost:1234",
55+
Value: &field,
56+
}
57+
58+
set := serpent.OptionSet{opt}
59+
require.NoError(t, set.SetDefaults())
60+
61+
// The value has to now be retrieved from a StartupValue() call.
62+
require.Equal(t, "localhost:1234", field.StartupValue().String())
63+
64+
// One new constraint is that we have to set the key on the runtimeconfig.Entry.
65+
// Attempting to perform any operation which accesses the store will enforce the need for a key.
66+
_, err := field.Resolve(ctx, resolver)
67+
require.ErrorIs(t, err, runtimeconfig.ErrKeyNotSet)
68+
69+
// Let's see that key. The environment var name is likely to be the most stable.
70+
field.SetKey(opt.Env)
71+
72+
newVal := serpent.HostPort{Host: "12.34.56.78", Port: "1234"}
73+
// Now that we've set it, we can update the runtime value of this field, which modifies given store.
74+
require.NoError(t, field.SetRuntimeValue(ctx, mutator, &newVal))
75+
76+
// ...and we can retrieve the value, as well.
77+
resolved, err := field.Resolve(ctx, resolver)
78+
require.NoError(t, err)
79+
require.Equal(t, newVal.String(), resolved.String())
80+
81+
// We can also remove the runtime config.
82+
require.NoError(t, field.UnsetRuntimeValue(ctx, mutator))
83+
})
84+
}
85+
2086
// TestConfig demonstrates creating org-level overrides for deployment-level settings.
2187
func TestConfig(t *testing.T) {
2288
t.Parallel()
2389

24-
vals := coderdtest.DeploymentValues(t)
25-
vals.Experiments = []string{string(codersdk.ExperimentMultiOrganization)}
26-
adminClient, _, _, _ := coderdenttest.NewWithAPI(t, &coderdenttest.Options{
27-
Options: &coderdtest.Options{DeploymentValues: vals},
28-
LicenseOptions: &coderdenttest.LicenseOptions{
29-
Features: license.Features{
30-
codersdk.FeatureMultipleOrganizations: 1,
31-
},
32-
},
33-
})
34-
altOrg := coderdenttest.CreateOrganization(t, adminClient, coderdenttest.CreateOrganizationOptions{})
90+
_, altOrg := setup(t)
3591

3692
t.Run("new", func(t *testing.T) {
3793
t.Parallel()
@@ -119,7 +175,7 @@ func TestConfig(t *testing.T) {
119175
}
120176
)
121177

122-
field := runtimeconfig.MustNew[*serpent.Struct[map[string]string]]("my-field", base.String())
178+
field := runtimeconfig.MustNew[*serpent.Struct[map[string]string]]("my-field", base.String())
123179

124180
// Check that default has been set.
125181
require.Equal(t, base.String(), field.StartupValue().String())
@@ -138,3 +194,20 @@ func TestConfig(t *testing.T) {
138194
require.Equal(t, override.Value, structVal.Value)
139195
})
140196
}
197+
198+
// setup creates a new API, enabled notifications + multi-org experiments, and returns the API client and a new org.
199+
func setup(t *testing.T) (*codersdk.Client, codersdk.Organization) {
200+
t.Helper()
201+
202+
vals := coderdtest.DeploymentValues(t)
203+
vals.Experiments = []string{string(codersdk.ExperimentMultiOrganization)}
204+
adminClient, _, _, _ := coderdenttest.NewWithAPI(t, &coderdenttest.Options{
205+
Options: &coderdtest.Options{DeploymentValues: vals},
206+
LicenseOptions: &coderdenttest.LicenseOptions{
207+
Features: license.Features{
208+
codersdk.FeatureMultipleOrganizations: 1,
209+
},
210+
},
211+
})
212+
return adminClient, coderdenttest.CreateOrganization(t, adminClient, coderdenttest.CreateOrganizationOptions{})
213+
}

coderd/runtimeconfig/mutator.go

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,18 @@ func NewStoreMutator(store Store) *StoreMutator {
2020
return &StoreMutator{store}
2121
}
2222

23-
func (s *StoreMutator) MutateByKey(ctx context.Context, key, val string) error {
23+
func (s StoreMutator) UpsertRuntimeSetting(ctx context.Context, key, val string) error {
2424
err := s.store.UpsertRuntimeConfig(ctx, database.UpsertRuntimeConfigParams{Key: key, Value: val})
2525
if err != nil {
2626
return xerrors.Errorf("update %q: %w", err)
2727
}
2828
return nil
2929
}
3030

31+
func (s StoreMutator) DeleteRuntimeSetting(ctx context.Context, key string) error {
32+
return s.store.DeleteRuntimeConfig(ctx, key)
33+
}
34+
3135
type OrgMutator struct {
3236
inner Mutator
3337
orgID uuid.UUID
@@ -37,16 +41,24 @@ func NewOrgMutator(orgID uuid.UUID, inner Mutator) *OrgMutator {
3741
return &OrgMutator{inner: inner, orgID: orgID}
3842
}
3943

40-
func (m OrgMutator) MutateByKey(ctx context.Context, key, val string) error {
41-
return m.inner.MutateByKey(ctx, orgKey(m.orgID, key), val)
44+
func (m OrgMutator) UpsertRuntimeSetting(ctx context.Context, key, val string) error {
45+
return m.inner.UpsertRuntimeSetting(ctx, orgKey(m.orgID, key), val)
46+
}
47+
48+
func (m OrgMutator) DeleteRuntimeSetting(ctx context.Context, key string) error {
49+
return m.inner.DeleteRuntimeSetting(ctx, key)
4250
}
4351

4452
type NoopMutator struct{}
4553

46-
func (n *NoopMutator) MutateByKey(ctx context.Context, key, val string) error {
54+
func NewNoopMutator() *NoopMutator {
55+
return &NoopMutator{}
56+
}
57+
58+
func (n NoopMutator) UpsertRuntimeSetting(context.Context, string, string) error {
4759
return nil
4860
}
4961

50-
func NewNoopMutator() *NoopMutator {
51-
return &NoopMutator{}
62+
func (n NoopMutator) DeleteRuntimeSetting(context.Context, string) error {
63+
return nil
5264
}

coderd/runtimeconfig/resolver.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ func NewStoreResolver(store Store) *StoreResolver {
1717
return &StoreResolver{store}
1818
}
1919

20-
func (s StoreResolver) ResolveByKey(ctx context.Context, key string) (string, error) {
20+
func (s StoreResolver) GetRuntimeSetting(ctx context.Context, key string) (string, error) {
2121
if s.store == nil {
2222
panic("developer error: store must be set")
2323
}
@@ -46,8 +46,8 @@ func NewOrgResolver(orgID uuid.UUID, inner Resolver) *OrgResolver {
4646
return &OrgResolver{inner: inner, orgID: orgID}
4747
}
4848

49-
func (r OrgResolver) ResolveByKey(ctx context.Context, key string) (string, error) {
50-
return r.inner.ResolveByKey(ctx, orgKey(r.orgID, key))
49+
func (r OrgResolver) GetRuntimeSetting(ctx context.Context, key string) (string, error) {
50+
return r.inner.GetRuntimeSetting(ctx, orgKey(r.orgID, key))
5151
}
5252

5353
// NoopResolver will always fail to resolve the given key.
@@ -58,6 +58,6 @@ func NewNoopResolver() *NoopResolver {
5858
return &NoopResolver{}
5959
}
6060

61-
func (n NoopResolver) ResolveByKey(context.Context, string) (string, error) {
61+
func (n NoopResolver) GetRuntimeSetting(context.Context, string) (string, error) {
6262
return "", EntryNotFound
6363
}

coderd/runtimeconfig/spec.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ type Initializer interface {
77
}
88

99
type Resolver interface {
10-
ResolveByKey(ctx context.Context, key string) (string, error)
10+
GetRuntimeSetting(ctx context.Context, key string) (string, error)
1111
}
1212

1313
type Mutator interface {
14-
MutateByKey(ctx context.Context, key, val string) error
15-
}
14+
UpsertRuntimeSetting(ctx context.Context, key, val string) error
15+
DeleteRuntimeSetting(ctx context.Context, key string) error
16+
}

0 commit comments

Comments
 (0)