storj/testsuite/storjscan/storjscantest/run.go
Yaroslav Vorobiov 14d0b0ee20 testsuite/storjscan: add backfill payments test
Add backfill payments test to testsuite/storjscan.
Test ensures that even when something happens with
storjscan and it's unvailable from satellite perspective
that all payments made during storjscan downtime will be
picked up during next StorjscanChore cycle.

Change-Id: I4db699a29061023e159b3191a1e4dcfae6d0175e
2022-10-04 18:56:48 +00:00

223 lines
6.1 KiB
Go

// Copyright (C) 2022 Storj Labs, Inc.
// See LICENSE for copying information.
package storjscantest
import (
"context"
"runtime/pprof"
"testing"
"time"
"github.com/spacemonkeygo/monkit/v3"
"github.com/zeebo/errs"
"go.uber.org/zap"
"golang.org/x/sync/errgroup"
"storj.io/common/grant"
"storj.io/common/storj"
"storj.io/common/testcontext"
"storj.io/private/dbutil/pgtest"
"storj.io/storj/private/blockchain"
"storj.io/storj/private/testmonkit"
"storj.io/storj/private/testplanet"
"storj.io/storj/satellite"
"storj.io/storj/satellite/satellitedb/satellitedbtest"
"storj.io/storjscan"
"storj.io/storjscan/private/testeth"
"storj.io/storjscan/storjscandb/storjscandbtest"
"storj.io/uplink"
)
var mon = monkit.Package()
// Stack contains references to storjscan app and eth test network.
type Stack struct {
Log *zap.Logger
App *storjscan.App
StartApp func() error
CloseApp func() error
Network *testeth.Network
Token blockchain.Address
}
// Test defines common services for storjscan tests.
type Test func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet, stack *Stack)
// Run runs testplanet and storjscan and executes test function.
func Run(t *testing.T, test Test) {
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)
}
config := testplanet.Config{
SatelliteCount: 1, StorageNodeCount: 4, UplinkCount: 1,
NonParallel: true,
}
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 := testplanet.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()
// storjscan ---------
stack := Stack{
Log: log.Named("storjscan"),
}
storjscanDB, err := storjscandbtest.OpenDB(ctx, stack.Log.Named("db"), satelliteDB.MasterDB.URL, "storjscandb-"+t.Name(), "S")
if err != nil {
t.Fatalf("%+v", err)
}
defer ctx.Check(storjscanDB.Close)
if err = storjscanDB.MigrateToLatest(ctx); err != nil {
t.Fatalf("%+v", err)
}
stack.Network, err = testeth.NewNetwork()
if err != nil {
t.Fatalf("%+v", err)
}
if err = stack.Network.Start(); err != nil {
t.Fatalf("%+v", err)
}
defer ctx.Check(stack.Network.Close)
token, err := testeth.DeployToken(ctx, stack.Network, 1000000)
if err != nil {
t.Fatalf("%+v", err)
}
stack.Token = blockchain.Address(token)
var storjscanConfig storjscan.Config
storjscanConfig.API.Address = "127.0.0.1:0"
storjscanConfig.API.Keys = []string{"eu:eusecret"}
storjscanConfig.Tokens.Endpoint = stack.Network.HTTPEndpoint()
storjscanConfig.Tokens.Contract = stack.Token.Hex()
storjscanConfig.TokenPrice.PriceWindow = time.Minute
storjscanConfig.TokenPrice.Interval = time.Minute
storjscanConfig.TokenPrice.UseTestPrices = true
stack.App, err = storjscan.NewApp(stack.Log.Named("app"), storjscanConfig, storjscanDB)
if err != nil {
t.Fatalf("%+v", err)
}
var run errgroup.Group
runCtx, runCancel := context.WithCancel(ctx)
stack.StartApp = func() error {
storjscanConfig.API.Address = stack.App.API.Listener.Addr().String()
stack.App, err = storjscan.NewApp(stack.Log.Named("app"), storjscanConfig, storjscanDB)
if err != nil {
return err
}
runCtx, runCancel = context.WithCancel(ctx)
run = errgroup.Group{}
run.Go(func() error {
err := stack.App.Run(runCtx)
return err
})
return nil
}
stack.CloseApp = func() error {
runCancel()
var errlist errs.Group
errlist.Add(run.Wait())
errlist.Add(stack.App.Close())
return errlist.Err()
}
run.Go(func() error {
err := stack.App.Run(runCtx)
return err
})
defer ctx.Check(stack.CloseApp)
// ------------
planetConfig.Reconfigure = testplanet.Reconfigure{Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
config.Payments.Storjscan.Auth.Identifier = "eu"
config.Payments.Storjscan.Auth.Secret = "eusecret"
config.Payments.Storjscan.Endpoint = "http://" + stack.App.API.Listener.Addr().String()
config.Payments.Storjscan.Confirmations = 1
config.Payments.Storjscan.DisableLoop = false
}}
planet, err := testplanet.NewCustom(ctx, log, planetConfig, satelliteDB)
if err != nil {
t.Fatalf("%+v", err)
}
defer ctx.Check(planet.Shutdown)
planet.Start(ctx)
provisionUplinks(ctx, t, planet)
test(t, ctx, planet, &stack)
})
})
}
}
func provisionUplinks(ctx context.Context, t *testing.T, planet *testplanet.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
}
}
}