go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/cv/internal/retention/tryjob_test.go (about) 1 // Copyright 2024 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 retention 16 17 import ( 18 "slices" 19 "testing" 20 "time" 21 22 "go.chromium.org/luci/gae/service/datastore" 23 24 "go.chromium.org/luci/cv/internal/common" 25 "go.chromium.org/luci/cv/internal/cvtesting" 26 "go.chromium.org/luci/cv/internal/run" 27 "go.chromium.org/luci/cv/internal/tryjob" 28 29 . "github.com/smartystreets/goconvey/convey" 30 . "go.chromium.org/luci/common/testing/assertions" 31 ) 32 33 func TestScheduleWipeoutTryjobs(t *testing.T) { 34 t.Parallel() 35 36 Convey("Schedule wipeout tryjobs tasks", t, func() { 37 ct := cvtesting.Test{} 38 ctx, cancel := ct.SetUp(t) 39 defer cancel() 40 registerWipeoutTryjobsTask(ct.TQDispatcher) 41 42 // create tryjobs with 1 minute interval. 43 tryjobs := make([]*tryjob.Tryjob, 3*tryjobsPerTask) 44 for i := range tryjobs { 45 tryjobs[i] = tryjob.MustBuildbucketID("bb.example.com", int64(i+1000)). 46 MustCreateIfNotExists(ctx) 47 ct.Clock.Add(1 * time.Minute) 48 } 49 50 // Make half of the tryjobs eligible for wipeout 51 ct.Clock.Set(tryjobs[len(tryjobs)/2].EntityUpdateTime.Add(retentionPeriod)) 52 53 So(scheduleWipeoutTryjobsTasks(ctx, ct.TQDispatcher), ShouldBeNil) 54 var expectedTryjobIDs common.TryjobIDs 55 for _, tj := range tryjobs[:len(tryjobs)/2] { 56 expectedTryjobIDs = append(expectedTryjobIDs, tj.ID) 57 } 58 59 var actualTryjobIDs common.TryjobIDs 60 for _, task := range ct.TQ.Tasks() { 61 So(task.ETA, ShouldHappenWithin, wipeoutTasksDistInterval, ct.Clock.Now()) 62 ids := task.Payload.(*WipeoutTryjobsTask).GetIds() 63 So(len(ids), ShouldBeLessThanOrEqualTo, tryjobsPerTask) 64 for _, id := range ids { 65 actualTryjobIDs = append(actualTryjobIDs, common.TryjobID(id)) 66 } 67 } 68 slices.Sort(expectedTryjobIDs) 69 slices.Sort(actualTryjobIDs) 70 So(actualTryjobIDs, ShouldResemble, expectedTryjobIDs) 71 }) 72 } 73 func TestWipeoutTryjobs(t *testing.T) { 74 t.Parallel() 75 76 Convey("Wipeout Tryjobs", t, func() { 77 ct := cvtesting.Test{} 78 ctx, cancel := ct.SetUp(t) 79 defer cancel() 80 81 tj := tryjob.MustBuildbucketID("bb.example.com", 12345). 82 MustCreateIfNotExists(ctx) 83 ct.Clock.Add(2 * retentionPeriod) // make tryjob eligible for wipeout 84 85 Convey("Can wipeout tryjob", func() { 86 Convey("when there's no watching run", func() { 87 So(wipeoutTryjobs(ctx, common.TryjobIDs{tj.ID}), ShouldBeNil) 88 So(datastore.Get(ctx, &tryjob.Tryjob{ID: tj.ID}), ShouldErrLike, datastore.ErrNoSuchEntity) 89 }) 90 Convey("when all watching run no longer exists", func() { 91 tj.LaunchedBy = common.MakeRunID("infra", tj.EntityCreateTime, 1, []byte("deadbeef")) 92 tj.ReusedBy = append(tj.ReusedBy, common.MakeRunID("infra", tj.EntityCreateTime.Add(1*time.Minute), 1, []byte("deadbeef"))) 93 So(wipeoutTryjobs(ctx, common.TryjobIDs{tj.ID}), ShouldBeNil) 94 So(datastore.Get(ctx, &tryjob.Tryjob{ID: tj.ID}), ShouldErrLike, datastore.ErrNoSuchEntity) 95 }) 96 }) 97 98 Convey("Don't wipeout tryjob", func() { 99 Convey("When a run that use this tryjob still exists", func() { 100 r := &run.Run{ 101 ID: common.MakeRunID("infra", tj.EntityCreateTime, 1, []byte("deadbeef")), 102 } 103 tj.LaunchedBy = r.ID 104 tj.ReusedBy = append(tj.ReusedBy, common.MakeRunID("infra", tj.EntityCreateTime.Add(-1*time.Minute), 1, []byte("deadbeef"))) 105 So(datastore.Put(ctx, r, tj), ShouldBeNil) 106 So(wipeoutTryjobs(ctx, common.TryjobIDs{tj.ID}), ShouldBeNil) 107 So(datastore.Get(ctx, &tryjob.Tryjob{ID: tj.ID}), ShouldBeNil) 108 }) 109 110 Convey("When Tryjob doesn't exist", func() { 111 So(wipeoutTryjobs(ctx, common.TryjobIDs{tj.ID + 1}), ShouldBeNil) 112 }) 113 }) 114 }) 115 }