@@ -38,6 +38,7 @@ import (
38
38
"github.com/coder/coder/v2/tailnet"
39
39
"github.com/coder/coder/v2/tailnet/tailnettest"
40
40
"github.com/coder/coder/v2/testutil"
41
+ "github.com/coder/quartz"
41
42
)
42
43
43
44
func TestActiveUsers (t * testing.T ) {
@@ -98,7 +99,7 @@ func TestActiveUsers(t *testing.T) {
98
99
t .Run (tc .Name ,func (t * testing.T ) {
99
100
t .Parallel ()
100
101
registry := prometheus .NewRegistry ()
101
- closeFunc ,err := prometheusmetrics .ActiveUsers (context .Background (),registry ,tc .Database (t ),time .Millisecond )
102
+ closeFunc ,err := prometheusmetrics .ActiveUsers (context .Background (),slogtest . Make ( t , nil ), registry ,tc .Database (t ),time .Millisecond )
102
103
require .NoError (t ,err )
103
104
t .Cleanup (closeFunc )
104
105
@@ -112,6 +113,100 @@ func TestActiveUsers(t *testing.T) {
112
113
}
113
114
}
114
115
116
+ func TestUsers (t * testing.T ) {
117
+ t .Parallel ()
118
+
119
+ for _ ,tc := range []struct {
120
+ Name string
121
+ Database func (t * testing.T ) database.Store
122
+ Count map [database.UserStatus ]int
123
+ }{{
124
+ Name :"None" ,
125
+ Database :func (t * testing.T ) database.Store {
126
+ return dbmem .New ()
127
+ },
128
+ Count :map [database.UserStatus ]int {},
129
+ }, {
130
+ Name :"One" ,
131
+ Database :func (t * testing.T ) database.Store {
132
+ db := dbmem .New ()
133
+ dbgen .User (t ,db , database.User {Status :database .UserStatusActive })
134
+ return db
135
+ },
136
+ Count :map [database.UserStatus ]int {database .UserStatusActive :1 },
137
+ }, {
138
+ Name :"MultipleStatuses" ,
139
+ Database :func (t * testing.T ) database.Store {
140
+ db := dbmem .New ()
141
+
142
+ dbgen .User (t ,db , database.User {Status :database .UserStatusActive })
143
+ dbgen .User (t ,db , database.User {Status :database .UserStatusDormant })
144
+
145
+ return db
146
+ },
147
+ Count :map [database.UserStatus ]int {database .UserStatusActive :1 ,database .UserStatusDormant :1 },
148
+ }, {
149
+ Name :"MultipleActive" ,
150
+ Database :func (t * testing.T ) database.Store {
151
+ db := dbmem .New ()
152
+ dbgen .User (t ,db , database.User {Status :database .UserStatusActive })
153
+ dbgen .User (t ,db , database.User {Status :database .UserStatusActive })
154
+ dbgen .User (t ,db , database.User {Status :database .UserStatusActive })
155
+ return db
156
+ },
157
+ Count :map [database.UserStatus ]int {database .UserStatusActive :3 },
158
+ }} {
159
+ tc := tc
160
+ t .Run (tc .Name ,func (t * testing.T ) {
161
+ t .Parallel ()
162
+ ctx ,cancel := context .WithTimeout (context .Background (),testutil .WaitShort )
163
+ defer cancel ()
164
+
165
+ registry := prometheus .NewRegistry ()
166
+ mClock := quartz .NewMock (t )
167
+ db := tc .Database (t )
168
+ closeFunc ,err := prometheusmetrics .Users (context .Background (),slogtest .Make (t ,nil ),mClock ,registry ,db ,time .Millisecond )
169
+ require .NoError (t ,err )
170
+ t .Cleanup (closeFunc )
171
+
172
+ _ ,w := mClock .AdvanceNext ()
173
+ w .MustWait (ctx )
174
+
175
+ checkFn := func ()bool {
176
+ metrics ,err := registry .Gather ()
177
+ if err != nil {
178
+ return false
179
+ }
180
+
181
+ // If we get no metrics and we know none should exist, bail
182
+ // early. If we get no metrics but we expect some, retry.
183
+ if len (metrics )== 0 {
184
+ return len (tc .Count )== 0
185
+ }
186
+
187
+ for _ ,metric := range metrics [0 ].Metric {
188
+ if tc .Count [database .UserStatus (* metric .Label [0 ].Value )]!= int (metric .Gauge .GetValue ()) {
189
+ return false
190
+ }
191
+ }
192
+
193
+ return true
194
+ }
195
+
196
+ require .Eventually (t ,checkFn ,testutil .WaitShort ,testutil .IntervalFast )
197
+
198
+ // Add another dormant user and ensure it updates
199
+ dbgen .User (t ,db , database.User {Status :database .UserStatusDormant })
200
+ tc .Count [database .UserStatusDormant ]++
201
+
202
+ _ ,w = mClock .AdvanceNext ()
203
+ w .MustWait (ctx )
204
+
205
+ require .Eventually (t ,checkFn ,testutil .WaitShort ,testutil .IntervalFast )
206
+ })
207
+ }
208
+ }
209
+
115
210
func TestWorkspaceLatestBuildTotals (t * testing.T ) {
116
211
t .Parallel ()
117
212