@@ -406,6 +406,104 @@ func TestUpdateStates(t *testing.T) {
406
406
407
407
require .True (t , updateAgentMetricsFnCalled )
408
408
})
409
+
410
+ t .Run ("WorkspaceUsageExperiment" , func (t * testing.T ) {
411
+ t .Parallel ()
412
+
413
+ var (
414
+ now = dbtime .Now ()
415
+ dbM = dbmock .NewMockStore (gomock .NewController (t ))
416
+ ps = pubsub .NewInMemory ()
417
+
418
+ templateScheduleStore = schedule.MockTemplateScheduleStore {
419
+ GetFn : func (context.Context , database.Store , uuid.UUID ) (schedule.TemplateScheduleOptions , error ) {
420
+ panic ("should not be called" )
421
+ },
422
+ SetFn : func (context.Context , database.Store , database.Template , schedule.TemplateScheduleOptions ) (database.Template , error ) {
423
+ panic ("not implemented" )
424
+ },
425
+ }
426
+ batcher = & statsBatcher {}
427
+
428
+ req = & agentproto.UpdateStatsRequest {
429
+ Stats : & agentproto.Stats {
430
+ ConnectionsByProto : map [string ]int64 {
431
+ "tcp" : 1 ,
432
+ "dean" : 2 ,
433
+ },
434
+ ConnectionCount : 3 ,
435
+ ConnectionMedianLatencyMs : 23 ,
436
+ RxPackets : 120 ,
437
+ RxBytes : 1000 ,
438
+ TxPackets : 130 ,
439
+ TxBytes : 2000 ,
440
+ SessionCountVscode : 1 ,
441
+ SessionCountJetbrains : 2 ,
442
+ SessionCountReconnectingPty : 3 ,
443
+ SessionCountSsh : 4 ,
444
+ Metrics : []* agentproto.Stats_Metric {
445
+ {
446
+ Name : "awesome metric" ,
447
+ Value : 42 ,
448
+ },
449
+ {
450
+ Name : "uncool metric" ,
451
+ Value : 0 ,
452
+ },
453
+ },
454
+ },
455
+ }
456
+ )
457
+ api := agentapi.StatsAPI {
458
+ AgentFn : func (context.Context ) (database.WorkspaceAgent , error ) {
459
+ return agent , nil
460
+ },
461
+ Database : dbM ,
462
+ StatsReporter : workspacestats .NewReporter (workspacestats.ReporterOptions {
463
+ Database : dbM ,
464
+ Pubsub : ps ,
465
+ StatsBatcher : batcher ,
466
+ TemplateScheduleStore : templateScheduleStorePtr (templateScheduleStore ),
467
+ }),
468
+ AgentStatsRefreshInterval : 10 * time .Second ,
469
+ TimeNowFn : func () time.Time {
470
+ return now
471
+ },
472
+ Experiments : []codersdk.Experiment {codersdk .ExperimentWorkspaceUsage },
473
+ }
474
+
475
+ // Workspace gets fetched.
476
+ dbM .EXPECT ().GetWorkspaceByAgentID (gomock .Any (), agent .ID ).Return (database.GetWorkspaceByAgentIDRow {
477
+ Workspace : workspace ,
478
+ TemplateName : template .Name ,
479
+ }, nil )
480
+
481
+ // We expect an activity bump because ConnectionCount > 0.
482
+ dbM .EXPECT ().ActivityBumpWorkspace (gomock .Any (), database.ActivityBumpWorkspaceParams {
483
+ WorkspaceID : workspace .ID ,
484
+ NextAutostart : time.Time {}.UTC (),
485
+ }).Return (nil )
486
+
487
+ // Workspace last used at gets bumped.
488
+ dbM .EXPECT ().UpdateWorkspaceLastUsedAt (gomock .Any (), database.UpdateWorkspaceLastUsedAtParams {
489
+ ID : workspace .ID ,
490
+ LastUsedAt : now ,
491
+ }).Return (nil )
492
+
493
+ resp , err := api .UpdateStats (context .Background (), req )
494
+ require .NoError (t , err )
495
+ require .Equal (t , & agentproto.UpdateStatsResponse {
496
+ ReportInterval : durationpb .New (10 * time .Second ),
497
+ }, resp )
498
+
499
+ batcher .mu .Lock ()
500
+ defer batcher .mu .Unlock ()
501
+ require .EqualValues (t , int64 (1 ), batcher .called )
502
+ require .EqualValues (t , batcher .lastStats .SessionCountVscode , 0 )
503
+ require .EqualValues (t , batcher .lastStats .SessionCountJetbrains , 0 )
504
+ require .EqualValues (t , batcher .lastStats .SessionCountReconnectingPty , 0 )
505
+ require .EqualValues (t , batcher .lastStats .SessionCountSsh , 0 )
506
+ })
409
507
}
410
508
411
509
func templateScheduleStorePtr (store schedule.TemplateScheduleStore ) * atomic.Pointer [schedule.TemplateScheduleStore ] {
0 commit comments