@@ -2842,9 +2842,12 @@ func TestCompleteJob(t *testing.T) {
2842
2842
// has_ai_task has a default value of nil, but once the workspace build completes it will have a value;
2843
2843
// it is set to "true" if the related template has any coder_ai_task resources defined, and its sidebar app ID
2844
2844
// will be set as well in that case.
2845
+ // HACK(johnstcn): we also set it to "true" if any _previous_ workspace builds ever had it set to "true".
2846
+ // This is to avoid tasks "disappearing" when you stop them.
2845
2847
t .Run ("WorkspaceBuild" , func (t * testing.T ) {
2846
2848
type testcase struct {
2847
2849
name string
2850
+ seedFunc func (context.Context , testing.TB , database.Store ) error // If you need to insert other resources
2848
2851
transition database.WorkspaceTransition
2849
2852
input * proto.CompletedJob_WorkspaceBuild
2850
2853
expectHasAiTask bool
@@ -2944,6 +2947,17 @@ func TestCompleteJob(t *testing.T) {
2944
2947
expectHasAiTask : true ,
2945
2948
expectUsageEvent : false ,
2946
2949
},
2950
+ {
2951
+ name : "current build does not have ai task but previous build did" ,
2952
+ seedFunc : seedPreviousWorkspaceStartWithAITask ,
2953
+ transition : database .WorkspaceTransitionStop ,
2954
+ input : & proto.CompletedJob_WorkspaceBuild {
2955
+ AiTasks : []* sdkproto.AITask {},
2956
+ Resources : []* sdkproto.Resource {},
2957
+ },
2958
+ expectHasAiTask : true ,
2959
+ expectUsageEvent : false ,
2960
+ },
2947
2961
} {
2948
2962
t .Run (tc .name , func (t * testing.T ) {
2949
2963
t .Parallel ()
@@ -2980,6 +2994,9 @@ func TestCompleteJob(t *testing.T) {
2980
2994
})
2981
2995
2982
2996
ctx := testutil .Context (t , testutil .WaitShort )
2997
+ if tc .seedFunc != nil {
2998
+ require .NoError (t , tc .seedFunc (ctx , t , db ))
2999
+ }
2983
3000
2984
3001
buildJobID := uuid .New ()
2985
3002
wsBuildID := uuid .New ()
@@ -2999,8 +3016,13 @@ func TestCompleteJob(t *testing.T) {
2999
3016
Tags : pd .Tags ,
3000
3017
})
3001
3018
require .NoError (t , err )
3019
+ var buildNum int32
3020
+ if latestBuild , err := db .GetLatestWorkspaceBuildByWorkspaceID (ctx , workspaceTable .ID ); err == nil {
3021
+ buildNum = latestBuild .BuildNumber
3022
+ }
3002
3023
build := dbgen .WorkspaceBuild (t , db , database.WorkspaceBuild {
3003
3024
ID : wsBuildID ,
3025
+ BuildNumber : buildNum + 1 ,
3004
3026
JobID : buildJobID ,
3005
3027
WorkspaceID : workspaceTable .ID ,
3006
3028
TemplateVersionID : version .ID ,
@@ -3038,7 +3060,7 @@ func TestCompleteJob(t *testing.T) {
3038
3060
require .True (t , build .HasAITask .Valid ) // We ALWAYS expect a value to be set, therefore not nil, i.e. valid = true.
3039
3061
require .Equal (t , tc .expectHasAiTask , build .HasAITask .Bool )
3040
3062
3041
- if tc .expectHasAiTask {
3063
+ if tc .expectHasAiTask && build . Transition != database . WorkspaceTransitionStop {
3042
3064
require .Equal (t , sidebarAppID , build .AITaskSidebarAppID .UUID .String ())
3043
3065
}
3044
3066
@@ -4244,3 +4266,63 @@ func (f *fakeUsageInserter) InsertDiscreteUsageEvent(_ context.Context, _ databa
4244
4266
f .collectedEvents = append (f .collectedEvents , event )
4245
4267
return nil
4246
4268
}
4269
+
4270
+ func seedPreviousWorkspaceStartWithAITask (ctx context.Context , t testing.TB , db database.Store ) error {
4271
+ t .Helper ()
4272
+ // If the below looks slightly convoluted, that's because it is.
4273
+ // The workspace doesn't yet have a latest build, so querying all
4274
+ // workspaces will fail.
4275
+ tpls , err := db .GetTemplates (ctx )
4276
+ if err != nil {
4277
+ return xerrors .Errorf ("seedFunc: get template: %w" , err )
4278
+ }
4279
+ if len (tpls ) != 1 {
4280
+ return xerrors .Errorf ("seedFunc: expected exactly one template, got %d" , len (tpls ))
4281
+ }
4282
+ ws , err := db .GetWorkspacesByTemplateID (ctx , tpls [0 ].ID )
4283
+ if err != nil {
4284
+ return xerrors .Errorf ("seedFunc: get workspaces: %w" , err )
4285
+ }
4286
+ if len (ws ) != 1 {
4287
+ return xerrors .Errorf ("seedFunc: expected exactly one workspace, got %d" , len (ws ))
4288
+ }
4289
+ w := ws [0 ]
4290
+ prevJob := dbgen .ProvisionerJob (t , db , nil , database.ProvisionerJob {
4291
+ OrganizationID : w .OrganizationID ,
4292
+ InitiatorID : w .OwnerID ,
4293
+ Type : database .ProvisionerJobTypeWorkspaceBuild ,
4294
+ })
4295
+ tvs , err := db .GetTemplateVersionsByTemplateID (ctx , database.GetTemplateVersionsByTemplateIDParams {
4296
+ TemplateID : tpls [0 ].ID ,
4297
+ })
4298
+ if err != nil {
4299
+ return xerrors .Errorf ("seedFunc: get template version: %w" , err )
4300
+ }
4301
+ if len (tvs ) != 1 {
4302
+ return xerrors .Errorf ("seedFunc: expected exactly one template version, got %d" , len (tvs ))
4303
+ }
4304
+ if tpls [0 ].ActiveVersionID == uuid .Nil {
4305
+ return xerrors .Errorf ("seedFunc: active version id is nil" )
4306
+ }
4307
+ res := dbgen .WorkspaceResource (t , db , database.WorkspaceResource {
4308
+ JobID : prevJob .ID ,
4309
+ })
4310
+ agt := dbgen .WorkspaceAgent (t , db , database.WorkspaceAgent {
4311
+ ResourceID : res .ID ,
4312
+ })
4313
+ wa := dbgen .WorkspaceApp (t , db , database.WorkspaceApp {
4314
+ AgentID : agt .ID ,
4315
+ })
4316
+ _ = dbgen .WorkspaceBuild (t , db , database.WorkspaceBuild {
4317
+ BuildNumber : 1 ,
4318
+ HasAITask : sql.NullBool {Valid : true , Bool : true },
4319
+ AITaskSidebarAppID : uuid.NullUUID {Valid : true , UUID : wa .ID },
4320
+ ID : w .ID ,
4321
+ InitiatorID : w .OwnerID ,
4322
+ JobID : prevJob .ID ,
4323
+ TemplateVersionID : tvs [0 ].ID ,
4324
+ Transition : database .WorkspaceTransitionStart ,
4325
+ WorkspaceID : w .ID ,
4326
+ })
4327
+ return nil
4328
+ }
0 commit comments