@@ -2842,9 +2842,12 @@ func TestCompleteJob(t *testing.T) {
28422842 // has_ai_task has a default value of nil, but once the workspace build completes it will have a value;
28432843 // it is set to "true" if the related template has any coder_ai_task resources defined, and its sidebar app ID
28442844 // 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.
28452847 t .Run ("WorkspaceBuild" , func (t * testing.T ) {
28462848 type testcase struct {
28472849 name string
2850+ seedFunc func (context.Context , testing.TB , database.Store ) error // If you need to insert other resources
28482851 transition database.WorkspaceTransition
28492852 input * proto.CompletedJob_WorkspaceBuild
28502853 expectHasAiTask bool
@@ -2944,6 +2947,17 @@ func TestCompleteJob(t *testing.T) {
29442947 expectHasAiTask : true ,
29452948 expectUsageEvent : false ,
29462949 },
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+ },
29472961 } {
29482962 t .Run (tc .name , func (t * testing.T ) {
29492963 t .Parallel ()
@@ -2980,6 +2994,9 @@ func TestCompleteJob(t *testing.T) {
29802994 })
29812995
29822996 ctx := testutil .Context (t , testutil .WaitShort )
2997+ if tc .seedFunc != nil {
2998+ require .NoError (t , tc .seedFunc (ctx , t , db ))
2999+ }
29833000
29843001 buildJobID := uuid .New ()
29853002 wsBuildID := uuid .New ()
@@ -2999,8 +3016,13 @@ func TestCompleteJob(t *testing.T) {
29993016 Tags : pd .Tags ,
30003017 })
30013018 require .NoError (t , err )
3019+ var buildNum int32
3020+ if latestBuild , err := db .GetLatestWorkspaceBuildByWorkspaceID (ctx , workspaceTable .ID ); err == nil {
3021+ buildNum = latestBuild .BuildNumber
3022+ }
30023023 build := dbgen .WorkspaceBuild (t , db , database.WorkspaceBuild {
30033024 ID : wsBuildID ,
3025+ BuildNumber : buildNum + 1 ,
30043026 JobID : buildJobID ,
30053027 WorkspaceID : workspaceTable .ID ,
30063028 TemplateVersionID : version .ID ,
@@ -3038,7 +3060,7 @@ func TestCompleteJob(t *testing.T) {
30383060 require .True (t , build .HasAITask .Valid ) // We ALWAYS expect a value to be set, therefore not nil, i.e. valid = true.
30393061 require .Equal (t , tc .expectHasAiTask , build .HasAITask .Bool )
30403062
3041- if tc .expectHasAiTask {
3063+ if tc .expectHasAiTask && build . Transition != database . WorkspaceTransitionStop {
30423064 require .Equal (t , sidebarAppID , build .AITaskSidebarAppID .UUID .String ())
30433065 }
30443066
@@ -4244,3 +4266,63 @@ func (f *fakeUsageInserter) InsertDiscreteUsageEvent(_ context.Context, _ databa
42444266 f .collectedEvents = append (f .collectedEvents , event )
42454267 return nil
42464268}
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