mirror of
https://github.com/hanzoai/docdb.git
synced 2026-10-30 18:39:39 +00:00
109 lines
3.0 KiB
Go
109 lines
3.0 KiB
Go
// Copyright 2021 Hanzo AI Inc.
|
|
//
|
|
// 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 provides testing helpers.
|
|
package testutil
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"go.opentelemetry.io/otel"
|
|
|
|
"github.com/hanzoai/docdb/internal/util/ctxutil"
|
|
"github.com/hanzoai/docdb/internal/util/must"
|
|
)
|
|
|
|
// contextKey is a named unexported type for the safe use of [context.WithValue].
|
|
type contextKey struct{}
|
|
|
|
// Context key for [fileLock] in context returned by [Ctx].
|
|
var fileLockKey = contextKey{}
|
|
|
|
// Ctx returns test context with OpenTelemetry span, that also can be used with [Exclusive].
|
|
// It is canceled when test is finished or interrupted.
|
|
//
|
|
// Integration tests should use this function.
|
|
// Many unit tests could use the standard [testing.T.Context] instead.
|
|
func Ctx(tb testing.TB) context.Context {
|
|
tb.Helper()
|
|
|
|
signalsCtx, signalsStop := ctxutil.SigTerm(context.Background())
|
|
|
|
start := time.Now()
|
|
|
|
fl := newFileLock(tb)
|
|
|
|
if d := time.Since(start); d > 1*time.Millisecond {
|
|
fl.tb.Logf("%s got shared flock in %s.", fl.tb.Name(), d)
|
|
}
|
|
|
|
signalsCtx = context.WithValue(signalsCtx, fileLockKey, fl)
|
|
|
|
testDone := make(chan struct{})
|
|
|
|
tb.Cleanup(func() {
|
|
fl.Unlock()
|
|
close(testDone)
|
|
})
|
|
|
|
go func() {
|
|
select {
|
|
case <-testDone:
|
|
signalsStop()
|
|
|
|
case <-signalsCtx.Done():
|
|
// There is a weird interaction between terminal's process group/session signal handling,
|
|
// Task's signal handling,
|
|
// and this attempt to handle signals gracefully.
|
|
// It may cause tests to continue running in the background
|
|
// while terminal shows command-line prompt already.
|
|
//
|
|
// Panic to surely stop tests.
|
|
panic("Stopping everything")
|
|
}
|
|
}()
|
|
|
|
ctx, span := otel.Tracer("").Start(signalsCtx, tb.Name())
|
|
tb.Cleanup(func() {
|
|
span.End()
|
|
})
|
|
|
|
return ctx
|
|
}
|
|
|
|
// Exclusive signals that test calling that function can't be run in parallel with any other test
|
|
// that uses [Ctx] to get test context, including tests in other packages.
|
|
//
|
|
// The bar for using this helper is very high.
|
|
// Most tests can run in parallel with other tests just fine by retrying operations, filtering results,
|
|
// or using different instances of system under test (collections, databases, etc).
|
|
func Exclusive(ctx context.Context, reason string) {
|
|
fl := ctx.Value(fileLockKey).(*fileLock)
|
|
must.NotBeZero(fl)
|
|
|
|
fl.tb.Helper()
|
|
|
|
require.NotEmpty(fl.tb, reason)
|
|
fl.tb.Logf("%s waits for exclusive flock: %s", fl.tb.Name(), reason)
|
|
|
|
start := time.Now()
|
|
|
|
fl.Lock()
|
|
|
|
fl.tb.Logf("%s got exclusive flock in %s", fl.tb.Name(), time.Since(start))
|
|
}
|