@@ -118,6 +118,102 @@ func TestDeploymentInsights(t *testing.T) {
118
118
require .NoError (t , err )
119
119
}
120
120
121
+ func TestUserActivityInsights (t * testing.T ) {
122
+ t .Parallel ()
123
+
124
+ logger := slogtest .Make (t , nil )
125
+ client := coderdtest .New (t , & coderdtest.Options {
126
+ IncludeProvisionerDaemon : true ,
127
+ AgentStatsRefreshInterval : time .Millisecond * 100 ,
128
+ })
129
+
130
+ // Create two users, one that will appear in the report and another that
131
+ // won't (due to not having/using a workspace).
132
+ user := coderdtest .CreateFirstUser (t , client )
133
+ _ , _ = coderdtest .CreateAnotherUser (t , client , user .OrganizationID )
134
+ authToken := uuid .NewString ()
135
+ version := coderdtest .CreateTemplateVersion (t , client , user .OrganizationID , & echo.Responses {
136
+ Parse : echo .ParseComplete ,
137
+ ProvisionPlan : echo .PlanComplete ,
138
+ ProvisionApply : echo .ProvisionApplyWithAgent (authToken ),
139
+ })
140
+ template := coderdtest .CreateTemplate (t , client , user .OrganizationID , version .ID )
141
+ require .Empty (t , template .BuildTimeStats [codersdk .WorkspaceTransitionStart ])
142
+
143
+ coderdtest .AwaitTemplateVersionJob (t , client , version .ID )
144
+ workspace := coderdtest .CreateWorkspace (t , client , user .OrganizationID , template .ID )
145
+ coderdtest .AwaitWorkspaceBuildJob (t , client , workspace .LatestBuild .ID )
146
+
147
+ // Start an agent so that we can generate stats.
148
+ agentClient := agentsdk .New (client .URL )
149
+ agentClient .SetSessionToken (authToken )
150
+ agentCloser := agent .New (agent.Options {
151
+ Logger : logger .Named ("agent" ),
152
+ Client : agentClient ,
153
+ })
154
+ defer func () {
155
+ _ = agentCloser .Close ()
156
+ }()
157
+ resources := coderdtest .AwaitWorkspaceAgents (t , client , workspace .ID )
158
+
159
+ // Start must be at the beginning of the day, initialize it early in case
160
+ // the day changes so that we get the relevant stats faster.
161
+ y , m , d := time .Now ().UTC ().Date ()
162
+ today := time .Date (y , m , d , 0 , 0 , 0 , 0 , time .UTC )
163
+
164
+ ctx , cancel := context .WithTimeout (context .Background (), testutil .WaitLong )
165
+ defer cancel ()
166
+
167
+ // Connect to the agent to generate usage/latency stats.
168
+ conn , err := client .DialWorkspaceAgent (ctx , resources [0 ].Agents [0 ].ID , & codersdk.DialWorkspaceAgentOptions {
169
+ Logger : logger .Named ("client" ),
170
+ })
171
+ require .NoError (t , err )
172
+ defer conn .Close ()
173
+
174
+ sshConn , err := conn .SSHClient (ctx )
175
+ require .NoError (t , err )
176
+ defer sshConn .Close ()
177
+
178
+ sess , err := sshConn .NewSession ()
179
+ require .NoError (t , err )
180
+ defer sess .Close ()
181
+
182
+ r , w := io .Pipe ()
183
+ defer r .Close ()
184
+ defer w .Close ()
185
+ sess .Stdin = r
186
+ sess .Stdout = io .Discard
187
+ err = sess .Start ("cat" )
188
+ require .NoError (t , err )
189
+
190
+ var userActivities codersdk.UserActivityInsightsResponse
191
+ require .Eventuallyf (t , func () bool {
192
+ // Keep connection active.
193
+ _ , err := w .Write ([]byte ("hello world\n " ))
194
+ if ! assert .NoError (t , err ) {
195
+ return false
196
+ }
197
+ userActivities , err = client .UserActivityInsights (ctx , codersdk.UserActivityInsightsRequest {
198
+ StartTime : today ,
199
+ EndTime : time .Now ().UTC ().Truncate (time .Hour ).Add (time .Hour ), // Round up to include the current hour.
200
+ TemplateIDs : []uuid.UUID {template .ID },
201
+ })
202
+ if ! assert .NoError (t , err ) {
203
+ return false
204
+ }
205
+ return len (userActivities .Report .Users ) > 0 && userActivities .Report .Users [0 ].Seconds > 0
206
+ }, testutil .WaitMedium , testutil .IntervalFast , "user activity is missing" )
207
+
208
+ // We got our latency data, close the connection.
209
+ _ = sess .Close ()
210
+ _ = sshConn .Close ()
211
+
212
+ require .Len (t , userActivities .Report .Users , 1 , "want only 1 user" )
213
+ require .Equal (t , userActivities .Report .Users [0 ].UserID , user .UserID , "want user id to match" )
214
+ assert .Greater (t , userActivities .Report .Users [0 ].Seconds , int64 (0 ), "want usage in seconds to be greater than 0" )
215
+ }
216
+
121
217
func TestUserLatencyInsights (t * testing.T ) {
122
218
t .Parallel ()
123
219
0 commit comments