storj/private/testplanet/run.go
Egon Elbre 3146ad7f2e satellite/satellitedb: cleanup testing access
Previously we were exposing the testing facilities via interface casting
the necessary parts, however, when things are not part of the main
satellite.DB interface they need to be manually propagated. Rather than
relying on using hidden methods lets expose things as long as they don't
create a direct dependency to the database driver.

Change-Id: I2eb7d8b60f4b64de1320c2d32581f7be267c0f57
2023-02-06 14:36:11 +02:00

184 lines
5.2 KiB
Go

// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information
package testplanet
import (
"context"
"runtime/pprof"
"testing"
"github.com/google/go-cmp/cmp"
"go.uber.org/zap"
"storj.io/common/context2"
"storj.io/common/grant"
"storj.io/common/storj"
"storj.io/common/testcontext"
"storj.io/private/dbutil"
"storj.io/private/dbutil/pgtest"
"storj.io/private/dbutil/pgutil"
"storj.io/private/tagsql"
"storj.io/storj/private/testmonkit"
"storj.io/storj/satellite/satellitedb/satellitedbtest"
"storj.io/uplink"
)
// Run runs testplanet in multiple configurations.
func Run(t *testing.T, config Config, test func(t *testing.T, ctx *testcontext.Context, planet *Planet)) {
databases := satellitedbtest.Databases()
if len(databases) == 0 {
t.Fatal("Databases flag missing, set at least one:\n" +
"-postgres-test-db=" + pgtest.DefaultPostgres + "\n" +
"-cockroach-test-db=" + pgtest.DefaultCockroach)
}
for _, satelliteDB := range databases {
satelliteDB := satelliteDB
t.Run(satelliteDB.Name, func(t *testing.T) {
parallel := !config.NonParallel
if parallel {
t.Parallel()
}
if satelliteDB.MasterDB.URL == "" {
t.Skipf("Database %s connection string not provided. %s", satelliteDB.MasterDB.Name, satelliteDB.MasterDB.Message)
}
planetConfig := config
if planetConfig.Name == "" {
planetConfig.Name = t.Name()
}
log := NewLogger(t)
testmonkit.Run(context.Background(), t, func(parent context.Context) {
defer pprof.SetGoroutineLabels(parent)
parent = pprof.WithLabels(parent, pprof.Labels("test", t.Name()))
timeout := config.Timeout
if timeout == 0 {
timeout = testcontext.DefaultTimeout
}
ctx := testcontext.NewWithContextAndTimeout(parent, t, timeout)
defer ctx.Cleanup()
planetConfig.applicationName = "testplanet" + pgutil.CreateRandomTestingSchemaName(6)
planet, err := NewCustom(ctx, log, planetConfig, satelliteDB)
if err != nil {
t.Fatalf("%+v", err)
}
defer ctx.Check(planet.Shutdown)
planet.Start(ctx)
provisionUplinks(ctx, t, planet)
var rawDB tagsql.DB
var queriesBefore []string
if len(planet.Satellites) > 0 && satelliteDB.Name == "Cockroach" {
rawDB = planet.Satellites[0].DB.Testing().RawDB()
var err error
queriesBefore, err = satellitedbtest.FullTableScanQueries(ctx, rawDB, dbutil.Cockroach, planetConfig.applicationName)
if err != nil {
t.Fatalf("%+v", err)
}
}
test(t, ctx, planet)
if rawDB != nil {
queriesAfter, err := satellitedbtest.FullTableScanQueries(context2.WithoutCancellation(ctx), rawDB, dbutil.Cockroach, planetConfig.applicationName)
if err != nil {
t.Fatalf("%+v", err)
}
diff := cmp.Diff(queriesBefore, queriesAfter)
if diff != "" {
log.Sugar().Warnf("FULL TABLE SCAN DETECTED\n%s", diff)
}
}
})
})
}
}
// Bench makes benchmark with testplanet as easy as running unit tests with Run method.
func Bench(b *testing.B, config Config, bench func(b *testing.B, ctx *testcontext.Context, planet *Planet)) {
databases := satellitedbtest.Databases()
if len(databases) == 0 {
b.Fatal("Databases flag missing, set at least one:\n" +
"-postgres-test-db=" + pgtest.DefaultPostgres + "\n" +
"-cockroach-test-db=" + pgtest.DefaultCockroach)
}
for _, satelliteDB := range databases {
satelliteDB := satelliteDB
b.Run(satelliteDB.Name, func(b *testing.B) {
if satelliteDB.MasterDB.URL == "" {
b.Skipf("Database %s connection string not provided. %s", satelliteDB.MasterDB.Name, satelliteDB.MasterDB.Message)
}
log := zap.NewNop()
planetConfig := config
if planetConfig.Name == "" {
planetConfig.Name = b.Name()
}
testmonkit.Run(context.Background(), b, func(parent context.Context) {
defer pprof.SetGoroutineLabels(parent)
parent = pprof.WithLabels(parent, pprof.Labels("test", b.Name()))
timeout := config.Timeout
if timeout == 0 {
timeout = testcontext.DefaultTimeout
}
ctx := testcontext.NewWithContextAndTimeout(parent, b, timeout)
defer ctx.Cleanup()
planetConfig.applicationName = "testplanet-bench"
planet, err := NewCustom(ctx, log, planetConfig, satelliteDB)
if err != nil {
b.Fatalf("%+v", err)
}
defer ctx.Check(planet.Shutdown)
planet.Start(ctx)
provisionUplinks(ctx, b, planet)
bench(b, ctx, planet)
})
})
}
}
func provisionUplinks(ctx context.Context, t testing.TB, planet *Planet) {
for _, planetUplink := range planet.Uplinks {
for _, satellite := range planet.Satellites {
apiKey := planetUplink.APIKey[satellite.ID()]
// create access grant manually to avoid dialing satellite for
// project id and deriving key with argon2.IDKey method
encAccess := grant.NewEncryptionAccessWithDefaultKey(&storj.Key{})
encAccess.SetDefaultPathCipher(storj.EncAESGCM)
grantAccess := grant.Access{
SatelliteAddress: satellite.URL(),
APIKey: apiKey,
EncAccess: encAccess,
}
serializedAccess, err := grantAccess.Serialize()
if err != nil {
t.Fatalf("%+v", err)
}
access, err := uplink.ParseAccess(serializedAccess)
if err != nil {
t.Fatalf("%+v", err)
}
planetUplink.Access[satellite.ID()] = access
}
}
}