@@ -4,16 +4,14 @@ import (
4
4
"context"
5
5
"testing"
6
6
7
- "github.com/coder/serpent "
7
+ "github.com/google/uuid "
8
8
"github.com/stretchr/testify/require"
9
9
10
- "github.com/coder/coder/v2/coderd/coderdtest"
10
+ "github.com/coder/serpent"
11
+
11
12
"github.com/coder/coder/v2/coderd/database/dbmem"
12
13
"github.com/coder/coder/v2/coderd/runtimeconfig"
13
14
"github.com/coder/coder/v2/coderd/util/ptr"
14
- "github.com/coder/coder/v2/codersdk"
15
- "github.com/coder/coder/v2/enterprise/coderd/coderdenttest"
16
- "github.com/coder/coder/v2/enterprise/coderd/license"
17
15
"github.com/coder/coder/v2/testutil"
18
16
)
19
17
@@ -38,12 +36,8 @@ func TestUsage(t *testing.T) {
38
36
t .Run ("deployment value with runtimeconfig" , func (t * testing.T ) {
39
37
t .Parallel ()
40
38
41
- _ , altOrg := setup (t )
42
-
43
39
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 ))
40
+ mgr := runtimeconfig .NewStoreManager (dbmem .New ())
47
41
48
42
// NOTE: this field is now wrapped
49
43
var field runtimeconfig.Entry [* serpent.HostPort ]
@@ -63,32 +57,30 @@ func TestUsage(t *testing.T) {
63
57
64
58
// One new constraint is that we have to set the name on the runtimeconfig.Entry.
65
59
// Attempting to perform any operation which accesses the store will enforce the need for a name.
66
- _ , err := field .Resolve (ctx , resolver )
60
+ _ , err := field .Resolve (ctx , mgr )
67
61
require .ErrorIs (t , err , runtimeconfig .ErrNameNotSet )
68
62
69
63
// Let's set that name; the environment var name is likely to be the most stable.
70
64
field .Initialize (opt .Env )
71
65
72
66
newVal := serpent.HostPort {Host : "12.34.56.78" , Port : "1234" }
73
67
// 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 ))
68
+ require .NoError (t , field .SetRuntimeValue (ctx , mgr , & newVal ))
75
69
76
70
// ...and we can retrieve the value, as well.
77
- resolved , err := field .Resolve (ctx , resolver )
71
+ resolved , err := field .Resolve (ctx , mgr )
78
72
require .NoError (t , err )
79
73
require .Equal (t , newVal .String (), resolved .String ())
80
74
81
75
// We can also remove the runtime config.
82
- require .NoError (t , field .UnsetRuntimeValue (ctx , mutator ))
76
+ require .NoError (t , field .UnsetRuntimeValue (ctx , mgr ))
83
77
})
84
78
}
85
79
86
80
// TestConfig demonstrates creating org-level overrides for deployment-level settings.
87
81
func TestConfig (t * testing.T ) {
88
82
t .Parallel ()
89
83
90
- _ , altOrg := setup (t )
91
-
92
84
t .Run ("new" , func (t * testing.T ) {
93
85
t .Parallel ()
94
86
@@ -105,6 +97,8 @@ func TestConfig(t *testing.T) {
105
97
t .Run ("zero" , func (t * testing.T ) {
106
98
t .Parallel ()
107
99
100
+ mgr := runtimeconfig .NewNoopManager ()
101
+
108
102
// A zero-value declaration of a runtimeconfig.Entry should behave as a zero value of the generic type.
109
103
// NB! A name has not been set for this entry; it is "uninitialized".
110
104
var field runtimeconfig.Entry [* serpent.Bool ]
@@ -115,20 +109,18 @@ func TestConfig(t *testing.T) {
115
109
require .NoError (t , field .SetStartupValue ("true" ))
116
110
117
111
// But attempting to resolve will produce an error.
118
- _ , err := field .Resolve (context .Background (), runtimeconfig . NewNoopResolver () )
112
+ _ , err := field .Resolve (context .Background (), mgr )
119
113
require .ErrorIs (t , err , runtimeconfig .ErrNameNotSet )
120
114
// But attempting to set the runtime value will produce an error.
121
115
val := serpent .BoolOf (ptr .Ref (true ))
122
- require .ErrorIs (t , field .SetRuntimeValue (context .Background (), runtimeconfig . NewNoopMutator () , val ), runtimeconfig .ErrNameNotSet )
116
+ require .ErrorIs (t , field .SetRuntimeValue (context .Background (), mgr , val ), runtimeconfig .ErrNameNotSet )
123
117
})
124
118
125
119
t .Run ("simple" , func (t * testing.T ) {
126
120
t .Parallel ()
127
121
128
122
ctx := testutil .Context (t , testutil .WaitShort )
129
- store := dbmem .New ()
130
- resolver := runtimeconfig .NewOrgResolver (altOrg .ID , runtimeconfig .NewStoreResolver (store ))
131
- mutator := runtimeconfig .NewOrgMutator (altOrg .ID , runtimeconfig .NewStoreMutator (store ))
123
+ mgr := runtimeconfig .NewStoreManager (dbmem .New ())
132
124
133
125
var (
134
126
base = serpent .String ("system@dev.coder.com" )
@@ -141,16 +133,16 @@ func TestConfig(t *testing.T) {
141
133
// Validate that it returns that value.
142
134
require .Equal (t , base .String (), field .String ())
143
135
// Validate that there is no org-level override right now.
144
- _ , err := field .Resolve (ctx , resolver )
136
+ _ , err := field .Resolve (ctx , mgr )
145
137
require .ErrorIs (t , err , runtimeconfig .EntryNotFound )
146
138
// Coalesce returns the deployment-wide value.
147
- val , err := field .Coalesce (ctx , resolver )
139
+ val , err := field .Coalesce (ctx , mgr )
148
140
require .NoError (t , err )
149
141
require .Equal (t , base .String (), val .String ())
150
142
// Set an org-level override.
151
- require .NoError (t , field .SetRuntimeValue (ctx , mutator , & override ))
143
+ require .NoError (t , field .SetRuntimeValue (ctx , mgr , & override ))
152
144
// Coalesce now returns the org-level value.
153
- val , err = field .Coalesce (ctx , resolver )
145
+ val , err = field .Coalesce (ctx , mgr )
154
146
require .NoError (t , err )
155
147
require .Equal (t , override .String (), val .String ())
156
148
})
@@ -159,9 +151,7 @@ func TestConfig(t *testing.T) {
159
151
t .Parallel ()
160
152
161
153
ctx := testutil .Context (t , testutil .WaitShort )
162
- store := dbmem .New ()
163
- resolver := runtimeconfig .NewOrgResolver (altOrg .ID , runtimeconfig .NewStoreResolver (store ))
164
- mutator := runtimeconfig .NewOrgMutator (altOrg .ID , runtimeconfig .NewStoreMutator (store ))
154
+ mgr := runtimeconfig .NewStoreManager (dbmem .New ())
165
155
166
156
var (
167
157
base = serpent.Struct [map [string ]string ]{
@@ -180,34 +170,65 @@ func TestConfig(t *testing.T) {
180
170
// Check that default has been set.
181
171
require .Equal (t , base .String (), field .StartupValue ().String ())
182
172
// Validate that there is no org-level override right now.
183
- _ , err := field .Resolve (ctx , resolver )
173
+ _ , err := field .Resolve (ctx , mgr )
184
174
require .ErrorIs (t , err , runtimeconfig .EntryNotFound )
185
175
// Coalesce returns the deployment-wide value.
186
- val , err := field .Coalesce (ctx , resolver )
176
+ val , err := field .Coalesce (ctx , mgr )
187
177
require .NoError (t , err )
188
178
require .Equal (t , base .Value , val .Value )
189
179
// Set an org-level override.
190
- require .NoError (t , field .SetRuntimeValue (ctx , mutator , & override ))
180
+ require .NoError (t , field .SetRuntimeValue (ctx , mgr , & override ))
191
181
// Coalesce now returns the org-level value.
192
- structVal , err := field .Resolve (ctx , resolver )
182
+ structVal , err := field .Resolve (ctx , mgr )
193
183
require .NoError (t , err )
194
184
require .Equal (t , override .Value , structVal .Value )
195
185
})
196
186
}
197
187
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 {})
188
+ func TestScoped (t * testing.T ) {
189
+ orgId := uuid .New ()
190
+
191
+ ctx := testutil .Context (t , testutil .WaitShort )
192
+
193
+ // Set up a config manager and a field which will have runtime configs.
194
+ mgr := runtimeconfig .NewStoreManager (dbmem .New ())
195
+ field := runtimeconfig .MustNew [* serpent.HostPort ]("addr" , "localhost:3000" )
196
+
197
+ // No runtime value set at this point, Coalesce will return startup value.
198
+ _ , err := field .Resolve (ctx , mgr )
199
+ require .ErrorIs (t , err , runtimeconfig .EntryNotFound )
200
+ val , err := field .Coalesce (ctx , mgr )
201
+ require .NoError (t , err )
202
+ require .Equal (t , field .StartupValue ().String (), val .String ())
203
+
204
+ // Set a runtime value which is NOT org-scoped.
205
+ host , port := "localhost" , "1234"
206
+ require .NoError (t , field .SetRuntimeValue (ctx , mgr , & serpent.HostPort {Host : host , Port : port }))
207
+ val , err = field .Resolve (ctx , mgr )
208
+ require .NoError (t , err )
209
+ require .Equal (t , host , val .Host )
210
+ require .Equal (t , port , val .Port )
211
+
212
+ orgMgr := mgr .Scoped (orgId .String ())
213
+ // Using the org scope, nothing will be returned.
214
+ _ , err = field .Resolve (ctx , orgMgr )
215
+ require .ErrorIs (t , err , runtimeconfig .EntryNotFound )
216
+
217
+ // Now set an org-scoped value.
218
+ host , port = "localhost" , "4321"
219
+ require .NoError (t , field .SetRuntimeValue (ctx , orgMgr , & serpent.HostPort {Host : host , Port : port }))
220
+ val , err = field .Resolve (ctx , orgMgr )
221
+ require .NoError (t , err )
222
+ require .Equal (t , host , val .Host )
223
+ require .Equal (t , port , val .Port )
224
+
225
+ // Ensure the two runtime configs are NOT equal to each other nor the startup value.
226
+ global , err := field .Resolve (ctx , mgr )
227
+ require .NoError (t , err )
228
+ org , err := field .Resolve (ctx , orgMgr )
229
+ require .NoError (t , err )
230
+
231
+ require .NotEqual (t , global .String (), org .String ())
232
+ require .NotEqual (t , field .StartupValue ().String (), global .String ())
233
+ require .NotEqual (t , field .StartupValue ().String (), org .String ())
213
234
}
0 commit comments