36cbf4f0b8
Testplanet tests will print into logs (WARN) if full table scan will be detected. Test won't be failed automatically. That's because currently we have multiple queries which are doing full table scan and it's not trivial to change. https://github.com/storj/storj/issues/5471 Change-Id: Ia2fcbfb9102424d58f95e00071329454a8c1066e
186 lines
5.3 KiB
Go
186 lines
5.3 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" {
|
|
db := planet.Satellites[0].DB
|
|
// not perfect but didn't find better way to do this
|
|
rawDB = db.(interface{ DebugGetDBHandle() tagsql.DB }).DebugGetDBHandle()
|
|
|
|
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
|
|
}
|
|
}
|
|
}
|