go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/bisection/culpritaction/revertculprit/revert_test_failure_culprit.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 revertculprit contains the logic to revert culprits 16 package revertculprit 17 18 import ( 19 "context" 20 21 "go.chromium.org/luci/bisection/internal/lucianalysis" 22 pb "go.chromium.org/luci/bisection/proto/v1" 23 "go.chromium.org/luci/bisection/util/datastoreutil" 24 "go.chromium.org/luci/bisection/util/loggingutil" 25 "go.chromium.org/luci/common/errors" 26 "go.chromium.org/luci/common/logging" 27 "go.chromium.org/luci/gae/service/datastore" 28 ) 29 30 type AnalysisClient interface { 31 TestIsUnexpectedConsistently(ctx context.Context, project string, key lucianalysis.TestVerdictKey, sinceCommitPosition int64) (bool, error) 32 } 33 34 func processTestFailureCulpritTask(ctx context.Context, analysisID int64, luciAnalysis AnalysisClient) error { 35 ctx = loggingutil.SetAnalysisID(ctx, analysisID) 36 logging.Infof(ctx, "Processing test failure culprit action") 37 38 // Get culprit model. 39 tfa, err := datastoreutil.GetTestFailureAnalysis(ctx, analysisID) 40 if err != nil { 41 return errors.Annotate(err, "get test failure analysis").Err() 42 } 43 44 culpritKey := tfa.VerifiedCulpritKey 45 culpritModel, err := datastoreutil.GetSuspect(ctx, culpritKey.IntID(), culpritKey.Parent()) 46 if err != nil { 47 return errors.Annotate(err, "get suspect").Err() 48 } 49 50 // We mark that actions have been taken for the analyses. 51 defer func() { 52 culpritModel.HasTakenActions = true 53 err := datastore.Put(ctx, culpritModel) 54 if err != nil { 55 // Just log, nothing we can do now. 56 logging.Errorf(ctx, "failed to set HasTakenActions: %v", err) 57 } 58 }() 59 60 // Check if primary test is still failing. 61 primaryTestFailure, err := datastoreutil.GetPrimaryTestFailure(ctx, tfa) 62 if err != nil { 63 return errors.Annotate(err, "get primary test failure").Err() 64 } 65 key := lucianalysis.TestVerdictKey{ 66 TestID: primaryTestFailure.TestID, 67 VariantHash: primaryTestFailure.VariantHash, 68 RefHash: primaryTestFailure.RefHash, 69 } 70 stillFail, err := luciAnalysis.TestIsUnexpectedConsistently(ctx, tfa.Project, key, primaryTestFailure.RegressionEndPosition) 71 if err != nil { 72 return errors.Annotate(err, "test is unexpected consistently").Err() 73 } 74 75 // If the latest verdict is not unexpected anymore, do not perform any action. 76 if !stillFail { 77 saveInactionReason(ctx, culpritModel, pb.CulpritInactionReason_TEST_NO_LONGER_UNEXPECTED) 78 return nil 79 } 80 81 if err := TakeCulpritAction(ctx, culpritModel); err != nil { 82 return errors.Annotate(err, "revert culprit suspect_id %d", culpritModel.Id).Err() 83 } 84 return nil 85 }