blob: f175b9d2edd2af30353d70813911c38b9adf22d4 [file] [log] [blame]
// Copyright 2024 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 testutil holds helper functions for testing.
package testutil
import (
"context"
"os"
"path/filepath"
"testing"
"time"
"cloud.google.com/go/spanner"
. "github.com/smartystreets/goconvey/convey"
"go.chromium.org/luci/common/errors"
"go.chromium.org/luci/common/spantest"
"go.chromium.org/luci/common/tsmon"
"go.chromium.org/luci/server/span"
)
// cleanupDatabase deletes all data from all tables.
func cleanupDatabase(ctx context.Context, client *spanner.Client) error {
_, err := client.Apply(ctx, []*spanner.Mutation{
// No need to explicitly delete interleaved tables.
spanner.Delete("Alerts", spanner.AllKeys()),
})
return err
}
// IntegrationTestContext returns a context for testing code that talks to Spanner
// and uses tsmon.
// Skips the test if integration tests are not enabled.
//
// Tests that use Spanner must not call t.Parallel().
func IntegrationTestContext(tb testing.TB) context.Context {
// tsmon metrics are used fairly extensively throughout LUCI Analysis,
// especially in contexts that also use Spanner.
ctx := SpannerTestContext(tb)
ctx, _ = tsmon.WithDummyInMemory(ctx)
return ctx
}
// SpannerTestContext returns a context for testing code that talks to Spanner.
// Skips the test if integration tests are not enabled.
//
// Tests that use Spanner must not call t.Parallel().
func SpannerTestContext(tb testing.TB) context.Context {
return spantest.SpannerTestContext(tb, cleanupDatabase)
}
// findInitScript returns path //analysis/internal/span/init_db.sql.
func findInitScript() (string, error) {
ancestor, err := filepath.Abs(".")
if err != nil {
return "", err
}
for {
scriptPath := filepath.Join(ancestor, "internal", "span", "init_db.sql")
_, err := os.Stat(scriptPath)
if os.IsNotExist(err) {
parent := filepath.Dir(ancestor)
if parent == ancestor {
return "", errors.Reason("init_db.sql not found").Err()
}
ancestor = parent
continue
}
return scriptPath, err
}
}
// SpannerTestMain is a test main function for packages that have tests that
// talk to spanner. It creates/destroys a temporary spanner database
// before/after running tests.
//
// This function never returns. Instead it calls os.Exit with the value returned
// by m.Run().
func SpannerTestMain(m *testing.M) {
spantest.SpannerTestMain(m, findInitScript)
}
// MustApply applies the mutations to the spanner client in the context.
// Asserts that application succeeds.
// Returns the commit timestamp.
func MustApply(ctx context.Context, ms ...*spanner.Mutation) time.Time {
ct, err := span.Apply(ctx, ms)
So(err, ShouldBeNil)
return ct
}