go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/resultdb/internal/services/deadlineenforcer/deadline_enforcer_test.go (about) 1 // Copyright 2021 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 deadlineenforcer 16 17 import ( 18 "context" 19 "testing" 20 "time" 21 22 "go.chromium.org/luci/common/clock" 23 "go.chromium.org/luci/common/tsmon" 24 "go.chromium.org/luci/common/tsmon/distribution" 25 "go.chromium.org/luci/server/tq" 26 27 "go.chromium.org/luci/resultdb/internal/invocations" 28 "go.chromium.org/luci/resultdb/internal/tasks/taskspb" 29 "go.chromium.org/luci/resultdb/internal/testutil" 30 "go.chromium.org/luci/resultdb/internal/testutil/insert" 31 resultpb "go.chromium.org/luci/resultdb/proto/v1" 32 33 . "github.com/smartystreets/goconvey/convey" 34 . "go.chromium.org/luci/common/testing/assertions" 35 ) 36 37 func TestExpiredInvocations(t *testing.T) { 38 Convey(`ExpiredInvocations`, t, func() { 39 ctx := testutil.SpannerTestContext(t) 40 ctx, cancel := context.WithTimeout(ctx, 10*time.Second) 41 defer cancel() 42 43 ctx, sched := tq.TestingContext(ctx, nil) 44 ctx, _ = tsmon.WithDummyInMemory(ctx) 45 store := tsmon.Store(ctx) 46 47 past := clock.Now(ctx).Add(-10 * time.Minute) 48 future := clock.Now(ctx).Add(10 * time.Minute) 49 50 testutil.MustApply(ctx, 51 insert.Invocation("expired", resultpb.Invocation_ACTIVE, map[string]any{"Deadline": past}), 52 insert.Invocation("unexpired", resultpb.Invocation_ACTIVE, map[string]any{"Deadline": future}), 53 ) 54 55 s, err := invocations.CurrentMaxShard(ctx) 56 So(err, ShouldBeNil) 57 for i := 0; i < s+1; i++ { 58 So(enforceOneShard(ctx, i), ShouldBeNil) 59 } 60 61 So(sched.Tasks().Payloads()[0], ShouldResembleProto, &taskspb.TryFinalizeInvocation{InvocationId: "expired"}) 62 var state resultpb.Invocation_State 63 testutil.MustReadRow(ctx, "Invocations", invocations.ID("expired").Key(), map[string]any{ 64 "State": &state, 65 }) 66 So(state, ShouldEqual, resultpb.Invocation_FINALIZING) 67 testutil.MustReadRow(ctx, "Invocations", invocations.ID("unexpired").Key(), map[string]any{ 68 "State": &state, 69 }) 70 So(state, ShouldEqual, resultpb.Invocation_ACTIVE) 71 72 So(store.Get(ctx, overdueInvocationsFinalized, time.Time{}, []any{insert.TestRealm}), ShouldEqual, 1) 73 d := store.Get(ctx, timeOverdue, time.Time{}, []any{insert.TestRealm}).(*distribution.Distribution) 74 // The 10 minute (600 s) delay should fall into bucket 29 (~400k - ~630k ms). 75 // allow +/- 1 bucket for clock shenanigans. 76 So(d.Buckets()[28] == 1 || d.Buckets()[29] == 1 || d.Buckets()[30] == 1, ShouldBeTrue) 77 }) 78 }