@@ -66,21 +66,24 @@ func TestRun(t *testing.T) {
66
66
require .NoError (t ,err )
67
67
68
68
client := coderdtest .New (t ,& coderdtest.Options {
69
- Database :db ,
70
- Pubsub :ps ,
71
- NotificationsEnqueuer :enqueuer ,
69
+ Database :db ,
70
+ Pubsub :ps ,
71
+ NotificationsEnqueuer :enqueuer ,
72
72
})
73
73
firstUser := coderdtest .CreateFirstUser (t ,client )
74
74
75
75
const numOwners = 2
76
- barrier := new (sync.WaitGroup )
77
- barrier .Add (numOwners + 1 )
76
+ const numRegularUsers = 2
77
+ ownerBarrier := new (sync.WaitGroup )
78
+ regularBarrier := new (sync.WaitGroup )
79
+ ownerBarrier .Add (numOwners )
80
+ regularBarrier .Add (numRegularUsers )
78
81
metrics := notifications .NewMetrics (prometheus .NewRegistry ())
79
82
80
83
eg ,runCtx := errgroup .WithContext (ctx )
81
84
82
85
// Start owner runners who will receive notifications
83
- runners := make ([]* notifications.Runner ,0 ,numOwners )
86
+ ownerRunners := make ([]* notifications.Runner ,0 ,numOwners )
84
87
for i := range numOwners {
85
88
runnerCfg := notifications.Config {
86
89
User : createusers.Config {
@@ -90,22 +93,47 @@ func TestRun(t *testing.T) {
90
93
NotificationTimeout :testutil .WaitLong ,
91
94
DialTimeout :testutil .WaitLong ,
92
95
Metrics :metrics ,
93
- DialBarrier :barrier ,
96
+ DialBarrier :ownerBarrier ,
94
97
}
95
98
err := runnerCfg .Validate ()
96
99
require .NoError (t ,err )
97
100
98
101
runner := notifications .NewRunner (client ,runnerCfg )
99
- runners = append (runners ,runner )
102
+ ownerRunners = append (ownerRunners ,runner )
100
103
eg .Go (func ()error {
101
104
return runner .Run (runCtx ,"owner-" + strconv .Itoa (i ),io .Discard )
102
105
})
103
106
}
104
107
108
+ // Start regular user runners who will maintain websocket connections
109
+ regularRunners := make ([]* notifications.Runner ,0 ,numRegularUsers )
110
+ for i := range numRegularUsers {
111
+ runnerCfg := notifications.Config {
112
+ User : createusers.Config {
113
+ OrganizationID :firstUser .OrganizationID ,
114
+ },
115
+ IsOwner :false ,
116
+ NotificationTimeout :testutil .WaitLong ,
117
+ DialTimeout :testutil .WaitLong ,
118
+ Metrics :metrics ,
119
+ DialBarrier :regularBarrier ,
120
+ OwnerDialBarrier :ownerBarrier ,
121
+ }
122
+ err := runnerCfg .Validate ()
123
+ require .NoError (t ,err )
124
+
125
+ runner := notifications .NewRunner (client ,runnerCfg )
126
+ regularRunners = append (regularRunners ,runner )
127
+ eg .Go (func ()error {
128
+ return runner .Run (runCtx ,"regular-" + strconv .Itoa (i ),io .Discard )
129
+ })
130
+ }
131
+
105
132
// Trigger notifications by creating and deleting a user
106
133
eg .Go (func ()error {
107
- barrier .Done ()
108
- barrier .Wait ()
134
+ // Wait for all runners to connect
135
+ ownerBarrier .Wait ()
136
+ regularBarrier .Wait ()
109
137
110
138
newUser ,err := client .CreateUserWithOrgs (runCtx , codersdk.CreateUserRequestWithOrgs {
111
139
OrganizationIDs : []uuid.UUID {firstUser .OrganizationID },
@@ -128,20 +156,37 @@ func TestRun(t *testing.T) {
128
156
require .NoError (t ,err ,"runner execution should complete successfully" )
129
157
130
158
cleanupEg ,cleanupCtx := errgroup .WithContext (ctx )
131
- for i ,runner := range runners {
159
+ for i ,runner := range ownerRunners {
160
+ cleanupEg .Go (func ()error {
161
+ return runner .Cleanup (cleanupCtx ,"owner-" + strconv .Itoa (i ),io .Discard )
162
+ })
163
+ }
164
+ for i ,runner := range regularRunners {
132
165
cleanupEg .Go (func ()error {
133
- return runner .Cleanup (cleanupCtx ,strconv .Itoa (i ),io .Discard )
166
+ return runner .Cleanup (cleanupCtx ,"regular-" + strconv .Itoa (i ),io .Discard )
134
167
})
135
168
}
136
169
err = cleanupEg .Wait ()
137
170
require .NoError (t ,err )
138
171
139
- // Verify that each runner received both notifications and recorded metrics
140
- for _ ,runner := range runners {
172
+ users ,err := client .Users (ctx , codersdk.UsersRequest {})
173
+ require .NoError (t ,err )
174
+ require .Len (t ,users .Users ,1 )
175
+ require .Equal (t ,firstUser .UserID ,users .Users [0 ].ID )
176
+
177
+ // Verify that owner runners received both notifications and recorded metrics
178
+ for _ ,runner := range ownerRunners {
141
179
runnerMetrics := runner .GetMetrics ()
142
180
require .Contains (t ,runnerMetrics ,notifications .UserCreatedNotificationLatencyMetric )
143
181
require .Contains (t ,runnerMetrics ,notifications .UserDeletedNotificationLatencyMetric )
144
182
}
183
+
184
+ // Verify that regular runners don't have notification metrics
185
+ for _ ,runner := range regularRunners {
186
+ runnerMetrics := runner .GetMetrics ()
187
+ require .NotContains (t ,runnerMetrics ,notifications .UserCreatedNotificationLatencyMetric )
188
+ require .NotContains (t ,runnerMetrics ,notifications .UserDeletedNotificationLatencyMetric )
189
+ }
145
190
}
146
191
147
192
func defaultNotificationsConfig (method database.NotificationMethod ) codersdk.NotificationsConfig {