blob: fbd46a6783fd10e0bc66c05795a75bf62a657219 [file] [log] [blame]
// Copyright 2018 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 engine
// This file contains helpers used by the rest of tests.
import (
"context"
"errors"
"math/rand"
"sort"
"time"
"github.com/golang/protobuf/proto"
"google.golang.org/api/pubsub/v1"
"go.chromium.org/luci/gae/impl/memory"
"go.chromium.org/luci/gae/service/datastore"
"go.chromium.org/luci/appengine/tq"
"go.chromium.org/luci/common/clock"
"go.chromium.org/luci/common/clock/testclock"
"go.chromium.org/luci/common/data/rand/mathrand"
"go.chromium.org/luci/common/data/stringset"
"go.chromium.org/luci/common/tsmon"
"go.chromium.org/luci/common/tsmon/store"
"go.chromium.org/luci/common/tsmon/target"
"go.chromium.org/luci/config/validation"
"go.chromium.org/luci/server/auth"
"go.chromium.org/luci/server/auth/authtest"
"go.chromium.org/luci/server/auth/signing"
"go.chromium.org/luci/server/auth/signing/signingtest"
"go.chromium.org/luci/server/secrets"
"go.chromium.org/luci/server/secrets/testsecrets"
"go.chromium.org/luci/scheduler/appengine/catalog"
"go.chromium.org/luci/scheduler/appengine/internal"
"go.chromium.org/luci/scheduler/appengine/messages"
"go.chromium.org/luci/scheduler/appengine/task"
)
const fakeAppID = "scheduler-app-id"
var epoch = time.Unix(1442270520, 0).UTC()
func allJobs(c context.Context) []Job {
datastore.GetTestable(c).CatchupIndexes()
entities := []Job{}
if err := datastore.GetAll(c, datastore.NewQuery("Job"), &entities); err != nil {
panic(err)
}
// Strip UTC location pointers from zero time.Time{} so that ShouldResemble
// can compare it to default time.Time{}. nil location is UTC too.
for i := range entities {
ent := &entities[i]
if ent.Cron.LastRewind.IsZero() {
ent.Cron.LastRewind = time.Time{}
}
if ent.Cron.LastTick.When.IsZero() {
ent.Cron.LastTick.When = time.Time{}
}
}
return entities
}
func sortedJobIds(jobs []*Job) []string {
ids := stringset.New(len(jobs))
for _, j := range jobs {
ids.Add(j.JobID)
}
asSlice := ids.ToSlice()
sort.Strings(asSlice)
return asSlice
}
func newTestContext(now time.Time) context.Context {
c := memory.UseWithAppID(context.Background(), fakeAppID)
c = clock.Set(c, testclock.New(now))
c = mathrand.Set(c, rand.New(rand.NewSource(1000)))
c = secrets.Use(c, &testsecrets.Store{})
// Signer is used by ShouldEnforceRealmACL to discover app ID.
c = auth.ModifyConfig(c, func(cfg auth.Config) auth.Config {
cfg.Signer = signingtest.NewSigner(&signing.ServiceInfo{
AppID: fakeAppID,
})
return cfg
})
c, _, _ = tsmon.WithFakes(c)
fake := store.NewInMemory(&target.Task{})
tsmon.GetState(c).SetStore(fake)
datastore.GetTestable(c).AddIndexes(&datastore.IndexDefinition{
Kind: "Job",
SortBy: []datastore.IndexColumn{
{Property: "Enabled"},
{Property: "ProjectID"},
},
})
datastore.GetTestable(c).CatchupIndexes()
return c
}
func newTestEngine() (*engineImpl, *fakeTaskManager) {
mgr := &fakeTaskManager{}
cat := catalog.New()
cat.RegisterTaskManager(mgr)
return NewEngine(Config{
Catalog: cat,
Dispatcher: &tq.Dispatcher{},
PubSubPushPath: "/push-url",
}).(*engineImpl), mgr
}
func mockOwnerCtx(ctx context.Context, realm string) context.Context {
return auth.WithState(ctx, &authtest.FakeState{
Identity: "user:owner@example.com",
FakeDB: authtest.NewFakeDB(
authtest.MockPermission("user:owner@example.com", realm, PermJobsGet),
authtest.MockPermission("user:owner@example.com", realm, PermJobsPause),
authtest.MockPermission("user:owner@example.com", realm, PermJobsResume),
authtest.MockPermission("user:owner@example.com", realm, PermJobsAbort),
authtest.MockPermission("user:owner@example.com", realm, PermJobsTrigger),
),
})
}
func mockReaderCtx(ctx context.Context, realm string) context.Context {
return auth.WithState(ctx, &authtest.FakeState{
Identity: "user:reader@example.com",
FakeDB: authtest.NewFakeDB(
authtest.MockPermission("user:reader@example.com", realm, PermJobsGet),
),
})
}
////
// fakeTaskManager implement task.Manager interface.
type fakeTaskManager struct {
launchTask func(ctx context.Context, ctl task.Controller) error
abortTask func(ctx context.Context, ctl task.Controller) error
examineNotification func(ctx context.Context, msg *pubsub.PubsubMessage) string
handleNotification func(ctx context.Context, msg *pubsub.PubsubMessage) error
handleTimer func(ctx context.Context, ctl task.Controller, name string, payload []byte) error
}
func (m *fakeTaskManager) Name() string {
return "fake"
}
func (m *fakeTaskManager) ProtoMessageType() proto.Message {
return (*messages.NoopTask)(nil)
}
func (m *fakeTaskManager) Traits() task.Traits {
return task.Traits{}
}
func (m *fakeTaskManager) ValidateProtoMessage(c *validation.Context, msg proto.Message, realmID string) {
}
func (m *fakeTaskManager) LaunchTask(c context.Context, ctl task.Controller) error {
return m.launchTask(c, ctl)
}
func (m *fakeTaskManager) AbortTask(c context.Context, ctl task.Controller) error {
if m.abortTask != nil {
return m.abortTask(c, ctl)
}
return nil
}
func (m *fakeTaskManager) ExamineNotification(c context.Context, msg *pubsub.PubsubMessage) string {
return m.examineNotification(c, msg)
}
func (m *fakeTaskManager) HandleNotification(c context.Context, ctl task.Controller, msg *pubsub.PubsubMessage) error {
return m.handleNotification(c, msg)
}
func (m fakeTaskManager) HandleTimer(c context.Context, ctl task.Controller, name string, payload []byte) error {
return m.handleTimer(c, ctl, name, payload)
}
func (m fakeTaskManager) GetDebugState(c context.Context, ctl task.ControllerReadOnly) (*internal.DebugManagerState, error) {
return nil, errors.New("not implemented")
}