blob: b8cb87b28c7babcfd9c2115dcf8a5379752f6b4f [file] [log] [blame]
// Copyright 2021 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package deadlineenforcer
import (
"context"
"testing"
"time"
"google.golang.org/protobuf/reflect/protoreflect"
"go.chromium.org/luci/common/clock"
"go.chromium.org/luci/common/tsmon"
"go.chromium.org/luci/common/tsmon/distribution"
"go.chromium.org/luci/server/tq"
"go.chromium.org/luci/resultdb/internal/invocations"
"go.chromium.org/luci/resultdb/internal/tasks/taskspb"
"go.chromium.org/luci/resultdb/internal/testutil"
"go.chromium.org/luci/resultdb/internal/testutil/insert"
resultpb "go.chromium.org/luci/resultdb/proto/v1"
. "github.com/smartystreets/goconvey/convey"
. "go.chromium.org/luci/common/testing/assertions"
)
func TestExpiredInvocations(t *testing.T) {
Convey(`ExpiredInvocations`, t, func() {
ctx := testutil.SpannerTestContext(t)
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
ctx, sched := tq.TestingContext(ctx, nil)
ctx, _ = tsmon.WithDummyInMemory(ctx)
store := tsmon.Store(ctx)
past := clock.Now(ctx).Add(-10 * time.Minute)
future := clock.Now(ctx).Add(10 * time.Minute)
testutil.MustApply(ctx,
insert.Invocation("expired", resultpb.Invocation_ACTIVE, map[string]any{"Deadline": past}),
insert.Invocation("unexpired", resultpb.Invocation_ACTIVE, map[string]any{"Deadline": future}),
)
s, err := invocations.CurrentMaxShard(ctx)
So(err, ShouldBeNil)
for i := 0; i < s+1; i++ {
So(enforceOneShard(ctx, i), ShouldBeNil)
}
So(sched.Tasks().Payloads(), ShouldResembleProto, []protoreflect.ProtoMessage{
&taskspb.RunExportNotifications{InvocationId: "expired"},
&taskspb.TryFinalizeInvocation{InvocationId: "expired"},
})
var state resultpb.Invocation_State
testutil.MustReadRow(ctx, "Invocations", invocations.ID("expired").Key(), map[string]any{
"State": &state,
})
So(state, ShouldEqual, resultpb.Invocation_FINALIZING)
testutil.MustReadRow(ctx, "Invocations", invocations.ID("unexpired").Key(), map[string]any{
"State": &state,
})
So(state, ShouldEqual, resultpb.Invocation_ACTIVE)
So(store.Get(ctx, overdueInvocationsFinalized, time.Time{}, []any{insert.TestRealm}), ShouldEqual, 1)
d := store.Get(ctx, timeOverdue, time.Time{}, []any{insert.TestRealm}).(*distribution.Distribution)
// The 10 minute (600 s) delay should fall into bucket 29 (~400k - ~630k ms).
// allow +/- 1 bucket for clock shenanigans.
So(d.Buckets()[28] == 1 || d.Buckets()[29] == 1 || d.Buckets()[30] == 1, ShouldBeTrue)
})
}