@@ -4401,6 +4401,309 @@ func TestGetPresetsBackoff(t *testing.T) {
4401
4401
})
4402
4402
}
4403
4403
4404
+ func TestGetPresetsAtFailureLimit (t * testing.T ) {
4405
+ t .Parallel ()
4406
+ if ! dbtestutil .WillUsePostgres () {
4407
+ t .SkipNow ()
4408
+ }
4409
+
4410
+ now := dbtime .Now ()
4411
+ hourBefore := now .Add (- time .Hour )
4412
+ orgID := uuid .New ()
4413
+ userID := uuid .New ()
4414
+
4415
+ findPresetByTmplVersionID := func (hardLimitedPresets []database.GetPresetsAtFailureLimitRow ,tmplVersionID uuid.UUID )* database.GetPresetsAtFailureLimitRow {
4416
+ for _ ,preset := range hardLimitedPresets {
4417
+ if preset .TemplateVersionID == tmplVersionID {
4418
+ return & preset
4419
+ }
4420
+ }
4421
+
4422
+ return nil
4423
+ }
4424
+
4425
+ testCases := []struct {
4426
+ name string
4427
+ // true - build is successful
4428
+ // false - build is unsuccessful
4429
+ buildSuccesses []bool
4430
+ hardLimit int64
4431
+ expHitHardLimit bool
4432
+ }{
4433
+ {
4434
+ name :"failed build" ,
4435
+ buildSuccesses : []bool {false },
4436
+ hardLimit :1 ,
4437
+ expHitHardLimit :true ,
4438
+ },
4439
+ {
4440
+ name :"2 failed builds" ,
4441
+ buildSuccesses : []bool {false ,false },
4442
+ hardLimit :1 ,
4443
+ expHitHardLimit :true ,
4444
+ },
4445
+ {
4446
+ name :"successful build" ,
4447
+ buildSuccesses : []bool {true },
4448
+ hardLimit :1 ,
4449
+ expHitHardLimit :false ,
4450
+ },
4451
+ {
4452
+ name :"last build is failed" ,
4453
+ buildSuccesses : []bool {true ,true ,false },
4454
+ hardLimit :1 ,
4455
+ expHitHardLimit :true ,
4456
+ },
4457
+ {
4458
+ name :"last build is successful" ,
4459
+ buildSuccesses : []bool {false ,false ,true },
4460
+ hardLimit :1 ,
4461
+ expHitHardLimit :false ,
4462
+ },
4463
+ {
4464
+ name :"last 3 builds are failed - hard limit is reached" ,
4465
+ buildSuccesses : []bool {true ,true ,false ,false ,false },
4466
+ hardLimit :3 ,
4467
+ expHitHardLimit :true ,
4468
+ },
4469
+ {
4470
+ name :"1 out of 3 last build is successful - hard limit is NOT reached" ,
4471
+ buildSuccesses : []bool {false ,false ,true ,false ,false },
4472
+ hardLimit :3 ,
4473
+ expHitHardLimit :false ,
4474
+ },
4475
+ }
4476
+
4477
+ for _ ,tc := range testCases {
4478
+ t .Run (tc .name ,func (t * testing.T ) {
4479
+ t .Parallel ()
4480
+
4481
+ db ,_ := dbtestutil .NewDB (t )
4482
+ ctx := testutil .Context (t ,testutil .WaitShort )
4483
+ dbgen .Organization (t ,db , database.Organization {
4484
+ ID :orgID ,
4485
+ })
4486
+ dbgen .User (t ,db , database.User {
4487
+ ID :userID ,
4488
+ })
4489
+
4490
+ tmpl := createTemplate (t ,db ,orgID ,userID )
4491
+ tmplV1 := createTmplVersionAndPreset (t ,db ,tmpl ,tmpl .ActiveVersionID ,now ,nil )
4492
+ for idx ,buildSuccess := range tc .buildSuccesses {
4493
+ createPrebuiltWorkspace (ctx ,t ,db ,tmpl ,tmplV1 ,orgID ,now ,& createPrebuiltWorkspaceOpts {
4494
+ failedJob :! buildSuccess ,
4495
+ createdAt :hourBefore .Add (time .Duration (idx )* time .Second ),
4496
+ })
4497
+ }
4498
+
4499
+ hardLimitedPresets ,err := db .GetPresetsAtFailureLimit (ctx ,tc .hardLimit )
4500
+ require .NoError (t ,err )
4501
+
4502
+ if ! tc .expHitHardLimit {
4503
+ require .Len (t ,hardLimitedPresets ,0 )
4504
+ return
4505
+ }
4506
+
4507
+ require .Len (t ,hardLimitedPresets ,1 )
4508
+ hardLimitedPreset := hardLimitedPresets [0 ]
4509
+ require .Equal (t ,hardLimitedPreset .TemplateVersionID ,tmpl .ActiveVersionID )
4510
+ require .Equal (t ,hardLimitedPreset .PresetID ,tmplV1 .preset .ID )
4511
+ })
4512
+ }
4513
+
4514
+ t .Run ("Ignore Inactive Version" ,func (t * testing.T ) {
4515
+ t .Parallel ()
4516
+
4517
+ db ,_ := dbtestutil .NewDB (t )
4518
+ ctx := testutil .Context (t ,testutil .WaitShort )
4519
+ dbgen .Organization (t ,db , database.Organization {
4520
+ ID :orgID ,
4521
+ })
4522
+ dbgen .User (t ,db , database.User {
4523
+ ID :userID ,
4524
+ })
4525
+
4526
+ tmpl := createTemplate (t ,db ,orgID ,userID )
4527
+ tmplV1 := createTmplVersionAndPreset (t ,db ,tmpl ,uuid .New (),now ,nil )
4528
+ createPrebuiltWorkspace (ctx ,t ,db ,tmpl ,tmplV1 ,orgID ,now ,& createPrebuiltWorkspaceOpts {
4529
+ failedJob :true ,
4530
+ })
4531
+
4532
+ // Active Version
4533
+ tmplV2 := createTmplVersionAndPreset (t ,db ,tmpl ,tmpl .ActiveVersionID ,now ,nil )
4534
+ createPrebuiltWorkspace (ctx ,t ,db ,tmpl ,tmplV2 ,orgID ,now ,& createPrebuiltWorkspaceOpts {
4535
+ failedJob :true ,
4536
+ })
4537
+ createPrebuiltWorkspace (ctx ,t ,db ,tmpl ,tmplV2 ,orgID ,now ,& createPrebuiltWorkspaceOpts {
4538
+ failedJob :true ,
4539
+ })
4540
+
4541
+ hardLimit := int64 (1 )
4542
+ hardLimitedPresets ,err := db .GetPresetsAtFailureLimit (ctx ,hardLimit )
4543
+ require .NoError (t ,err )
4544
+
4545
+ require .Len (t ,hardLimitedPresets ,1 )
4546
+ hardLimitedPreset := hardLimitedPresets [0 ]
4547
+ require .Equal (t ,hardLimitedPreset .TemplateVersionID ,tmpl .ActiveVersionID )
4548
+ require .Equal (t ,hardLimitedPreset .PresetID ,tmplV2 .preset .ID )
4549
+ })
4550
+
4551
+ t .Run ("Multiple Templates" ,func (t * testing.T ) {
4552
+ t .Parallel ()
4553
+
4554
+ db ,_ := dbtestutil .NewDB (t )
4555
+ ctx := testutil .Context (t ,testutil .WaitShort )
4556
+ dbgen .Organization (t ,db , database.Organization {
4557
+ ID :orgID ,
4558
+ })
4559
+ dbgen .User (t ,db , database.User {
4560
+ ID :userID ,
4561
+ })
4562
+
4563
+ tmpl1 := createTemplate (t ,db ,orgID ,userID )
4564
+ tmpl1V1 := createTmplVersionAndPreset (t ,db ,tmpl1 ,tmpl1 .ActiveVersionID ,now ,nil )
4565
+ createPrebuiltWorkspace (ctx ,t ,db ,tmpl1 ,tmpl1V1 ,orgID ,now ,& createPrebuiltWorkspaceOpts {
4566
+ failedJob :true ,
4567
+ })
4568
+
4569
+ tmpl2 := createTemplate (t ,db ,orgID ,userID )
4570
+ tmpl2V1 := createTmplVersionAndPreset (t ,db ,tmpl2 ,tmpl2 .ActiveVersionID ,now ,nil )
4571
+ createPrebuiltWorkspace (ctx ,t ,db ,tmpl2 ,tmpl2V1 ,orgID ,now ,& createPrebuiltWorkspaceOpts {
4572
+ failedJob :true ,
4573
+ })
4574
+
4575
+ hardLimit := int64 (1 )
4576
+ hardLimitedPresets ,err := db .GetPresetsAtFailureLimit (ctx ,hardLimit )
4577
+
4578
+ require .NoError (t ,err )
4579
+
4580
+ require .Len (t ,hardLimitedPresets ,2 )
4581
+ {
4582
+ hardLimitedPreset := findPresetByTmplVersionID (hardLimitedPresets ,tmpl1 .ActiveVersionID )
4583
+ require .Equal (t ,hardLimitedPreset .TemplateVersionID ,tmpl1 .ActiveVersionID )
4584
+ require .Equal (t ,hardLimitedPreset .PresetID ,tmpl1V1 .preset .ID )
4585
+ }
4586
+ {
4587
+ hardLimitedPreset := findPresetByTmplVersionID (hardLimitedPresets ,tmpl2 .ActiveVersionID )
4588
+ require .Equal (t ,hardLimitedPreset .TemplateVersionID ,tmpl2 .ActiveVersionID )
4589
+ require .Equal (t ,hardLimitedPreset .PresetID ,tmpl2V1 .preset .ID )
4590
+ }
4591
+ })
4592
+
4593
+ t .Run ("Multiple Templates, Versions and Workspace Builds" ,func (t * testing.T ) {
4594
+ t .Parallel ()
4595
+
4596
+ db ,_ := dbtestutil .NewDB (t )
4597
+ ctx := testutil .Context (t ,testutil .WaitShort )
4598
+ dbgen .Organization (t ,db , database.Organization {
4599
+ ID :orgID ,
4600
+ })
4601
+ dbgen .User (t ,db , database.User {
4602
+ ID :userID ,
4603
+ })
4604
+
4605
+ tmpl1 := createTemplate (t ,db ,orgID ,userID )
4606
+ tmpl1V1 := createTmplVersionAndPreset (t ,db ,tmpl1 ,tmpl1 .ActiveVersionID ,now ,nil )
4607
+ createPrebuiltWorkspace (ctx ,t ,db ,tmpl1 ,tmpl1V1 ,orgID ,now ,& createPrebuiltWorkspaceOpts {
4608
+ failedJob :true ,
4609
+ })
4610
+ createPrebuiltWorkspace (ctx ,t ,db ,tmpl1 ,tmpl1V1 ,orgID ,now ,& createPrebuiltWorkspaceOpts {
4611
+ failedJob :true ,
4612
+ })
4613
+
4614
+ tmpl2 := createTemplate (t ,db ,orgID ,userID )
4615
+ tmpl2V1 := createTmplVersionAndPreset (t ,db ,tmpl2 ,tmpl2 .ActiveVersionID ,now ,nil )
4616
+ createPrebuiltWorkspace (ctx ,t ,db ,tmpl2 ,tmpl2V1 ,orgID ,now ,& createPrebuiltWorkspaceOpts {
4617
+ failedJob :true ,
4618
+ })
4619
+ createPrebuiltWorkspace (ctx ,t ,db ,tmpl2 ,tmpl2V1 ,orgID ,now ,& createPrebuiltWorkspaceOpts {
4620
+ failedJob :true ,
4621
+ })
4622
+
4623
+ tmpl3 := createTemplate (t ,db ,orgID ,userID )
4624
+ tmpl3V1 := createTmplVersionAndPreset (t ,db ,tmpl3 ,uuid .New (),now ,nil )
4625
+ createPrebuiltWorkspace (ctx ,t ,db ,tmpl3 ,tmpl3V1 ,orgID ,now ,& createPrebuiltWorkspaceOpts {
4626
+ failedJob :true ,
4627
+ })
4628
+
4629
+ tmpl3V2 := createTmplVersionAndPreset (t ,db ,tmpl3 ,tmpl3 .ActiveVersionID ,now ,nil )
4630
+ createPrebuiltWorkspace (ctx ,t ,db ,tmpl3 ,tmpl3V2 ,orgID ,now ,& createPrebuiltWorkspaceOpts {
4631
+ failedJob :true ,
4632
+ })
4633
+ createPrebuiltWorkspace (ctx ,t ,db ,tmpl3 ,tmpl3V2 ,orgID ,now ,& createPrebuiltWorkspaceOpts {
4634
+ failedJob :true ,
4635
+ })
4636
+
4637
+ hardLimit := int64 (2 )
4638
+ hardLimitedPresets ,err := db .GetPresetsAtFailureLimit (ctx ,hardLimit )
4639
+ require .NoError (t ,err )
4640
+
4641
+ require .Len (t ,hardLimitedPresets ,3 )
4642
+ {
4643
+ hardLimitedPreset := findPresetByTmplVersionID (hardLimitedPresets ,tmpl1 .ActiveVersionID )
4644
+ require .Equal (t ,hardLimitedPreset .TemplateVersionID ,tmpl1 .ActiveVersionID )
4645
+ require .Equal (t ,hardLimitedPreset .PresetID ,tmpl1V1 .preset .ID )
4646
+ }
4647
+ {
4648
+ hardLimitedPreset := findPresetByTmplVersionID (hardLimitedPresets ,tmpl2 .ActiveVersionID )
4649
+ require .Equal (t ,hardLimitedPreset .TemplateVersionID ,tmpl2 .ActiveVersionID )
4650
+ require .Equal (t ,hardLimitedPreset .PresetID ,tmpl2V1 .preset .ID )
4651
+ }
4652
+ {
4653
+ hardLimitedPreset := findPresetByTmplVersionID (hardLimitedPresets ,tmpl3 .ActiveVersionID )
4654
+ require .Equal (t ,hardLimitedPreset .TemplateVersionID ,tmpl3 .ActiveVersionID )
4655
+ require .Equal (t ,hardLimitedPreset .PresetID ,tmpl3V2 .preset .ID )
4656
+ }
4657
+ })
4658
+
4659
+ t .Run ("No Workspace Builds" ,func (t * testing.T ) {
4660
+ t .Parallel ()
4661
+
4662
+ db ,_ := dbtestutil .NewDB (t )
4663
+ ctx := testutil .Context (t ,testutil .WaitShort )
4664
+ dbgen .Organization (t ,db , database.Organization {
4665
+ ID :orgID ,
4666
+ })
4667
+ dbgen .User (t ,db , database.User {
4668
+ ID :userID ,
4669
+ })
4670
+
4671
+ tmpl1 := createTemplate (t ,db ,orgID ,userID )
4672
+ tmpl1V1 := createTmplVersionAndPreset (t ,db ,tmpl1 ,tmpl1 .ActiveVersionID ,now ,nil )
4673
+ _ = tmpl1V1
4674
+
4675
+ hardLimit := int64 (1 )
4676
+ hardLimitedPresets ,err := db .GetPresetsAtFailureLimit (ctx ,hardLimit )
4677
+ require .NoError (t ,err )
4678
+ require .Nil (t ,hardLimitedPresets )
4679
+ })
4680
+
4681
+ t .Run ("No Failed Workspace Builds" ,func (t * testing.T ) {
4682
+ t .Parallel ()
4683
+
4684
+ db ,_ := dbtestutil .NewDB (t )
4685
+ ctx := testutil .Context (t ,testutil .WaitShort )
4686
+ dbgen .Organization (t ,db , database.Organization {
4687
+ ID :orgID ,
4688
+ })
4689
+ dbgen .User (t ,db , database.User {
4690
+ ID :userID ,
4691
+ })
4692
+
4693
+ tmpl1 := createTemplate (t ,db ,orgID ,userID )
4694
+ tmpl1V1 := createTmplVersionAndPreset (t ,db ,tmpl1 ,tmpl1 .ActiveVersionID ,now ,nil )
4695
+ successfulJobOpts := createPrebuiltWorkspaceOpts {}
4696
+ createPrebuiltWorkspace (ctx ,t ,db ,tmpl1 ,tmpl1V1 ,orgID ,now ,& successfulJobOpts )
4697
+ createPrebuiltWorkspace (ctx ,t ,db ,tmpl1 ,tmpl1V1 ,orgID ,now ,& successfulJobOpts )
4698
+ createPrebuiltWorkspace (ctx ,t ,db ,tmpl1 ,tmpl1V1 ,orgID ,now ,& successfulJobOpts )
4699
+
4700
+ hardLimit := int64 (1 )
4701
+ hardLimitedPresets ,err := db .GetPresetsAtFailureLimit (ctx ,hardLimit )
4702
+ require .NoError (t ,err )
4703
+ require .Nil (t ,hardLimitedPresets )
4704
+ })
4705
+ }
4706
+
4404
4707
func requireUsersMatch (t testing.TB ,expected []database.User ,found []database.GetUsersRow ,msg string ) {
4405
4708
t .Helper ()
4406
4709
require .ElementsMatch (t ,expected ,database .ConvertUserRows (found ),msg )