Skip to content

Commit

Permalink
add metering testing framework
Browse files Browse the repository at this point in the history
  • Loading branch information
ArnaudBger committed Oct 8, 2024
1 parent d27ad93 commit da4f95b
Show file tree
Hide file tree
Showing 22 changed files with 1,847 additions and 6 deletions.
2 changes: 2 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
dauthsecret "github.com/streamingfast/dauth/secret"
dauthtrust "github.com/streamingfast/dauth/trust"
"github.com/streamingfast/dmetering"
dmeteringfile "github.com/streamingfast/dmetering/file"
dmeteringgrpc "github.com/streamingfast/dmetering/grpc"
dmeteringlogger "github.com/streamingfast/dmetering/logger"
firecore "github.com/streamingfast/firehose-core"
Expand Down Expand Up @@ -43,6 +44,7 @@ func Main[B firecore.Block](chain *firecore.Chain[B]) {
dmetering.RegisterNull()
dmeteringgrpc.Register()
dmeteringlogger.Register()
dmeteringfile.Register()
paymentGatewayMetering.Register()

chain.Validate()
Expand Down
2 changes: 0 additions & 2 deletions devel/standard/standard.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ start:
- merger
- relayer
- firehose
- substreams-tier1
- substreams-tier2
flags:
advertise-block-id-encoding: "hex"
advertise-chain-name: "acme-dummy-blockchain"
Expand Down
1 change: 1 addition & 0 deletions firehose/info/endpoint_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ func (s *InfoServer) getBlockFromMergedBlocksStore(ctx context.Context, blockNum
time.Sleep(time.Millisecond * 500)
continue
}

return block
}
}
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ require (
github.com/streamingfast/derr v0.0.0-20230515163924-8570aaa43fe1
github.com/streamingfast/dgrpc v0.0.0-20240423143010-f36784700c9a
github.com/streamingfast/dhammer v0.0.0-20230125192823-c34bbd561bd4
github.com/streamingfast/dmetering v0.0.0-20240816165719-51768d3da951
github.com/streamingfast/dmetering v0.0.0-20241007182823-f92200a54cdb
github.com/streamingfast/dmetrics v0.0.0-20230919161904-206fa8ebd545
github.com/streamingfast/dstore v0.1.1-0.20240826190906-91345d4a31f2
github.com/streamingfast/jsonpb v0.0.0-20210811021341-3670f0aa02d0
Expand Down Expand Up @@ -175,7 +175,7 @@ require (
go.uber.org/automaxprocs v1.5.1
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/net v0.23.0
golang.org/x/oauth2 v0.18.0
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.24.0 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -551,8 +551,8 @@ github.com/streamingfast/dgrpc v0.0.0-20240423143010-f36784700c9a h1:JwAGZ7f5vkB
github.com/streamingfast/dgrpc v0.0.0-20240423143010-f36784700c9a/go.mod h1:EPtUX/vhRphE37Zo6sDcgD/S3sm5YqXHhxAgzS6Ebwo=
github.com/streamingfast/dhammer v0.0.0-20230125192823-c34bbd561bd4 h1:HKi8AIkLBzxZWmbCRUo1RxoOLK33iXO6gZprfsE9rf4=
github.com/streamingfast/dhammer v0.0.0-20230125192823-c34bbd561bd4/go.mod h1:ehPytv7E4rI65iLcrwTes4rNGGqPPiugnH+20nDQyp4=
github.com/streamingfast/dmetering v0.0.0-20240816165719-51768d3da951 h1:6o6MS3JHrp9A7V6EBHbR7W7mzVCFmXc8U0AjTfvz7PI=
github.com/streamingfast/dmetering v0.0.0-20240816165719-51768d3da951/go.mod h1:UqWuX3REU/IInBUaymFN2eLjuvz+/0SsoUFjeQlLNyI=
github.com/streamingfast/dmetering v0.0.0-20241007182823-f92200a54cdb h1:SooWpzSSU04Z321lLWS6OkTAgoXH0qQEv5mVUi4b+q8=
github.com/streamingfast/dmetering v0.0.0-20241007182823-f92200a54cdb/go.mod h1:UqWuX3REU/IInBUaymFN2eLjuvz+/0SsoUFjeQlLNyI=
github.com/streamingfast/dmetrics v0.0.0-20230919161904-206fa8ebd545 h1:SUl04bZKGAv207lp7/6CHOJIRpjUKunwItrno3K463Y=
github.com/streamingfast/dmetrics v0.0.0-20230919161904-206fa8ebd545/go.mod h1:JbxEDbzWRG1dHdNIPrYfuPllEkktZMgm40AwVIBENcw=
github.com/streamingfast/dstore v0.1.1-0.20240826190906-91345d4a31f2 h1:BB3VSDl8/OHBSvjqfgufwqr4tD5l7XPjXybDm6uudj4=
Expand Down
226 changes: 226 additions & 0 deletions test/integration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
package test

import (
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"testing"
"time"

_ "github.com/streamingfast/dmetering/file"
"github.com/streamingfast/substreams/client"
"github.com/streamingfast/substreams/manifest"
pbsubstreamsrpc "github.com/streamingfast/substreams/pb/sf/substreams/rpc/v2"
"github.com/stretchr/testify/require"
"golang.org/x/net/context"
)

type Case struct {
name string
spkgRootPath string
moduleName string
startBlock uint64
// set endBlock to 0 to connect live
endBlock uint64
expectedReadBytes float64
}

func TestIntegration(t *testing.T) {
if os.Getenv("RUN_INTEGRATION_TESTS") != "true" {
t.Skip()
}

cases := []Case{
{
name: "sunny path",
spkgRootPath: "./substreams_acme/substreams-acme-v0.1.0.spkg",
moduleName: "map_test_data",
startBlock: 0,
endBlock: 1000,
expectedReadBytes: 696050,
},

{
name: "sunny path",
spkgRootPath: "./substreams_acme/substreams-acme-v0.1.0.spkg",
moduleName: "map_test_data",
startBlock: 0,
endBlock: 0,
expectedReadBytes: 696050,
},
}

ctx := context.Background()

rootPath, err := filepath.Abs("../")
if err != nil {
t.Fatalf("getting absolute path: %v", err)
}

go func() {
err = runTier1(ctx, t, rootPath)
require.NoError(t, err)
}()

go func() {
err = runTier2(ctx, t, rootPath)
require.NoError(t, err)
}()

var meteringServer *MeteringTestServer
go func() {
meteringServer = NewMeteringServer(t, ":10016")
meteringServer.Run()
}()

clientConfig := client.NewSubstreamsClientConfig("localhost:9003", "", 0, false, true)
substreamsClient, _, _, _, err := client.NewSubstreamsClient(clientConfig)
require.NoError(t, err)

// WAIT SERVERS TO BE READY
time.Sleep(15 * time.Second)

for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
if c.endBlock == 0 {
// RUN LIVE
go func() {
err = runDummyNode(ctx, t)
require.NoError(t, err)
}()
}

err = requestTier1(ctx, t, c, substreamsClient)
require.NoError(t, err)

resultEvents := meteringServer.bufferedEvents
var totalReadBytes float64
for _, events := range resultEvents {
for _, event := range events.Events {
for _, metric := range event.Metrics {
// TODO : CHOOSE THE RIGHT METRIC
if metric.Key == "file_uncompressed_read_bytes" {
totalReadBytes += metric.Value
}
}
}
}

require.Equal(t, c.expectedReadBytes, totalReadBytes)
meteringServer.clearBufferedEvents()
})
}
}

func runTier1(ctx context.Context, t *testing.T, rootDir string) error {
cmdPath := filepath.Join(rootDir, "/cmd/firecore")
firehoseDataStoragePath := filepath.Join(rootDir, "devel/standard/firehose-data/storage/")
mergedBlocksStore := fmt.Sprintf("file://%s", filepath.Join(firehoseDataStoragePath, "merged-blocks"))
forkedBlocksStore := fmt.Sprintf("file://%s", filepath.Join(firehoseDataStoragePath, "forked-blocks"))
oneBlocksStore := fmt.Sprintf("file://%s", filepath.Join(firehoseDataStoragePath, "one-blocks"))

tier1Args := []string{
"run",
cmdPath,
"start", "substreams-tier1",
"--config-file=",
"--log-to-file=false",
"--common-auth-plugin=null://",
fmt.Sprintf("--common-tmp-dir=%s", t.TempDir()),
fmt.Sprintf("--common-metering-plugin=grpc://localhost:10016?network=dummy_blockchain"),
"--common-system-shutdown-signal-delay=30s",
fmt.Sprintf("--common-merged-blocks-store-url=%s", mergedBlocksStore),
fmt.Sprintf("--common-one-block-store-url=%s", oneBlocksStore),
fmt.Sprintf("--common-forked-blocks-store-url=%s", forkedBlocksStore),
"--common-live-blocks-addr=localhost:10014",
"--common-first-streamable-block=0",
"--substreams-tier1-grpc-listen-addr=:9003",
"--substreams-tier1-subrequests-endpoint=localhost:9004",
"--substreams-tier1-subrequests-insecure=false",
"--substreams-tier1-subrequests-plaintext=true",
fmt.Sprintf("--substreams-state-store-url=%s/substreams_dummy", t.TempDir()),
"--substreams-state-store-default-tag=vtestdummy",
}

tier1Cmd := exec.CommandContext(ctx, "go", tier1Args...)

err := handlingTestInstance(t, tier1Cmd, "TIER1", true)
if err != nil {
return fmt.Errorf("handling instance %w", err)
}

return err
}

func runTier2(ctx context.Context, t *testing.T, rootDir string) error {
cmdPath := rootDir + "/cmd/firecore"
tier2Args := []string{
"run",
cmdPath,
"start", "substreams-tier2",
"--config-file=",
"--log-to-file=false",
fmt.Sprintf("--common-tmp-dir=%s", t.TempDir()),
"--substreams-tier2-grpc-listen-addr=:9004",
"--substreams-tier1-subrequests-plaintext=true",
"--substreams-tier1-subrequests-insecure=false",
}

tier2Cmd := exec.CommandContext(ctx, "go", tier2Args...)

err := handlingTestInstance(t, tier2Cmd, "TIER2", true)
if err != nil {
return fmt.Errorf("handling instance %w", err)
}

return err
}

func runDummyNode(ctx context.Context, t *testing.T) error {
launchDummyCmd := exec.CommandContext(ctx, "../devel/standard/start.sh")

err := handlingTestInstance(t, launchDummyCmd, "DUMMY_BLOCKCHAIN", true)
if err != nil {
return fmt.Errorf("handling instance %w", err)
}

return err
}

func requestTier1(ctx context.Context, t *testing.T, testCase Case, substreamsClient pbsubstreamsrpc.StreamClient) error {
manifestReader, err := manifest.NewReader(testCase.spkgRootPath)
require.NoError(t, err)

pkgBundle, err := manifestReader.Read()
require.NoError(t, err)

require.NotEmptyf(t, pkgBundle, "pkgBundle is empty")

request := pbsubstreamsrpc.Request{
StartBlockNum: int64(testCase.startBlock),
StartCursor: "",
StopBlockNum: testCase.endBlock,
FinalBlocksOnly: false,
ProductionMode: false,
OutputModule: testCase.moduleName,
Modules: pkgBundle.Package.Modules,
DebugInitialStoreSnapshotForModules: nil,
NoopMode: false,
}

stream, err := substreamsClient.Blocks(ctx, &request)
require.NoError(t, err)

for {
block, err := stream.Recv()
if err == io.EOF {
break
}
require.NoError(t, err)

t.Logf("[REQUESTER]: %v", block)
}
return nil
}
57 changes: 57 additions & 0 deletions test/metering_server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package test

import (
"context"
"net"
"testing"

"github.com/test-go/testify/require"

pbmetering "github.com/streamingfast/dmetering/pb/sf/metering/v1"
"google.golang.org/grpc"
"google.golang.org/protobuf/types/known/emptypb"
)

type MeteringTestServer struct {
pbmetering.UnimplementedMeteringServer
httpListenAddr string
t *testing.T
bufferedEvents []*pbmetering.Events
}

func NewMeteringServer(t *testing.T, httpListenAddr string) *MeteringTestServer {
return &MeteringTestServer{
t: t,
httpListenAddr: httpListenAddr,
bufferedEvents: make([]*pbmetering.Events, 0),
}
}

func (s *MeteringTestServer) Run() {
lis, err := net.Listen("tcp", s.httpListenAddr)
if err != nil {
require.NoError(s.t, err)
}

grpcServer := grpc.NewServer()

pbmetering.RegisterMeteringServer(grpcServer, s)

s.t.Logf("[Metering]: Server listening port %s", s.httpListenAddr)
if err = grpcServer.Serve(lis); err != nil {
require.NoError(s.t, err)
}
}

func (s *MeteringTestServer) Emit(ctx context.Context, events *pbmetering.Events) (*emptypb.Empty, error) {
s.bufferedEvents = append(s.bufferedEvents, events)
return &emptypb.Empty{}, nil
}

func (s *MeteringTestServer) mustEmbedUnimplementedMeteringServer() {
panic("implement me")
}

func (s *MeteringTestServer) clearBufferedEvents() {
s.bufferedEvents = make([]*pbmetering.Events, 0)
}
11 changes: 11 additions & 0 deletions test/substreams_acme/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# substreams auth file
.substreams.env

# Compiled source files
target/

# Sink data when running any sinker
sink-data/

# The spkg packed by the subtreams cli
*.spkg
Loading

0 comments on commit da4f95b

Please sign in to comment.