go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/bisection/testfailureanalysis/status_updater.go (about) 1 // Copyright 2023 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package testfailureanalysis handles test failure analysis. 16 package testfailureanalysis 17 18 import ( 19 "context" 20 21 "go.chromium.org/luci/bisection/model" 22 pb "go.chromium.org/luci/bisection/proto/v1" 23 "go.chromium.org/luci/bisection/util/datastoreutil" 24 "go.chromium.org/luci/common/clock" 25 "go.chromium.org/luci/common/errors" 26 "go.chromium.org/luci/gae/service/datastore" 27 ) 28 29 // UpdateAnalysisStatus updates status of a test failure analysis. 30 func UpdateAnalysisStatus(ctx context.Context, tfa *model.TestFailureAnalysis, status pb.AnalysisStatus, runStatus pb.AnalysisRunStatus) error { 31 return datastore.RunInTransaction(ctx, func(ctx context.Context) error { 32 e := datastore.Get(ctx, tfa) 33 if e != nil { 34 return e 35 } 36 37 // If the run has ended or canceled, we don't want to do anything. 38 if tfa.RunStatus == pb.AnalysisRunStatus_ENDED || tfa.RunStatus == pb.AnalysisRunStatus_CANCELED { 39 return nil 40 } 41 42 // All the same, no need to update. 43 if tfa.RunStatus == runStatus && tfa.Status == status { 44 return nil 45 } 46 47 if runStatus == pb.AnalysisRunStatus_ENDED || runStatus == pb.AnalysisRunStatus_CANCELED { 48 tfa.EndTime = clock.Now(ctx) 49 } 50 // Do not update start time again if it has started. 51 if runStatus == pb.AnalysisRunStatus_STARTED && tfa.RunStatus != pb.AnalysisRunStatus_STARTED { 52 tfa.StartTime = clock.Now(ctx) 53 } 54 55 tfa.Status = status 56 tfa.RunStatus = runStatus 57 return datastore.Put(ctx, tfa) 58 }, nil) 59 } 60 61 // UpdateNthSectionAnalysisStatus updates status of a test failure analysis. 62 func UpdateNthSectionAnalysisStatus(ctx context.Context, nsa *model.TestNthSectionAnalysis, status pb.AnalysisStatus, runStatus pb.AnalysisRunStatus) error { 63 return datastore.RunInTransaction(ctx, func(ctx context.Context) error { 64 e := datastore.Get(ctx, nsa) 65 if e != nil { 66 return e 67 } 68 69 // If the run has ended or canceled, we don't want to do anything. 70 if nsa.RunStatus == pb.AnalysisRunStatus_ENDED || nsa.RunStatus == pb.AnalysisRunStatus_CANCELED { 71 return nil 72 } 73 74 // All the same, no need to update. 75 if nsa.RunStatus == runStatus && nsa.Status == status { 76 return nil 77 } 78 79 nsa.Status = status 80 nsa.RunStatus = runStatus 81 if runStatus == pb.AnalysisRunStatus_ENDED || runStatus == pb.AnalysisRunStatus_CANCELED { 82 nsa.EndTime = clock.Now(ctx) 83 } 84 return datastore.Put(ctx, nsa) 85 }, nil) 86 } 87 88 // UpdateAnalysisStatusWhenError updates analysis and nthsection analysis 89 // when an error occured. 90 // As there still maybe reruns in progress, we should check if there are still 91 // running reruns. 92 func UpdateAnalysisStatusWhenError(ctx context.Context, tfa *model.TestFailureAnalysis) error { 93 reruns, err := datastoreutil.GetInProgressReruns(ctx, tfa) 94 if err != nil { 95 return errors.Annotate(err, "get in progress rerun").Err() 96 } 97 // Analysis still in progress, we don't need to do anything. 98 if len(reruns) > 0 { 99 return nil 100 } 101 // Otherwise, update status to error. 102 nsa, err := datastoreutil.GetTestNthSectionForAnalysis(ctx, tfa) 103 if err != nil { 104 return errors.Annotate(err, "get test nthsection for analysis").Err() 105 } 106 if nsa == nil { 107 return errors.New("no nthsection analysis") 108 } 109 // This will be a no-op if the nthsection analysis already ended or canceled. 110 err = UpdateNthSectionAnalysisStatus(ctx, nsa, pb.AnalysisStatus_ERROR, pb.AnalysisRunStatus_ENDED) 111 if err != nil { 112 return errors.Annotate(err, "update nthsection analysis status").Err() 113 } 114 115 // This will be a no-op if the analysis already ended or canceled. 116 err = UpdateAnalysisStatus(ctx, tfa, pb.AnalysisStatus_ERROR, pb.AnalysisRunStatus_ENDED) 117 if err != nil { 118 return errors.Annotate(err, "update analysis status").Err() 119 } 120 return nil 121 }